一、面向字节流
- 传输单位 :以字节 为基本单位,数据是连续的 "流",没有明确的边界 。例如,发送方连续发送多个字节,接收方可能按任意字节数读取 ,无法直接区分 "一个完整的消息"。
- 可靠性 :通常是可靠传输(如 TCP 协议),会保证数据的顺序性、无丢失、无重复。发送方会确认数据是否被接收,若丢失则重传。
- 应用场景 :适合对数据完整性要求高的场景,如 文件传输(FTP)、网页浏览(HTTP)、邮件发送(SMTP)等。这些场景需要确保数据完整、有序地到达,哪怕传输过程中需要拆分或重组字节流。
二、面向数据报
- 传输单位 :以 数据报(Datagram)为基本单位,每个数据报是独立的 "数据包 ",有明确 的边界。发送方发送一个数据报,接收方必须完整读取这个数据报才能处理。
- 可靠性 :通常是不可靠传输(如 UDP 协议),不保证数据的顺序性、可能丢失或重复。发送方发送后不会确认,数据报直接 "尽力交付"。
- 应用场景 :适合对实时性要求高、可容忍少量丢包 的场景,如视频通话(UDP)、在线游戏、DNS 解析等。数据报的独立传输特性,让它在低延迟场景下更具优势。
总结来说,两者的核心差异在于数据的传输粒度和可靠性设计:面向字节流追求 "完整有序",面向数据报追求 "快速独立"。
三、字节、字符、数据包
1. 字节(Byte)
- 定义 :计算机存储和传输的最小单位 ,由 8 个二进制位(bit)组成。例如,字母 "A" 在计算机中用 1 个字节存储(ASCII 编码:
01000001)。 - 特点:是 "硬件层面" 的基本单元,所有数据最终都会被拆分为字节进行存储或传输。
2. 字符(Character)
- 定义 :人类可识别的文字符号 (如字母、汉字、标点),其在计算机中的存储依赖 "编码方式",不同编码下字符与字节的对应关系不同 。
- 例 1:ASCII 编码中,1 个字符 = 1 个字节(如 "a"→1 字节)。
- 例 2:UTF-8 编码中,英文字符 1 字节,汉字通常 3 字节(如 "中"→3 字节)。
- 特点:是 "人类语义层面" 的单位,用于表达信息;其底层存储依赖字节,是 "字节的上层抽象"。
3. 数据包(Data Packet)
- 定义 :网络传输中逻辑上的独立数据单元,包含 "数据内容" 和 "控制信息"(如目的地址、源地址、校验码等)。
- 构成 :数据包的 "数据内容" 可以是字节流 或字符对应的字节 ,再加上头部(控制信息)和尾部(校验等)组成完整数据包。
- 例:你发送一条消息 "Hello",在网络中会被拆分为字节(H→
01001000、e→01100101等),再封装成数据包(添加目的 IP、源 IP 等头部)进行传输。
- 例:你发送一条消息 "Hello",在网络中会被拆分为字节(H→
- 特点 :是 "网络传输层面" 的单位,用于在网络中高效、有序地传递数据;数据包是字节 / 字符的 "传输载体"。
三者的关系总结
- 字节是底层存储 / 传输的最小单元;
- 字符是字节的上层语义抽象(用于表达人类可理解的符号);
- 数据包是字节 / 字符在网络中传输时的 "封装形式",通过添加控制信息实现可靠或快速传输。
不管是字节流(如 TCP)还是数据报(如 UDP),本质上都是先把字符(或其他数据)解析为字节(按指定编码,比如 UTF-8、GBK),再以字节为单位传输
四、Socket API 与操作系统的关系
Socket 是操作系统提供的网络编程接口,它属于操作系统的内核功能。简单来说,开发者通过 Socket API 向操作系统 "请求网络通信能力",由操作系统底层完成实际的网卡操作、数据传输等复杂工作。
五、操作系统的 "广义文件" 抽象
在操作系统中,"文件" 是一个高度抽象的概念 ------ 不仅包含普通的文本 / 二进制文件,还包含硬件设备 (如网卡、键盘、磁盘等)。操作系统将这些硬件设备也 "伪装 " 成文件,通过统一的 "打开 - 读写 - 关闭" 流程 来管理,目的是简化开发者的操作复杂度。
以网卡为例:
- 直接操作网卡硬件非常复杂(需要处理底层协议、硬件驱动等)。
- 操作系统将网卡 "抽象成 Socket 文件",开发者只需像操作普通文件一样 "打开 Socket → 读写数据 → 关闭 Socket",就能间接完成网卡的网络通信工作。
六、"文件描述符表" 的作用
当你在程序中 "打开 " 一个文件(或 Socket)时,操作系统会在 "文件描述符表" 中为它分配一个唯一的 "表项"(即文件描述符,是一个整数)。这个表项是程序与操作系统交互的 "索引"------ 程序通过文件描述符,就能让操作系统识别并操作对应的文件(或硬件设备,如网卡)。
比如,当你创建一个 UDP Socket 时,操作系统会在文件描述符表中分配一个表项,后续对这个 Socket 的 "读写" 操作,都会通过这个表项关联到实际的网卡硬件。
七、UDP Socket 的核心组件(DatagramSocket & DatagramPacket)
在 Java 等语言的 UDP 编程中,这两个类是核心:
1. DatagramSocket
- 它是 "网卡遥控器" 的抽象 ,负责 "打开、关闭 Socket 连接" 以及 "发送 / 接收数据的通道管理"。
- 功能:
- 绑定端口:让操作系统知道 "哪个端口的 UDP 数据要交给这个 Socket 处理"。
- 发送 / 接收数据:但它不直接处理 "数据内容 ",而是通过
DatagramPacket来传递数据。 - 生命周期管理:完成通信后,需要关闭
DatagramSocket以释放系统资源。
2. DatagramPacket
- 它是 "UDP 数据包 " 的容器 ,封装了 "要传输的数据内容 " 和 "数据的元信息"(如目标 IP、目标端口、源 IP 等)。
- 功能:
- 作为 "发送载体":你需要把要发送的字节数据 放入
DatagramPacket,并设置目标地址 / 端口 ,再通过DatagramSocket发送出去。 - 作为 "接收载体":
DatagramSocket接收 UDP 数据时,会把数据存入DatagramPacket,你可以从这个对象中读取接收到的字节数据,以及数据的来源地址 / 端口。
- 作为 "发送载体":你需要把要发送的字节数据 放入
DatagramSocket
DatagramSocket 是 UDP Socket,用于发送和接收 UDP 数据报。
构造方法
| 方法签名 | 方法说明 |
|---|---|
DatagramSocket() |
创建一个 UDP 数据报套接字的 Socket,绑定到本机任意一个随机端口(一般用于客户端) |
DatagramSocket(int port) |
创建一个 UDP 数据报套接字的 Socket,绑定到本机指定的端口(一般用于服务端) |
方法
| 方法签名 | 方法说明 |
|---|---|
void receive(DatagramPacket p) |
从此套接字接收数据报(如果没有接收到数据报,该方法会阻塞等待) |
void send(DatagramPacket p) |
从此套接字发送数据报包(不会阻塞等待,直接发送) |
void close() |
关闭此数据报套接字 |
DatagramPacket
DatagramPacket是 UDP Socket 发送和接收的数据报。
构造方法
| 方法签名 | 方法说明 |
|---|---|
DatagramPacket(byte[] buf, int length) |
构造一个DatagramPacket以用来接收数据报,接收的数据保存在字节数组(第一个参数buf)中,接收指定长度(第二个参数length) |
DatagramPacket(byte[] buf, int offset, int length, SocketAddress address) |
构造一个DatagramPacket以用来发送数据报,发送的数据为字节数组(第一个参数buf)中,从0到指定长度(第二个参数length)。address指定目的主机的 IP 和端口号 |
方法
| 方法签名 | 方法说明 |
|---|---|
InetAddress getAddress() |
从接收的数据报中,获取发送端主机 IP 地址;或从发送的数据报中,获取接收端主机 IP 地址 |
int getPort() |
从接收的数据报中,获取发送端主机的端口号;或从发送的数据报中,获取接收端主机端口号 |
byte[] getData() |
获取数据报中的数据 |
补充说明
构造 UDP 发送的数据报时,需要传入 SocketAddress,该对象可以使用 InetSocketAddress 来创建。
InetSocketAddress(SocketAddress 的子类)构造方法
| 方法签名 | 方法说明 |
|---|---|
InetSocketAddress(InetAddress addr, int port) |
创建一个 Socket 地址,包含 IP 地址和端口号 |
(1)UDP 回声服务器(UdpEchoServer)
功能:接收客户端数据,原样返回(回声效果)。

(2)UDP 回声客户端(UdpEchoClient)
功能:向服务器发送用户输入,接收并打印服务器的回声响应。

(3)UDP 英译汉字典服务器(UdpDictServer)
功能:扩展回声服务器,将 "回声逻辑" 改为 "英译汉逻辑",通过继承复用原有代码。

八、TCP 流套接字编程
ServerSocket
ServerSocket 是创建 TCP 服务端 Socket 的 API。
- 构造方法
| 方法签名 | 方法说明 |
|---|---|
ServerSocket(int port) |
创建一个服务器流套接字 Socket,并绑定到指定端口 |
- 方法
| 方法签名 | 方法说明 |
|---|---|
Socket accept() |
开始监听指定端口(创建时绑定的端口)。有客户端连接后,返回一个服务端 Socket 对象,并基于该 Socket 建立与客户端的连接,否则阻塞等待 |
void close() |
关闭此套接字 |
Socket
Socket 是客户端 Socket,或服务端中接收到客户端建立连接(accept方法)的请求后,返回的服务端 Socket。不管是客户端还是服务端 Socket,都是双方建立连接以后,保存的对端信息,及用来与对方收发数据的。
- 构造方法
| 方法签名 | 方法说明 |
|---|---|
Socket(String host, int port) |
创建一个客户端流套接字 Socket,并与对应的主机上,对应端口的进程建立连接 |
- 方法
| 方法签名 | 方法说明 |
|---|---|
InetAddress getInetAddress() |
返回套接字所连接的地址 |
InputStream getInputStream() |
返回此套接字的输入流 |
OutputStream getOutputStream() |
返回此套接字的输出流 |