发送大数据时,PDU的问题?

昨天发现通过 Ice发送请求传递一个大块数据时,当请求的体积大于1.2M后,直接抛出异常Connection Lost,对方peer或是断开了。通过防火墙配置排查,以及对同一网络同一机器的php服务post大于1.2M的请求没问题,排除了服务机器上的防火墙。剩下就是跟踪抓包了。

我的开发环境是 VMWare 12 上运行Centos 7,VM使用NAT桥接到主机的网络,作为开发的服务器。

我用 Ice接口分别发送 8M数据块 和 80K,以及 800K数据块的请求。8M数据块的请求失败,80K和800K数据块的请求成功了。在请求 8M数据块的情况时,连接果然断开了,收到了服务器peer发来的RST。

先看 8M数据块的请求的抓包:

请求的第一个 Segment, 开始于 seq=123, len=21888, ack=107,声明下一个 Segment的 seq=22011

服务器对第一个 Segment 进行了 Ack, seq关联分段过来的ack 107, ack关联分段过来的下一seq 22011

跟着是请求的第二个 Segment

然后服务器的 socket就回应了重置 RST, ack关联不上,并且发来了重置标志 RST

 

80K 数据块的情况是,小于 MSS,可以通过一个分段进行发送。

 

800K 数据块的情况,大于 MSS,需要通过多个分段进行发送。

 

 

从上面的几个图可以看到,抓包器并没有完全抓到所有的 Segment,出现了很多的 [TCP ACKed unseen segment],而实际上这只是抓包器统计分析给出的判断。所以回到最上面发送 8M数据块的情况,服务器向请求方发出RST并不是 [TCP ACKed unseen segment],它们之间不存在因果关系。

 

下面我用python再通过 TCP 直接发送 8M数据块,一切正常。

中途接收窗口为0, 因为我还没有在接收端进行recv读缓冲的操作,发送端一直向接收端询问窗口是否发生改变,直到最后接收端发来了窗口更新的通知

由于我在接收端从缓冲中读出了数据,接收窗口更新,发送端继续发送数据

现在接收端在同步读缓冲区,双方的MSS也发生了改变?增大到了 65534

整个过程,接收端并没有向发送端发出重置RST。

 

其实发出重置RST的一方,很有可能是提早强制关闭了连接,(不同于FIN的四次握手,不必等待发送缓冲发送完,RST发出后也不必等待对方回应就可以马上结束连接)。换句话说,就是服务器使用的中间件 ZeroC Ice提早结束了连接。通过打开中间件的网络跟踪选项,日志果然出现了连接关闭的记录,协议抛出异常,原因是中间件默认消息数据量上限是1M。

 

今次这个问题大费周折去排查,原因是将中间件的TraceLogger指向到了文件,stderr也重定向到文件,没能迅速及时观察到异常信息。

使用中间件,并不意味事件就变简单了,后面还不得不逐一面对中间件所带来的问题。虽然ZeroC Ice号称跨平台,但在某些平台上却不能如你所愿地进行。对于sequence<byte>在其它平台都默认映射为最优的容器,唯独的php平台,它映射为整形的数组,当我使用ZeroC Ice的php接口发送 8M的数据时,php日志记录下警告要分配134M内存。

 

wiki中的PDU,本文的PDU发生在传输层,也就是 segment for TCP。

OSI model[edit]

PDUs are relevant in relation to each of the first 4 layers of the OSI model as follows:[2]

Given a context pertaining to a specific OSI layer, PDU is sometimes used as a synonym for its representation at that layer.

posted on 2018-01-09 14:27  bbqz007  阅读(1051)  评论(0编辑  收藏  举报