TCP 和 UDP 在创建套接字(Socket)时的区别
1. 创建套接字的区别
(1) TCP 套接字(SOCK_STREAM)
面向连接,必须先建立连接(
connect()
/accept()
)才能通信。可靠传输,保证数据顺序、不丢失、不重复。
适用于需要稳定传输的场景(如 HTTP、FTP、SSH)。
TCP 套接字创建流程
#include <sys/socket.h>// 1. 创建 TCP 套接字(SOCK_STREAM)
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {perror("socket() failed");exit(1);
}// 2. 绑定地址(可选,服务器通常需要 bind())
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY); // 监听所有 IP
addr.sin_port = htons(8080); // 端口 8080if (bind(sockfd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {perror("bind() failed");exit(1);
}// 3. 监听连接(仅服务器需要)
if (listen(sockfd, 5) < 0) { // 5 是等待队列长度perror("listen() failed");exit(1);
}// 4. 接受连接(服务器)或发起连接(客户端)
// 服务器端:
int client_fd = accept(sockfd, NULL, NULL);
// 客户端:
connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr));
(2) UDP 套接字(SOCK_DGRAM)
无连接,直接发送数据,无需
connect()
(但可以调用connect()
绑定默认目标)。不可靠传输,数据可能丢失、乱序、重复。
适用于实时性要求高、允许少量丢包的场景(如 DNS、视频流、游戏)。
UDP 套接字创建流程
#include <sys/socket.h>// 1. 创建 UDP 套接字(SOCK_DGRAM)
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0) {perror("socket() failed");exit(1);
}// 2. 绑定地址(可选,服务器通常需要 bind())
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY); // 监听所有 IP
addr.sin_port = htons(8080); // 端口 8080if (bind(sockfd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {perror("bind() failed");exit(1);
}// 3. 直接发送/接收数据(无需 listen/accept/connect)
// 发送数据:
sendto(sockfd, buffer, buffer_len, 0, (struct sockaddr*)&dest_addr, sizeof(dest_addr));
// 接收数据:
recvfrom(sockfd, buffer, buffer_len, 0, NULL, NULL); // 不关心来源地址时
2. 核心区别对比
特性 | TCP(SOCK_STREAM ) | UDP(SOCK_DGRAM ) |
---|---|---|
连接方式 | 面向连接(connect() /accept() ) | 无连接(直接 sendto() /recvfrom() ) |
可靠性 | 可靠(不丢包、不重复、按序) | 不可靠(可能丢包、乱序) |
流量控制 | 有(滑动窗口) | 无(直接发送) |
传输效率 | 较低(有握手、确认机制) | 较高(无额外控制) |
适用场景 | HTTP、FTP、SSH、数据库 | DNS、视频流、VoIP、游戏 |
函数调用 | socket() + bind() + listen() + accept() + connect() | socket() + bind() + sendto() /recvfrom() |
3. 如何选择 TCP 还是 UDP?
用 TCP 的情况:
需要可靠传输(如文件下载、网页访问)。
数据顺序必须保证(如数据库查询)。
可以接受稍高的延迟(如 SSH 远程登录)。
用 UDP 的情况:
实时性要求高(如视频会议、在线游戏)。
允许少量丢包(如 VoIP 通话)。
需要广播/组播(如 DHCP 获取 IP)。
4. 总结
TCP | UDP | |
---|---|---|
创建方式 | socket(AF_INET, SOCK_STREAM, 0) | socket(AF_INET, SOCK_DGRAM, 0) |
是否需要 connect() | 必须(客户端) | 可选(可绑定默认目标) |
是否需要 listen() /accept() | 服务器必须 | 不需要 |
数据发送方式 | send() /recv() 或 write() /read() | sendto() /recvfrom() |
典型应用 | Web 服务器(HTTP)、SSH、MySQL | DNS、视频流、QUIC(HTTP/3) |
如果数据必须可靠到达,用 TCP;如果速度更重要,用 UDP。