news 2026/4/24 20:44:37

TCP与UDP通信

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
TCP与UDP通信

一、TCP与UDP

对比项TCP(确保把信号送到)UDP(不管在不在都送出去)
特点面向连接、可靠传输、流量控制、拥塞控制、全双工无连接、尽力交付、无重传、无拥塞控制、低开销
优点可靠性(ACK确认、超时重传)、顺序性传输效率高(8字节首部)、实时性强
缺点首部开销大(20字节)、连接管理复杂、延迟高数据可能丢失、乱序
应用场景HTTP/HTTPS、文件传输(FTP)、邮件(SMTP/IMAP)视频流(RTP)、DNS查询、在线游戏、VoIP

TCP首部包含:源端口号;序列号;校验和

目标端口未监听;网络拥塞会导致TCP链接失效

二、TCP通信

2.1 TCP网络编程流程

步骤服务器流程函数
1创建流式套接字socket()
2填充服务器的网络信息结构体struct sockaddr_in
3将套接字与服务器的网络信息结构体绑定bind()
4将套接字设置成被动监听状态listen()
5阻塞等待客户端连接accept()
6收发数据recv() / send()
7关闭套接字close()

2.2 socket编程

2.2.1 socket函数

项目内容
头文件#include <sys/socket.h>
函数原型int socket(int domain, int type, int protocol);
参数 - domainAF_INET(IPv4)、AF_INET6(IPv6)、AF_PACKET(原始套接字)、AF_UNIX(本地通信)、AF_LOCAL(本地通信)
参数 - typeSOCK_STREAM(TCP)、SOCK_DGRAM(UDP)、SOCK_RAW(原始套接字)
参数 - protocol无附加协议填0(自动选择默认协议)
返回值成功返回套接字(文件描述符,非负整数),失败返回-1(并重置错误码)

2.2.2 bind函数

项目内容
头文件#include <sys/socket.h>
函数原型int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
参数 - sockfd文件描述符(由 socket 函数返回)
参数 - addr地址结构体指针,指向要绑定给 sockfd 的协议地址(以 IPv4 的 struct sockaddr_in 为例)
参数 - addrlen地址的长度
返回值成功返回 0,失败返回 -1(并重置错误码)
//addr 结构体 struct sockaddr_in { sa_family_t sin_family; in_port_t sin_port; struct in_addr sin_addr; }; //sin_addr 结构体 struct in_addr { uint32_t s_addr; };

定义结构体后要用memset函数清空结构体

项目内容
头文件<string.h>
函数原型void *memset(void *s, int c, size_t n);
作用将指针s指向的内存区域的前n个字节,全部设置为c的值
返回值返回指针s(即填充后的内存起始地址)

也可以直接 struct sockaddr_in serverInfo = {0};

结构体的初始化

//定义配置服务器地址结构体 struct sockaddr_in serverInfo; //清空结构体 memset(&serverInfo,0,sizeof(serverInfo)); //初始化IPV4协议族 serverInfo.sin_family = AF_INET; //初始化端口号 (主机字节序->网络字节序) serverInfo.sin_port = htons(8888); //初始化IP serverInfo.sin_addr.s_addr = inet_addr("192.168.23.100");

2.2.3 listen函数

项目内容
头文件#include <sys/socket.h>
函数原型int listen(int sockfd, int backlog);
参数 - sockfd表示要监听的 socket 套接字
参数 - backlog表示半连接队列的长度(即 socket 可以排队的最大连接个数)
返回值成功返回 0,失败返回 -1(并重置错误码)

把socket从主动变成被动监听状态

2.2.4 accept函数(阻塞函数)

项目内容
头文件#include <sys/socket.h>
函数原型int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
参数 - sockfd表示处于监听状态的 socket
参数 - addr用于保存客户端地址的结构体指针,如果不关心客户端的信息,可以传 NULL
参数 - addrlen输入时为 addr 的缓冲区大小,输出时为实际地址长度,如果不关心客户端的信息,可以传 NULL
返回值成功返回新的 socket 文件描述符(由内核生成,代表着与返回客户端的 TCP 连接,专用于与客户端通信),失败返回 -1(并重置错误码)

2.2.5 connect函数

项目内容
头文件#include <sys/socket.h>
函数原型int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
参数 - sockfd表示客户端的 socket 套接字
参数 - addr表示目标服务器的地址结构体
参数 - addrlen地址结构体的长度
返回值成功返回 0,失败返回 -1(并重置错误码)

2.2.6 recv函数

项目内容
头文件#include <sys/socket.h>
函数原型ssize_t recv(int sockfd, void *buf, size_t len, int flags);
参数 - sockfd表示客户端的 socket 套接字(connect_fd)
参数 - buf用于存储接收的数据
参数 - len数据大小
参数 - flags控制选项(如 MSG_DONTWAIT 非阻塞,MSG_PEEK 窥视数据,0 阻塞)
返回值成功返回实际接收数据字节数,0表示客户端断开链接,失败返回 -1(并重置错误码)

recv()不是从buf里收数据,而是从内核的接收缓冲区里收数据

2.2.7 send函数

项目内容
头文件#include <sys/socket.h>
函数原型ssize_t send(int sockfd, const void *buf, size_t len, int flags);
参数 - sockfd表示客户端的 socket 套接字
参数 - buf要发送的数据首地址
参数 - len数据大小
参数 - flags控制选项(如 MSG_DONTWAIT 非阻塞,MSG_PEEK 窥视数据,0 阻塞)
返回值成功返回实际发送数据字节数,失败返回 -1(并重置错误码)

2.2.8 close函数

项目内容
头文件#include <unistd.h>
函数原型int close(int fd);
参数 - fd表示要关闭的套接字
返回值成功返回 0,失败返回 -1

2.3 系统内核处理

函数内核处理
socket()创建套接字结构体,分配文件描述符
bind()把IP和端口号绑定到套接字
listen()创建半连接队列和全连接队列,转为监听状态
accept()从全连接队列取出已完成连接的客户端,生成新套接字
connect()发起三次握手,发送SYN包
recv()从内核接收缓冲区拷贝数据到用户空间
send()从用户空间拷贝数据到内核发送缓冲区
close()释放套接字资源,发起四次挥手

2.4 TCP网络编程流程

步骤客户端操作调用的函数
1创建流式套接字socket()
2填充服务器的网络信息结构体struct sockaddr_in
3与服务器建立连接connect()
4收发数据send()/recv()
5关闭套接字close()

Telnet是一种远程登录协议,用于通过网络连接到另一台计算机的终端。后接服务器IP

2.5 三次握手

确保双方都能正常收发数据,同步初始序号,避免历史连接请求造成混乱,为后面的可靠传输打好基础。

2.5.1 三次握手的状态变化

发送方服务端状态变化客户端状态变化原因说明
客户端CLOSED → SYN_SENT客户端主动发起连接,发出同步请求,等待服务端确认
服务端LISTEN → SYN_RCVDSYN_SENT(不变)服务端收到 SYN,回复确认并携带自己的 SYN,表示愿意连接;自身进入半连接状态,等待客户端最终确认
客户端SYN_RCVD → ESTABLISHEDSYN_SENT → ESTABLISHED客户端收到 SYN+ACK,确认连接可用,双方进入数据传输状态

2.5.2 两次握手不可以原因

问题类型两次握手的问题三次握手如何解决
数据包丢失服务端发的 SYN+ACK 丢失后,客户端不知道、服务端空等,造成半开连接

客户端收到 SYN+ACK 后必须回复 ACK,服务端收到 ACK 才认为连接建立;

若 ACK 丢失会重发或超时关闭,避免空等

SYN 攻击风险攻击者发一个 SYN,服务端就立即分配资源建立连接,极易耗尽内存服务端发 SYN+ACK 后不分配应用资源,收到客户端的 ACK 确认后才真正建立连接,有效抵抗伪造 SYN 攻击

2.6 四次挥手

2.6.1 四次握手的状态变化

第几次挥手发送方状态变化原因
第一次客户端ESTABLISHED → FIN_WAIT_1客户端主动关闭,表示“我没数据要发了”,进入等待服务端确认的状态
第二次服务端ESTABLISHED → CLOSE_WAIT服务端收到 FIN,回复确认,表示“我知道你要关了”;但服务端可能还有数据要发,所以先进入半关闭状态
客户端FIN_WAIT_1 → FIN_WAIT_2收到服务端的 ACK 确认,进入 FIN_WAIT_2,等待服务端发 FIN
第三次服务端CLOSE_WAIT → LAST_ACK服务端数据发完了,主动发送 FIN,表示“我也没数据要发了”,等待客户端最后一次确认
第四次客户端FIN_WAIT_2 → TIME_WAIT收到服务端的 FIN,回复确认,但不确定 ACK 是否丢失,所以等待 2MSL(保证服务端能收到 ACK)
服务端LAST_ACK → CLOSED收到客户端的 ACK,连接彻底关闭
客户端TIME_WAIT → CLOSED2MSL 时间到,没有收到重传的 FIN,确认服务端已收到 ACK,连接关闭

因为TCP的全双工特性,所以会有四次握手

2.6.2 四次挥手不可以合并成三次

服务端收到客户端的 FIN 后,可能还有数据没发完,所以先回复ACK 表示“我知道你要关了”,等数据发完再发 FIN。第二次和第三次挥手不能合并,因为中间可能有数据传输。

2.7 两种过程使用时间

过程使用时机
三次握手通信开始前,客户端和服务端建立连接时使用
四次挥手通信结束后,客户端或服务端释放连接时使用

三、UDP通信流程

3.1 相关函数

3.1.1 recvfrom函数

项目内容
头文件#include <sys/socket.h>
#include <sys/types.h>
函数原型ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
参数 - sockfd表示客户端的 socket 套接字
参数 - buf要接收的数据首地址
参数 - len可接受数据的最大长度
参数 - flags控制选项(如 MSG_DONTWAIT 非阻塞,MSG_PEEK 窥视数据,0 阻塞)
参数 - src_addr源地址,获取发送方的信息
参数 - addrlen地址长度
返回值成功返回接收字节数,失败返回 -1(并重置错误码)

3.1.2 sendto函数

项目内容
头文件#include <sys/socket.h>
#include <sys/types.h>
函数原型ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
参数 - sockfd表示客户端的 socket 套接字
参数 - buf要发送的数据首地址
参数 - len数据大小
参数 - flags控制选项(如 MSG_DONTWAIT 非阻塞,MSG_PEEK 窥视数据,0 阻塞)
参数 - dest_addr目的地址,数据将要发向哪一个 IP 地址的主机
参数 - addrlen地址长度
返回值成功返回发送字节数,失败返回 -1(并重置错误码)

3.1.3 sendto函数

项目内容
头文件#include <sys/socket.h>
#include <sys/types.h>
函数原型ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
参数 - sockfd表示客户端的 socket 套接字
参数 - buf要发送的数据首地址
参数 - len数据大小
参数 - flags控制选项(如 MSG_DONTWAIT 非阻塞,MSG_PEEK 窥视数据,0 阻塞)
参数 - dest_addr目的地址,数据将要发向哪一个 IP 地址的主机
参数 - addrlen地址长度
返回值成功返回发送字节数,失败返回 -1(并重置错误码)

3.2 单播

单播:一对一通信,数据包从单一源地址发送到单一目标地址

层级职责
应用层调用sendto()发送数据到指定目标 IP 和端口
调用recvfrom()接收来自特定源的数据
传输层封装 UDP 头部:源端口、目标端口、长度、校验和
不建立连接,直接发送数据报
网络层封装 IP 头部:源 IP、目标 IP(单播地址,如 192.168.1.100)
根据目标 IP 查找路由表,选择下一跳
链路层根据目标 IP 的 MAC 地址(通过 ARP 解析)封装以太网帧
通过物理网络设备(如网卡)发送到目标主机

3.3 组播

组播:一对多通信,数据包发送到一个组播组,组内所有成员均可接收

层级职责
应用层发送端:调用发送数据到组播地址(如 239.255.0.1)
接收端:调用加入组播组(IP_ADD_MEMBERSHIP)
传输层封装 UDP 头部:目标端口为组播端口(如 12345)
组播成员无需提前建立连接
网络层封装 IP 头部:目标 IP 为组播地址(D 类地址,224.0.0.0~239.255.255.255)
接收端通过 IGMP 报文通知路由器加入/离开组播组
路由器维护组播组成员列表,仅向存在成员的子网转发数据
数据链路层组播 MAC 地址映射:将 IP 组播地址转换为以太网组播 MAC(如 01:00:5E:XX:XX:XX)
交换机/路由器:根据组播 MAC 地址复制数据包到多个端口

3.4 setsockopt函数

项目内容
头文件#include <sys/socket.h>
函数原型int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);
参数 - sockfd目标套接字描述符,表示需要配置的套接字
参数 - level选项层级(如 SOL_SOCKET、IPPROTO_IP)
参数 - optname选项名称(如 SO_REUSEADDR、IP_ADD_MEMBERSHIP)
参数 - optval指向选项值的指针,类型和长度需与 optname 匹配
参数 - optlenoptval 指向的数据长度
返回值成功返回 0,失败返回非 0 数据

3.5 广播

广播:一对所有通信,数据包发送到同一网络内的所有主机

层级职责
应用层发送端:调用setsockopt()启用广播选项(SO_BROADCAST
调用sendto()发送数据到广播地址(如 255.255.255.255)
传输层封装 UDP 头部:目标端口为广播端口(如 9999)
接收端无需加入组,但需监听指定端口
网络层封装 IP 头部:目标 IP 为广播地址(受限广播 255.255.255.255 或定向广播 192.168.1.255)
受限广播仅在本局域网内传播,路由器默认不转发
定向广播可跨子网(需路由器支持,通常被禁用)
数据链路层广播 MAC 地址:FF:FF:FF:FF:FF:FF
交换机将广播包泛洪到所有端口(除源端口)
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/24 20:41:17

终极指南:Sealed Secrets CRD升级全流程解析与实战技巧

终极指南&#xff1a;Sealed Secrets CRD升级全流程解析与实战技巧 【免费下载链接】sealed-secrets A Kubernetes controller and tool for one-way encrypted Secrets 项目地址: https://gitcode.com/GitHub_Trending/se/sealed-secrets Sealed Secrets是一个Kubernet…

作者头像 李华
网站建设 2026/4/24 20:40:19

Vue Design System:从零开始构建企业级UI设计系统的完整指南

Vue Design System&#xff1a;从零开始构建企业级UI设计系统的完整指南 【免费下载链接】vue-design-system An open source tool for building UI Design Systems with Vue.js 项目地址: https://gitcode.com/gh_mirrors/vu/vue-design-system Vue Design System 是一…

作者头像 李华
网站建设 2026/4/24 20:39:17

CKEditor5自定义命令开发终极指南:实现一键格式化与内容转换

CKEditor5自定义命令开发终极指南&#xff1a;实现一键格式化与内容转换 【免费下载链接】ckeditor5 Powerful rich text editor framework with a modular architecture, modern integrations, and features like collaborative editing. 项目地址: https://gitcode.com/Git…

作者头像 李华