Socket 详细描述Socket(套接字) 是计算机网络通信中的一个抽象概念,它是应用层与传输层(TCP/IP协议栈)之间的编程接口(API)。简单来说,Socket 是网络上两个应用程序进行双
Socket 详细描述
Socket(套接字) 是计算机网络通信中的一个抽象概念,它是应用层与传输层(TCP/IP协议栈)之间的编程接口(API)。简单来说,Socket 是网络上两个应用程序进行双向通信的端点,它构成了网络通信的基础。
一、Socket 的本质与定义
从不同的角度看,Socket 有不同的含义:
-
编程接口:对于程序员来说,Socket 是一组操作系统提供的 API(如
socket(),bind(),connect()等)。它屏蔽了底层复杂的 TCP/IP 协议细节,让开发者能像读写文件一样通过网络发送和接收数据。 -
通信端点:在网络层面,Socket 是一个五元组(或更简单的三元组/二元组)定义的连接终点。
-
通用五元组:
(协议, 源IP, 源端口, 目的IP, 目的端口) -
这个五元组唯一标识了网络中的一个连接。
-
-
文件描述符:在类 Unix 系统(Linux/Mac)中,Socket 是一种特殊的文件。当它被创建后,会返回一个整数形式的文件描述符(File Descriptor),可以用
read/write等操作来处理网络数据。
二、Socket 的核心组成要素
一个 Socket 绑定了以下四个核心要素(即其地址):
-
协议族(Protocol Family):指定通信使用的网络协议。
-
AF_INET:IPv4 互联网协议(最常用)。 -
AF_INET6:IPv6 互联网协议。 -
AF_UNIX/AF_LOCAL:用于同一台机器上的进程间通信(IPC)。
-
-
Socket 类型(Type):指定通信的语义(数据传输方式)。
-
SOCK_STREAM(流式套接字):面向连接的、可靠的、基于字节流的通信。对应 TCP 协议。 -
SOCK_DGRAM(数据报套接字):无连接的、不可靠的、固定长度的数据报通信。对应 UDP 协议。 -
SOCK_RAW(原始套接字):允许直接访问底层协议(如 IP 或 ICMP),常用于开发网络工具(如 ping、traceroute)。
-
-
本地 IP 地址:本机在网络中的地址。
-
本地端口号(Port):用于区分本机上不同的网络应用程序(0-65535)。
三、Socket 的类型详解
1. 流式套接字 (TCP)
-
特点:
-
面向连接:通信前必须先建立连接(三次握手)。
-
可靠传输:数据保证送达,按序到达,且有重传机制。
-
字节流:没有消息边界,发送方多次写入可能被接收方一次读取(粘包问题需应用层自己处理)。
-
全双工:双方可以同时发送和接收数据。
-
-
应用场景:Web 浏览(HTTP/HTTPS)、文件传输(FTP)、邮件(SMTP)、SSH 登录等需要数据完整性的场景。
2. 数据报套接字 (UDP)
-
特点:
-
无连接:不需要建立连接,直接发送数据。
-
不可靠:不保证数据到达,不保证顺序,也没有重传。
-
数据报:保留了消息边界,发送一次,接收方就读取一次。
-
低延迟:头部开销小,没有拥塞控制,速度快。
-
-
应用场景:视频直播、语音通话(VoIP)、在线游戏、DNS 查询等对实时性要求高、能容忍少量丢包的场景。
3. 原始套接字 (Raw Socket)
-
特点:绕过传输层(TCP/UDP),直接操作网络层数据包。
-
应用场景:网络扫描、协议分析(如 Wireshark)、自定义协议开发。通常需要 Root/Administrator 权限。
四、Socket 通信流程(TCP 示例)
TCP 通信采用经典的 Client-Server(客户端-服务器)模型。
服务器端 (Server) 流程:
-
创建 Socket (
socket())创建一个套接字对象,指定协议族和类型。
-
绑定地址 (
bind())将套接字与本机的 IP 地址和端口号绑定。
-
监听 (
listen())开始监听来自客户端的连接请求,设置等待队列的长度。
-
接受连接 (
accept())阻塞等待客户端连接。一旦有连接到来,返回一个新的套接字(已连接套接字),专门用于与该客户端通信。原来的监听套接字继续负责迎接新客人。
-
收发数据 (
recv()/send())使用返回的新的套接字与客户端进行数据交换。
-
关闭连接 (
close())通信结束后关闭套接字。
客户端 (Client) 流程:
-
创建 Socket (
socket()) -
发起连接 (
connect())向服务器的 IP 和端口发起连接请求(触发三次握手)。
-
收发数据 (
send()/recv()) -
关闭连接 (
close())
(注:UDP 不需要 listen 和 accept,也没有 connect 的概念,直接通过 sendto 和 recvfrom 向指定地址发送/接收数据报)
五、关键概念解析
1. 阻塞与非阻塞 (Blocking vs Non-blocking)
-
阻塞:默认模式。调用
recv()时如果没有数据,程序会一直停在那里等待,直到有数据到来;调用accept()时没有连接,也会一直等待。 -
非阻塞:设置后,如果调用
recv()没有数据,函数会立即返回一个错误(如EWOULDBLOCK),程序可以继续执行其他任务。常用于高并发服务器。
2. I/O 多路复用 (IO Multiplexing)
为了解决大量 Socket 连接的管理问题,引入了 select, poll, epoll (Linux) / kqueue (BSD) 等机制。
-
原理:一个线程监视多个 Socket。当某个 Socket 就绪(可读/可写/异常)时,通知程序进行处理。
-
优势:单线程即可处理成千上万的连接,是高性能网络服务器(如 Nginx, Redis)的基石。
3. 粘包与拆包 (TCP Sticky Problem)
由于 TCP 是字节流,内核为了效率可能会将多次 send 的数据合并成一次发送(粘包),也可能将一个大数据包拆分成多个小包发送(拆包)。
-
解决方案(应用层自己定义规则):
-
定长消息。
-
使用特殊分隔符(如 HTTP 的
\r\n)。 -
在消息头中声明消息体长度(TLV 格式,最常用)。
-
六、常用 Socket API 函数速查
|
函数 |
作用 |
备注 |
|---|---|---|
|
|
创建套接字 |
返回文件描述符 |
|
|
绑定IP和端口 |
服务端必备 |
|
|
监听端口 |
服务端必备 |
|
|
接受连接 |
返回新的连接fd |
|
|
发起连接 |
客户端必备 |
|
|
发送数据 |
|
|
|
接收数据 |
|
|
|
关闭连接 |
|
|
|
设置套接字选项 |
如设置重用地址 |
七、总结
Socket 是网络编程的入口。它不仅仅是代码层面的 API,更是计算机网络中端到端通信这一抽象概念的具象化体现。
-
如果你需要可靠的文件传输,请选择 TCP Socket。
-
如果你需要极低的延迟(如视频通话),请选择 UDP Socket。
-
如果你想构建高性能服务器,必须掌握 非阻塞 I/O 和 I/O 多路复用技术。
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐


所有评论(0)