JavaSE | 14-网络编程

本文更新于 2026-03-26

常见架构

维度C/S (客户端模式)B/S (浏览器模式)
硬件要求较高(利用本地资源)较低(主要靠服务器)
部署难度困难(需逐个安装)极易(地址一输即用)
升级维护整体升级,成本高无缝升级,用户无感
网络要求部分功能可离线运行必须全程联网
典型案例英雄联盟、Photoshop知乎、GitHub、1Panel

网络编程三要素

1. IP 地址 (Internet Protocol Address) —— “收货地址”

设备在网络中的唯一标识。 如果没有 IP 地址,数据包就不知道该发给哪台电脑。

  • IPv4:目前主流,如 192.168.1.1。它是 32 位地址,通常用“点分十进制”表fff示。

  • IPv6:为了解决 IPv4 地址枯竭问题,位数为 128 位,采用“冒分十六进制”。

  • 特殊地址127.0.0.1localhost(回环地址,代表本机)。

方法名作用返回值示例
getHostName()获取主机名www.baidu.comLAPTOP-XXXX
getHostAddress()获取字符串格式的 IP 地址110.242.68.4
isReachable(int timeout)测试在指定时间内是否能连接上该地址true / false(类似 ping)

2. 端口 (Port) —— “收货人姓名/房间号”

应用程序在设备中的唯一标识。 一台电脑上同时运行着微信、IDEA、拼图游戏和浏览器,IP 只能找电脑,而端口负责找到对应的程序

  • 范围:0 ~ 65535。

  • 分类

    • 周知端口 (0~1023):被系统协议占用,如 HTTP (80)、HTTPS (443)、FTP (21)。

    • 注册端口 (1024~49151):常用软件占用,如 MySQL (3306)、Tomcat (8080)、Redis (6379)。

    • 动态端口 (49152~65535):系统自动分配。

  • 注意:同一个端口在同一时刻不能被两个程序同时占用。


3. 协议 (Protocol) —— “语言/交通规则”

数据传输的规则。 通信双方必须遵守相同的约定(如数据格式、重传机制),才能听懂对方在说什么。

在 Java 基础开发中,最核心的是 传输层 的两大协议:

协议UDP (用户数据报协议)TCP (传输控制协议)
连接性面向无连接(直接发,不管对方在不在)面向连接(必须先握手建立连接)
可靠性不可靠(可能丢包、乱序)可靠(保证数据准确、有序)
传输效率极高(没有确认机制)相对较低
传输限制每个数据包限 64KB无限制(流式传输)
典型应用视频会议、直播、语音通话浏览器网页 (HTTP)、文件传输、邮件

TCP/IP协议

层级层名称核心职责 (快递比喻)常见协议
4应用层 (Application)内容制作:决定快递寄什么(信件、包裹、视频)。HTTP, FTP, DNS, SMTP
3传输层 (Transport)运输方式:平邮(UDP)还是挂号信(TCP)。TCP, UDP
2网络层 (Internet)地址路由:规划从上海到北京的最优路线。IP, ICMP, ARP
1网络接口层 (Link)物理运输:实际上是走铁路、公路还是空运。Ethernet (以太网), Wi-Fi

UDP发送数据

具体流程

  • 找邮局:创建 DatagramSocket 对象(码头/发送端)。

  • 装包裹:创建 DatagramPacket 对象,并打包数据、指定接收端 IP 和端口。

  • 发快递:调用 send() 方法发送包裹。

  • 关门走人:释放资源(close())。

	DatagramSocket ds = new DatagramSocket();  
	String s =  "你好";  
	byte[] bytes = s.getBytes();  
	InetAddress address = InetAddress.getLocalHost();  
	  
	int port = 10086;  
	  
	DatagramPacket dp =  new DatagramPacket(bytes, bytes.length, address, port);  
	  
	ds.send(dp);  
	ds.close();

UDP接收数据

具体流程

  • 设信箱:创建 DatagramSocket 对象,并明确指定端口(必须和发送端指向的端口一致)。

  • 准备空盘子:创建一个字节数组,用来存放接收到的数据。

  • 造空包裹:创建 DatagramPacket 对象,作为接收数据的容器。

  • 等快递:调用 receive() 方法。注意:这个方法是阻塞的,没收到货之前程序会一直停在这儿。

	DatagramSocket  ds = new DatagramSocket(10086);  
	  
	byte[] bytes = new byte[1024];  
	DatagramPacket dp = new DatagramPacket(bytes, bytes.length);  
	
	//receive是阻塞的
	ds.receive(dp);  
	
	byte[] data = dp.getData();  
	int len = dp.getLength();  
	InetAddress address = dp.getAddress();  
	int port = dp.getPort();  
	  
	System.out.println("接收到了来自" + address + ":" + port + "的数据:" + new String(data, 0, len));

UDP的三种通信方式

单播

  • 这是最常见的通信方式。发送端明确指定接收端的 IP 地址端口号。只有目标主机能收到数据包。

  • 特点:点对点,不会给其他不相关的机器造成负担。

  • Java 实现:使用常规的 InetAddress.getByName("192.168.1.100")

广播

  • 发送端向局域网(LAN)内的所有主机发送数据。无论对方想不想听,数据都会送到他们的门口。

  • 广播地址:固定为 255.255.255.255

  • 特点:范围限制在当前局域网内,路由器通常不会转发广播包(防止垃圾信息塞满互联网)。

  • Java 实现

	// 发送到广播地址
	InetAddress address = InetAddress.getByName("255.255.255.255");
	DatagramPacket dp = new DatagramPacket(bytes, bytes.length, address, 10086);

组播

  • 组播是介于单播和广播之间的一种高效方式。发送端向一个特定的组播地址发消息,只有“加入”了这个组的主机才能收到。

  • 组播地址范围:D 类地址(224.0.0.0 ~ 239.255.255.255)。其中 224.0.0.0 ~ 224.0.0.255 为预留。

  • 特点:比广播更节省资源,只有感兴趣的主机才会处理数据。

  • Java 实现(特殊类):接收端需要使用 MulticastSocket 并调用 joinGroup()

TCP发送和接收数据

  • 客户端 (Socket):主动拨号的人(请求连接)。

  • 服务端 (ServerSocket):接电话的人(等待连接)。

//TCP发送数据
	
	// 1. 创建客户端 Socket 对象,并连接服务端
	// 这一步会自动完成“三次握手”
	Socket socket = new Socket("127.0.0.1", 10086);

	// 2. 获取输出流,准备往服务器写数据
	OutputStream os = socket.getOutputStream();

	// 3. 写出数据
	os.write("你好,TCP服务端!我是客户端".getBytes());

	// 4. 释放资源
	os.close();
	socket.close();
	
	
//TCP接收数据

	// 1. 创建服务端的 ServerSocket,并指定端口
	ServerSocket ss = new ServerSocket(10086);

	// 2. 等待客户端连接(阻塞式)
	// 只有客户端拨通了,这行代码才会往下走,并返回一个 Socket 对象
	System.out.println("服务端已启动,等待连接...");
	Socket socket = ss.accept(); 

	// 3. 获取输入流,读取客户端发来的数据
	InputStream is = socket.getInputStream();
	byte[] bytes = new byte[1024];
	int len = is.read(bytes); // 读取数据

	// 4. 解析并打印
	String msg = new String(bytes, 0, len);
	System.out.println("收到消息:" + msg);

	// 5. 释放资源
	socket.close();
	ss.close();

三次握手 (Three-way Handshake) —— 建立连接

核心目的:确认双方的收、发能力都是正常的,并同步序列号。

  • 第一次握手:客户端发送一个 SYN 包给服务端。

    • 潜台词:“喂,你能听到我说话吗?”(客户端:确认自己能发;服务端:确认自己能收,对方能发)。
  • 第二次握手:服务端收到后,回传一个 SYN + ACK 包。

    • 潜台词:“我能听到!你能听到我说话吗?”(服务端:确认自己能发;客户端:确认自己能收,对方能发/收都正常)。
  • 第三次握手:客户端收到后,再回传一个 ACK 包。

    • 潜台词:“我也能听到。那我们要开始传数据了。”(服务端:确认对方收/发都正常)。

四次挥手 (Four-way Wave) —— 释放连接

核心目的:确保双方都发送完了数据,并优雅地关闭双向通道。

  • 第一次挥手:客户端发一个 FIN 包。

    • 潜台词:“我的数据传完了,我要挂了。”(此时客户端进入半关闭状态)。
  • 第二次挥手:服务端回一个 ACK

    • 潜台词:“我知道你要挂了,但我这儿还有点活没干完,你等会儿。”(此时服务端可能还在发最后的数据)。
  • 第三次挥手:服务端干完活了,发一个 FIN

    • 潜台词:“好了,我也干完了,挂吧。”
  • 第四次挥手:客户端回一个 ACK,并进入 TIME_WAIT 状态。

    • 潜台词:“收到,拜拜!”(客户端会等一会儿确保服务端收到了这个 ACK,然后彻底消失)。

为什么握手是 3 次,挥手要 4 次?

  • 为什么不是 2 次? * 防止“失效的连接请求”突然到达服务端。如果只有 2 次,服务端一回应就建立连接,但客户端其实已经走掉了,这会浪费服务端资源。

  • 为什么挥手多一次? * 核心原因:半关闭状态。当客户端说“我不发了”时(第一次挥手),服务端可能还有数据没发完。服务端必须先回一个 ACK 告诉客户端“我收到你的请求了”,等自己发完最后的数据,再发 FIN(第三次挥手)。中间这两步不能合并

今日访问 ... 次 | 今日访客 ... 人 | 本页阅读 ...
小站已萌萌哒运行了 0 0 0
已累计耕耘 33 篇博文 · 共 115.17k 个字
总访问量 ...
备案图标 豫公网安备41019702004633号