一、粘包现象出现
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()会把里面的数据读取出来,读取的过程中,我们一开始的时候并不知道读取的是一个包,还是几个包,还是半个包,只有通过读取里面的数据才能知道。
-------------------------------------------------------
下面在读一个包的过程中,包有五个代表位置可能被截断出来。定义读取包的状态。

包:
-----------------包头-----------+--------------包体-----------------|
--^-----------------^------------^-------------^--------------------^
在收完了包头,我们需要为整个数据包加上消息头。
加上消息头的目的是为了标记这个消息有没有过期,还是不是原来的连接,用于处理过期事件,和标记这个消息是属于那个对象连接,方便之后收发数据。
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);
















