TCP传输协议
TCP是一种面向连接的传输协议,提供可靠的数据传输服务。它通过一系列机制确保数据从发送方准确无误地传送到接收方。
实现可靠性的原理
1、三次握手建立连接
- 第一次握手:客户端发送一个SYN(同步序列号)包给服务器,表明客户端希望建立连接。
- 第二次握手:服务器接收到SYN包,发送一个SYN-ACK(同步序列号确认)包作为响应,表示同意建立连接并确认客户端的SYN。
- 第三次握手:客户端接收到SYN-ACK包,发送一个ACK(确认)包给服务器,确认建立连接。
2、序列号和确认机制
- 序列号:发送方给每个数据段分配一个序列号,用于标识数据段的位置。
- 确认号:接收方发送ACK包,包含下一个期望接收的序列号,确认已成功接收到的数据段。
3、超时重传
- 超时时间:根据网络条件动态调整,防止频繁重传和不必要的等待。
- 重传机制:发送方在超时后重发数据段,保证丢失的数据能够被重新传输。
4、流量控制
- 窗口大小:接收方通告的接收窗口(Receive Window)大小,表示接收方当前可以接收的数据量。
- 滑动窗口:发送方根据接收方的窗口大小动态调整发送速率,防止网络拥堵和接收方的缓冲区溢出。
5、拥塞控制
- 慢启动(Slow Start):初始阶段逐步增加发送窗口,避免一开始就发送大量数据导致网络拥塞。
- 拥塞避免(Congestion Avoidance):在接近网络带宽极限时,缓慢增加发送窗口,防止拥塞。
- 快速重传(Fast Retransmit):在接收到三个重复的ACK后,立即重传丢失的数据段。
- 快速恢复(Fast Recovery):重传后,不进入慢启动阶段,而是将窗口减半,快速恢复数据传输。
6、校验和
- 校验和计算:发送方计算校验和并将其附加到数据段中。
- 校验和验证:接收方接收数据段后重新计算校验和,验证数据完整性。如果校验和不匹配,数据段将被丢弃并请求重传。
通过以上机制,TCP能够实现可靠的数据传输,确保数据的完整性、顺序性和无错误传输。
四次挥手流程图
客户端 服务器
| |
FIN_WAIT_1 (发出 FIN) ------> CLOSE_WAIT (收到 FIN,发出 ACK)
| |
FIN_WAIT_2 (收到 ACK) <------ CLOSE_WAIT (准备关闭连接)
| |
FIN_WAIT_2 (等待 FIN) <------ LAST_ACK (发出 FIN)
| |
TIME_WAIT (收到 FIN, 发出 ACK) <------ CLOSED (收到 ACK)
| |
CLOSED (等待 2*MSL) ------> CLOSED (关闭连接)
TCP传输所需API
int socket(int domain, int type, int protocol); //返回主机套接字
domain:家族协议,如AF_INET (IPv4)
或AF_INET6 (IPv6)
。
type:套接字类型SOCK_STREAM (TCP)
。
protocol:协议,一般默认0
系统帮忙选择合适的协议。
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); //绑定套接字
sockfd:套接字文件描述符。
addr:包含地址和端口的结构体。
addrlen:地址结构体的长度。
int listen(int sockfd, int backlog); //设置套接字为监听模式,准备接受连接
sockfd:套接字文件描述符。
backlog:请求队列的最大长度。
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); //接受连接请求,连接成功返回一个客户端套接字
sockfd:监听套接字文件描述符。
addr:指向存储客户端地址的结构体。
addrlen:地址结构体的长度。
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); //向服务器发起连接请求
sockfd:监听套接字文件描述符。
addr:指向存储客户端地址的结构体。
addrlen:地址结构体的长度。
ssize_t send(int sockfd, const void *buf, size_t len, int flags); //发送数据
ssize_t recv(int sockfd, void *buf, size_t len, int flags); //接收数据
sockfd:监听套接字文件描述符。
buf:数据缓冲区。
len:缓冲区长度。
falgs:可选的标志位(通常为 0),可设置非阻塞。
int close(int sockfd); //关闭套接字
int shutdown(int sockfd, int how); //关闭套接字部分通道
sockfd:套接字文件描述符。
how:指定关闭方式,如 SHUT_RD
、SHUT_WR
或 SHUT_RDWR
,选择关闭部分套接字管道。