<Java>19 网络编程

本文最后更新于:2023年6月27日 上午

19 网络编程

网络通信:两台设备之间通过网络实现数据传输。

java.net 包下提供了一系列类或接口,供程序员使用,完成网络通信

19.1 网络的相关概念

网络

网络:两台或多台设备通过一定物理设备连接起来构成了网络

根据网络覆盖范围的不同,对网络进行分类:

  • 局域网:覆盖范围最小,仅覆盖一个教室·机房
  • 城域网:覆盖范围较大,可覆盖一个城市
  • 广域网:覆盖范围最大,可以覆盖全国,甚至全球。万维网 是广域网的代表

IP 地址

IP 地址:用于唯一标识网络中的每台计算机 / 主机

查看 IP 地址:ipconfig

IPv4 是 4 个字节(32位)表示。每个字节范围是 [0,255]

IP 地址的表示形式:点分十进制(xx.xx.xx.xx),每个十进制数范围是 [0,255]

IP 地址的组成 = 网络地址 + 主机地址

  • A类:0 + 7 位网络号 + 24 位主机号(0.0.0.0 ~ 127.255.255.255)
  • B类:1 + 0 + 14 位网络号 + 16 位主机号(128.0.0.0 ~ 191.255.255.255)
  • C类:1 + 1 + 0 + 21 位网络号 + 8 位主机号(192.0.0.0 ~ 223.255.255.255)
  • D类:1 + 1 + 1 + 0 + 28 位多播组号(224.0.0.0 ~ 239.255.255.255)
  • E类:1 + 1 + 1 + 1 + 0 + 27 位(留待后用)(240.0.0.0 ~ 247.255.255.255)

IPv6 是互联网工程任务组设计的用于替代 IPv4 的下一代 IP 协议。其地址数量可以为全世界每一粒沙子编上一个地址

IPv4 最大的问题在于网络地址资源有限,严重制约了互联网的应用和发展。IPv6 的使用,不仅能解决网络地址资源数量的问题,也解决了多种接入设备接入互联网的障碍

IPv6 使用 16 个字节(128 位)表示地址。

表示形式有:

  • 冒分十六进制表示法: (X:X:X:X:X:X:X:X)

    : 之间的部分,出现 0 开头的场合,那些 0 可以省略

  • 0 位压缩表示法:把连续的 0 压缩为 ::,这个压缩只能出现一次(X::X:X)

  • 内嵌 IPv4 地址表示法:前 96位 用冒分十六进制表示,后面 32位 用 IPv4 的点分十进制(X:X:X:X:X:XX:d.d.d.d)

子网掩码

只用一个 IP 地址,无法分辨网络部分与主机部分的分界线。因此,使用子网掩码来表示分界线。

这个场合,对应的网络部分的子网掩码的二进制数字设为 1


(子网掩码图_19.1)

此外,还能把子网掩码与 IP 地址组合

  • 在 IP 地址后加斜线及网络部分二进制数字数(IPV4):192.168.15.1/16
  • IPv6:X:X:X:X:X:X:X:X/64

通过更改子网掩码,可以细分网络为多个子网。


(子网图_19.1)

保留地址

IP 还定义了一套特殊的地址格式,称为保留地址,这些保留地址不分配给任何主机。

网络号 主机号 地址类型 举例 用途
全 0 全 0 本机地址 0.0.0.0 启动时使用
任意 全 0 网络地址 61.0.0.0 标识一个网络
任意 全 1 直接广播地址 129.21.255.255 在特定网络上广播
全 1 全 1 有线广播地址 255.255.255.255 在本网段上广播
第一段为 127 任意 回送地址 127.0.0.1 测试

私有地址

私有地址:与 IP 地址(全局地址)相比,在不同的网络中可以重复的地址。

私有地址是以下范围中的地址。这些地址不能作为全局地址使用:

  • 10.0.0.0 ~ 10.255.255.255
  • 172.16.0.0 ~ 172.31.255.255
  • 192.168.0.0 ~ 192.168.255.255

将私有地址连接到全局地址的方法:

  • NAT:一种私有地址与全局地址一一对应的机制
  • NAPT:一种用一个全局地址连接多个计算机的机制

域名

示例:http://bbs.tianya.cn/post-house-252774-1.shtml

为了方便记忆,解决记忆 IP 的困难

IP 地址根据 HTTP 协议 映射成域名

通过 DNS(Domain Name System)服务将域名转化为 IP 地址

端口号

用于标识计算机上某个特定的网络程序

表示形式:以整数形式,范围 [0,65535]

0 ~ 1024 已经被占用,不要使用。比如 ssh 22、ftp 21、smtp 25、http 80

常见的网络程序端口号:

  • tomcat:8080
  • mysql:3306
  • oracle:1521
  • sqlserver:1433

网络通信协议

协议(TCP/IP)

TCP/IP:传输控制协议 / 因特网互联协议(Transmission Control Protocol / Internet Protocol),又叫 网络通讯协议。这个协议是 Internet 最基本的协议、Internet 国际互联网络的基础。简单来讲,就是由 网络层的 IP 协议 和传输层的 TCP 协议 组成

(数据封装图_19.1)

OSI 模型(理论) TCP/IP 模型(实际使用) TCP/IP 模型各层对应协议
应用层 应用层 HTTP、ftp、telent、DNS……
表示层 应用层 同上
会话层 应用层 同上
传输层 传输层(TCP) TCP、UDP……
网络层 网络层(IP) IP、ICMP、ARP……
数据链路层 物理 + 数据链路层 Link
物理层 物理 + 数据链路层 同上

19.1.1 TCP 和 UDP

TCP

传输控制协议

  1. 使用 TCP 协议前,须先建立 TCP 连接,形成传输数据通道。TCP 通信是一对一通信
  2. 传输前,采用 “三次握手” 方式,是可靠的
  3. TCP 协议进行通信的两个应用进程:客户端、服务端
  4. 在连接中可进行大数据量的传输。传输前,先确认要交流的数据量。那个数据量、数据窗口取较小方的数值。
  5. 发送方没有收到接收方的确认应答时,(在一定次数内)会再次发送数据包
  6. 传输完毕,需释放已建立的连接,效率低

UDP

用户数据协议

  1. 将 数据、源、目的 封装成数据包,不需要建立连接。可以同时向多个接收方发送
  2. 每个数据包大小限制在 64K 以内,不适合传输大量数据
  3. 因无需连接,所以是不可靠的
  4. 接收方无需发送确认应答
  5. 发送数据结束时无需释放资源(因为不是面向连接的),速度快

19.2 InetAddress

相关方法

  • getLocalHost:获取本机 InetAddress 对象
  • getByName:根据指定主机名 / 域名获取 IP 地址对象
  • getHostName:获取 InetAddress 对象的主机名
  • getHostAddress:获取 InetAddress 对象的地址

19.3 Socket

  1. 套接字(Socket)开发网络应用程序被广泛采用,以至于成为了事实上的标准
  2. 通信的两端都要有 Socket,是两台机器间通信的端点
  3. 网络通信其实就是 Socket 间的通信
  4. Socket 允许程序把网络连接当成一个流,数据在两个 Socket 间通过 IO 传输
  5. 一般主动发起通信的应用程序属于客户端,等待通信请求的为服务端

19.3.1 TCP 网络通信编程

  1. 基于客户端——服务端的网络通信
  2. 底层使用的是 TCP / IP 协议
  3. 应用场景距离:客户端发送数据,服务端接收并显示
  4. 基于 Socket 的 TCP 编程

下面,示范一个 服务端

public void server() throws IOException{
 ServerSocket serverSocket = new ServerSocket(9000);		//[1]
 Socket clientSocket = serverSocket.accept();	   			//[2]
 //下面是输入流,不解释了
 InputStream inputStream = clientSocket.getInputStream();
 System.out.println(clientSocket.getInetAddress());
 int n;
 byte[] b = new byte[1024];
 byte[] B = new byte[0];
 while ((n = inputStream.read(b, 0, 1024)) != -1) {
     B = Arrays.copyOf(B, B.length + n);
     for (int i = 0; i < n; i++) {
         B[B.length - n + i] = b[i];
     }
 }
 serverSocket.close();										//[3]
 System.out.println(new String(B));
}
  1. ServerSocket serverSocket = new ServerSocket(9000);

    这个语句用以监听 9000 这个端口

    细节:这里要求该端口没有被其他服务占用。

  2. Socket clientSocket = serverSocket.accept();

    这个语句用以接收连接的 Socket。没有连接时,程序会阻滞在这里

    细节:此处 accept() 可以返回多个 Socket,即多并发

  3. serverSocket.close();

    结束后,务必关闭!

下面,示范一个客户端

public void client() throws IOException{
 String serverIP = "192.168.3.16";								//[1]
 Socket socket = new Socket(serverIP, 9000);					//[2]
 OutputStream outputStream = socket.getOutputStream();
 outputStream.write("hello,Server!".getBytes(StandardCharsets.UTF_8));
 socket.shutdownOutput();										//[3]
 outputStream.close();
 socket.close();
}
  1. 这个 IP 是我的本机地址。代表的是 服务端 地址

  2. Socket socket = new Socket(serverIP, 9000);

    表示访问指定 IP 的 9000 端口

  3. socket.shutdownOutput();

    这里是输出一个结束标记。若不如此做,socket 就不知道是否数据发送完成

    特别的,由 字节流 输出的场合,writer.newLine() 可以替代结束标记。但是这个场合,接收必须是 reader.readLine()

#19.3.1.1 netstat 指令

  1. netstat -an 可以查看当前主机网络情况,包括端口监听情况和网络连接情况

  2. netstat -an | more 可以分页显示

  3. netstat -anb 可以显示占用端口的应用

  4. 要求在 dos 控制台下执行

  5. Listening 表示某个端口在监听。

    如果有一个外部程序连接到该端口,就会显示一条连接信息 Established

#19.3.1.2 TCP 连接秘密

当客户端连接到服务端后,实际上客户端也是通过一个端口和服务端进行通讯的。这个端口由 TCP/IP 来分配,是不确定的,随机的。

19.3.2 UDP 网络通信编程

  1. DatagramSocketDatagramPacket 实现了基于 UDP 协议网络程序
  2. 没有明确的服务端和客户端,演变成数据的发送端和接收端
  3. UDP 数据报通过数据报套接字 DatagramSocket 发送和接收。系统不保证 UDP 数据报一定能安全送到目的地,也不能确定什么时候能抵达
  4. DatagramPacket 对象封装了 UDP 数据报,在数据报中包含了发送端的 IP 地址和端口号以及接收端的 IP 地址和端口号
  5. 接收到 DtagramPacket 对象时,需要进行拆包,取出数据
  6. DatagramSocket 可以指定在哪个端口接收数据
  7. UDP 协议中每个数据报都给出了完整的地址信息,因此无需发送方和接收方的连接

下面,示范一个接收端

DatagramSocket ds = new DatagramSocket(9000);					//[1]
byte[] bytes = new byte[1024];
DatagramPacket dp = new DatagramPacket(bytes, bytes.length);	//[2]
System.out.println("萝茵 聆听中……");
ds.receive(dp);													//[3]
int len = dp.getLength();
bytes = dp.getData();
System.out.println("萝茵听到了如下内容:\n" + new String(bytes, 0, len));
ds.close();														//[4]
  1. DatagramSocket ds = new DatagramSocket(9000);

    以 9000 这个端口作为监听端口

  2. DatagramPacket dp = new DatagramPacket(bytes, bytes.length);

    构建 DatagramPacket 对象,准备接收数据

  3. ds.receive(dp);

    监听信息,放到刚刚创建的 DatagramPacket 对象

  4. ds.close()

    要记得关闭呦 ★ ~

下面,示范一个发送端

System.out.println("萝茵,大声喊道:你好,世界!");
DatagramSocket ds = new DatagramSocket(8000);					//[1]
InetAddress ia = InetAddress.getByName(serverIP);
byte[] bytes = "你好,世界".getBytes(StandardCharsets.UTF_8);
DatagramPacket dp = new DatagramPacket(bytes, bytes.length, ia, 9001);
																//[2]
ds.send(dp);													//[3]
System.out.println("声音在虚无中回荡着……");
ds.close();														//[4]
  1. DatagramSocket ds = new DatagramSocket(8000);

    以 8000 这个端口作为发送端口

  2. DatagramPacket dp = new DatagramPacket(bytes, bytes.length, ia, 9001);

    把要发送的数据、数据长度、对象地址、对象端口 放到包里

  3. ds.send(dp);

    走你 ★ ~

  4. ds.close();

    鸟尽弓藏

附录

项目开发流程

#1 需求分析

需求分析师(懂技术 + 懂行业)

  1. 需求分析报告
    • 项目功能
    • 客户要求

#2 设计阶段

架构师 / 项目经理

  1. 设计工作

    • UML 类图
    • 流程图
    • 模块设计
    • 数据库设计
    • 架构
  2. 原型开发

  3. 组建团队

#3 实现阶段

程序员 / 码农

  1. 完成架构师的模块功能
  2. 测试自己的模块

#4 测试阶段

测试工程师

  1. 单元测试
  2. 测试用例
  3. 白盒测试
  4. 黑盒测试
  5. 集成测试

#5 实施阶段

实施工程师(开发能力 / 环境配置部署能力)

  1. 把项目正确地部署到客户的平台,并保证运行正常
  2. 身体好

#6 维护阶段

  1. 发现 bug 并解决
  2. 项目升级

<Java>19 网络编程
https://i-melody.github.io/2022/01/12/Java/入门阶段/19 网络编程/
作者
Melody
发布于
2022年1月12日
许可协议