13解决TCP粘包缺包问题

一、粘包现象出现

a)客户端粘包现象
---- 客户端因为有一个Nagle优化算法要是有三个数据包,则他们可能会被Nagle优化算法直接合并一个数据包发送出去
b)服务器端粘包现象
---- 服务器端两次 recv之间可能间隔100毫秒,那可能在这100毫秒内,客户端这三个包都到了,这三个包都被保存到了服务器端的 针对该TCP连接收数据的 缓冲(区)中。
c)缺包
---- send("abc......."); //8000字节;这个可能被客户端拆成6个包发送出去了;但是网络可能出现延迟或者阻塞,多次才能接收完,服务器端第一次recv() = "ab",recv = "c...",recv.........,recv() = ".....de".... [缺包]

二、解决办法

如何解决拆包问题:给收发的数据包定义一个统一的格式[规则];c/s都按照这个格式来,就能够解决粘包问题;
包格式: 包头+包体 的格式;
其中 包头 是固定长度【10字节】,在包头中,有一个成员变量会记录整个包【包头+包体】的长度;
这样的话,先收包头,从包头中,我知道了整个包的长度,然后 用整个包的长度 - 10个字节 = 包体的长度。
我再收 “包体的长度”这么多的字节; 收满了包体的长度字节数,我就认为,一个完整的数据包【包头+包体】收完;

三、程序设计

3.1准备

这里我们是以LT的模式进行读取的。所以我们读取缓冲区的数据,一直读到其为空。
ssize_t reco = recvproc(c,c->precvbuf,c->irecvlen);
reco的意义是:读取了这么多。
读取的数据一直保存在c->precvbuf的位置,在缓冲区是以追加的模式保存。c是全局的。

要是以ET模式进行读取,该怎么读取?查看上一随笔的内容。

在处理一个TCP连接的时候,要是连接的缓冲区中有数据,那么epool_wait()会把里面的数据读取出来,读取的过程中,我们一开始的时候并不知道读取的是一个包,还是几个包,还是半个包,只有通过读取里面的数据才能知道。
-------------------------------------------------------
下面在读一个包的过程中,包有五个代表位置可能被截断出来。定义读取包的状态。
image
包:
-----------------包头-----------+--------------包体-----------------|
--^-----------------^------------^-------------^--------------------^

在收完了包头,我们需要为整个数据包加上消息头。
加上消息头的目的是为了标记这个消息有没有过期,还是不是原来的连接,用于处理过期事件,和标记这个消息是属于那个对象连接,方便之后收发数据。

3.2程序流程

\------------------------------------------------------------------
ngx_wait_request_handler()
\------------------------------------------------------------------
\----c->curStat == \_PKG_HD_INIT(接收包头开始阶段)
\----recvproc(c,c->precvbuf,c->irecvlen)
\----c->curStat == \_PKG_HD_RECVING(接收包头中阶段)
\--------中间可能多次进入接收包头recvproc(c,c->precvbuf,c->irecvlen)
\--------ngx_wait_request_handler_proc_p1(c);
\------------c->curStat = \_PKG_BD_INIT;(接收包体开始)
\-------------------------------------------------------------------
\----recvproc(c,c->precvbuf,c->irecvlen)
\----c->curStat == \_PKG_BD_RECVING(接收包体中阶段)
\--------中间可能多次进入接收包体recvproc(c,c->precvbuf,c->irecvlen)
\--------ngx_wait_request_handler_proc_plast(c);
\------------c->curStat == \_PKG_HD_INIT(接收包头开始下一阶段)
\-------------------------------------------------------------------

3.3具体函数

ngx_wait_request_handler_proc_p1(c);包头收完整后的处理
----1.解析包头数据
----2.加消息头

ngx_wait_request_handler_proc_plast(c);收到一个完整包后的处理
----1.将整个(一条)数据包(内存)加入消息队列中
--------inMsgRecvQueue(c->pnewMemPointer);

posted @   豪崽_ZH  阅读(146)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
点击右上角即可分享
微信分享提示