博客园  :: 首页  :: 新随笔  :: 管理

2.2.1 posix api 接口原理与网络状态

Posted on 2023-03-08 04:22  wsg_blog  阅读(143)  评论(0编辑  收藏  举报

Linux C/C++服务器

Posix API接口原理与网络状态

整理网络相关的各个状态和相关接口的工作原理

  • tcp建立连接
  • tcp数据传输
  • tcp断开连接

网络api接口
客户端接口:socket()、bind()、connect()、send()、recv()、close()
服务端接口:socket()、bind()、listen()、accept()、recv()、send()、close()、epoll()

tcp状态迁移图

tcp建立连接

三次握手

三次握手是协议栈帮忙实现的,不需要业务端写代码,发生在客户端connect()与服务端listen()、accept()的过程中

  1. 第一次握手,客户端第一次发出syn数据包,SYN状态位置为1,Sequence Number=12345(随机生成),第一次握手后服务端会生成Syn队列(半连接队列)
  2. 第二次握手,服务器收到后回一个确认消息即ACK,ACK状态位置为1,Acknowledgment Number= 12346(Sequence Number+1)和一个SYN数据包
  3. 第三次握手,客户端收到服务器发来的SYN数据后再发送一个ACK确认数据,数据无误后建立tcp连接,第三次握手后服务端会生成Accept队列(全连接队列)

listen(listenfd, backlog);
1.backlog 一般指全连接队列的总数(不同版本不同)
accept();
accept接口会去全连接队列中取数据

tcp数据传输

在send和recv数据传输的过程中,tcp处于ESTABLISHED状态

send返回正数,就发送成功了吗?

不一定,send只是把数据拷贝到内核发送缓冲区,同样recv只是把内核网络协议栈中数据拷贝出来
如果想知道send是否发送成功,需要业务层加上ACK的确认机制

tcp粘包

连续发送的数据包在recv接收端可能存在粘包的问题,即buffer中两条数据合并为一条

  • 在应用层协议头前面 加上 pktlen 包的长度
while(count < tcphdr->length){
  size = read(tcphdr->length - count);
  count += size;
}
  • 为每一个包加上分隔符 "/r/n"
buffer *pkt = new buffer();
read(buffer, 1024);
for(){
  if(buffer[idx] == "/r/n"){
    pkt = &buffer[idx+2];
  }
}

tcp断开连接

close(),连接断开不分客户端和服务端,只分主动和被动,close只是发送FIN包,并不会立即断开,需要等四次挥手结束

四次挥手

  1. 第一次挥手:主动断开方调用close()接口,向另一方(被动断开方)发送状态码FIN=1,Sequence Number=x数据包,并进入FIN-WAIT-1状态
  2. 第二次挥手:被动断开方收到FIN数据包回复状态码ACK=1,Sequence Number=y,Acknowledgment Numbe=x+1数据包,并进入CLOSE_WAIT状态,另一方收到ACK包进入FIN-WAIT-2状态
  3. 第三次挥手:被动断开方调用close()接口,向另一方(主动断开放)发送状态码FIN=1,ACK=1,Sequence Number=z,Acknowledgment Numbe=x+1数据包,并进入LAST-ACK状态
  4. 第四次挥手:主动断开方收到FIN-ACK数据包,回复ACK=1,Sequence Number=x+1, Acknowledgment Numbe=z+1,并进入
    主动断开方状态:FIN_WAIT_1、FIN_WAIT_2、TIME_WAIT
    被动断开方状态:CLOSE_WAIT、LAST_ACK
  • 大量的CLOSE_WAIT?

recv()返回0,但没有及时调用close()

  • 为什么TIME_WAIT为2MSL超时

在Client发送出最后的ACK回复,但该ACK可能丢失。Server如果没有收到ACK,将不断重复发送FIN片段。所以Client不能立即关闭,它必须确认Server接收到了该ACK。Client会在发送出ACK之后进入到TIME_WAIT状态。Client会设置一个计时器,等待2MSL的时间。如果在该时间内再次收到FIN,那么Client会重发ACK并再次等待2MSL。所谓的2MSL是两倍的MSL(Maximum Segment Lifetime)。MSL指一个片段在网络中最大的存活时间,2MSL就是一个发送和一个回复所需的最大时间。如果直到2MSL,Client都没有再次收到FIN,那么Client推断ACK已经被成功接收,则结束TCP连接。

心跳检测