详解TCP网络协议栈的工作原理
来源 | OSCHINA 社区
作者 | 华为云开发者联盟-Lion Long
原文链接:https://my.oschina.net/u/4526289/blog/10090377
一、TCP 网络开发 API
TCP,全称传输控制协议(Transmission Control Protocol),是一种面向连接的、可靠的、基于字节流的传输层通信协议。
1.1、TCP 服务器调用的 API
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
// 1
int socket(int domain, int type, int protocol);
// 2
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
// 3
int listen(int sockfd, int backlog);
// 4
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
// 5
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
// 6
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
// 7
int close(int fd);
// 8
int shutdown(int sockfd, int how);
1.2、TCP 客户端调用的 API
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
// 1
int socket(int domain, int type, int protocol);
// 2
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
// 3
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
// 4
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
// 5
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
// 6
int close(int fd);
// 7
int shutdown(int sockfd, int how);
1.3、API 函数的作用
二、TCP 的三个阶段
2.1 TCP 建立连接
2.1.1、TCP 的三次握手
0 |1 |2 |3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-------------------------------+-------------------------------+
| Source Port | Destination Port |
+---------------------------------------------------------------+
| Sequence Number |
+---------------------------------------------------------------+
| Acknowledgment Number |
+-------+-----------+-+-+-+-+-+-+-------------------------------+
| Header| Reserve |U|A|P|R|S|F| Window |
| Length| |R|C|S|S|Y|I| |
| | |G|K|H|T|N|N| |
+-------------------------------+-------------------------------+
| Checksum | Urgent Pointer |
+---------------------------------------------------------------+
| Option |
+---------------------------------------------------------------+
| Data |
| ... |
+---------------------------------------------------------------+
SYN:即 synchronous,同步。
ACK:即 acknowledgement,确认。
PSH:即 push,推送。
FIN :即 finish,结束。
RST:即 reset,重置。
URG:即 urgent,紧急。
Sequence Number:是数据包本身第一个字节的序列号。
Acknowledge Number:是期望对方继续发送的那个确认数据包的序列号其值一般为接收到的 Sequence Number 加 1。
2.1.2、TCP 状态转换
2.2 TCP 传输数据
2.2.1、传输控制块 TCB
2.2.2、TCP 分包
2.2.3、TCP 粘包及解决方案
// ...
ssize count=0;
ssize size=0;
while(count<tcpHdr->length)
{
size=recv(fd,buffer,buffersize,0);
count+=size;
}
// ...
(2)为每个包添加分隔符。在数据末尾添加分隔符,这会导致解数据可能需要有合包操作;因为分割数据包后,需要记录后一个数据包,用于与该包后面部分数据进行合并。
2.3 TCP 四次挥手
断开连接是比建立连接和传输数据还复杂的一个过程,断开连接主要分为主动关闭和被动关闭两种。
四次挥手示意图:
需要注意的是,调用 close () 不是立即完成断开,而是关闭了数据传输,进入了四次挥手阶段,TCB 数据结构还没有释放。四次挥手结束才真正把 TCB 释放。
根据四次挥手流程,可以思考一些问题:
(1)传输数据过程中,网线断了之后立刻连接,TCP 如何知道?
网线掉线网卡会停止供电,再次连接后网卡恢复供电,网卡服务重启,网络连接重连。应用程序设计通过心跳包检测。
(2)服务器如何知道客户端是否宕机?
一样需要通过心跳包机制来检测。
(3)服务器如何甄别网络阻塞和宕机?
服务器发送心跳包时,不仅仅发一次,而是要发送多次的;如果是网络阻塞,那么在一定时间内一定有回复信息;如果是宕机,无论多长时间都没有客户端的回复。
(4)如果出现大量的 CLOSING 状态,如何处理?
出现大量 CLOSING 状态,基本上业务上要处理的逻辑过多,导致一直在 CLOSING 状态;可以使用异步,将网络层和业务层分离,单独处理。
(5)四次挥手中,为什么存在 TIME_WAIT 状态?
防止没有 LAST_ACK 或 LAST_ACK 丢失,导致一直重发已经不存在的 socket。
总结
需要掌握 TCP 三次握手和四次挥手的过程,熟悉 TCP 状态转换。清楚什么是 SYN 包和 ACK 包。
(1)三次握手是 由客户端发起 SYN,服务端收到 SYN 后发送 SYN 和 ACK,客户端回复 ACK;完成连接的建立。
(2)断开连接主要有主动断开和被动断开。
(3)四次挥手是 由发起方调用 close (),同时发送 FIN 包;接收端接收到 FIN 包返回 ACK 包,接收端发送 FIN 包;发起方接收到 FIN 包返回 ACK 包;完成断开。
(4)理解 TCP 的状态转换图。LISTEN 状态到 SYN_RCVD 状态和 SYN_SEND 状态,如何进入 ESTABLISHED 状态;四次挥手 FIN_WAIT_1、FIN_WAIT_2、TIME_WAIT、CLOSING 直接的转换,CLOSE_WAIT 和 LAST_ACK 的处理等。
(5)理解 API 的底层原理,以及全连接队列和半连接队列。
(6)TCP 的分包场景以及 TCP 粘包的处理方式。
TCP 通信完整过程:
END
点这里 ↓↓↓ 记得 关注✔ 标星⭐ 哦
微信扫码关注该文公众号作者