很急,我有一个socket客户端专门接收另一个服务器端进行通信,当接收一个大的包时,服务器端发出的数据和接收的数据不匹配。原来是好的,客户端换了一个机房后出现这个问题,请求大家帮忙一下,有谁遇到过这种情况?这是 traceroute <服务器ip> 输出的结果
1 192.168.0.1 (192.168.0.1) 9.362 ms 10.738 ms 11.645 ms
2 * * *
3 221.130.164.53 (221.130.164.53) 4.702 ms 5.436 ms 6.411 ms
4 221.130.164.50 (221.130.164.50) 11.882 ms 12.189 ms 12.457 ms
5 221.130.164.45 (221.130.164.45) 7.344 ms 8.048 ms 14.875 ms
6 221.130.164.34 (221.130.164.34) 12.674 ms 8.339 ms 7.916 ms
7 221.130.174.142 (221.130.174.142) 7.213 ms 6.907 ms 6.513 ms
8 211.138.178.18 (211.138.178.18) 6.118 ms 7.410 ms 8.086 ms
9 211.138.183.190 (211.138.183.190) 4.227 ms 4.940 ms 6.649 ms
10 * * *
1 192.168.0.1 (192.168.0.1) 9.362 ms 10.738 ms 11.645 ms
2 * * *
3 221.130.164.53 (221.130.164.53) 4.702 ms 5.436 ms 6.411 ms
4 221.130.164.50 (221.130.164.50) 11.882 ms 12.189 ms 12.457 ms
5 221.130.164.45 (221.130.164.45) 7.344 ms 8.048 ms 14.875 ms
6 221.130.164.34 (221.130.164.34) 12.674 ms 8.339 ms 7.916 ms
7 221.130.174.142 (221.130.174.142) 7.213 ms 6.907 ms 6.513 ms
8 211.138.178.18 (211.138.178.18) 6.118 ms 7.410 ms 8.086 ms
9 211.138.183.190 (211.138.183.190) 4.227 ms 4.940 ms 6.649 ms
10 * * *
【2010-01-23 21:21:15】【系统接收】
00 00 00 C7 00 00 00 05 00 42 30 52 1B D5 55 40
D7 3D 24 4F 31 30 36 35 38 33 38 38 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 接收cmpp服务器传过来的数据,丢失..
而你traceroute 的结果并没有看出有什么问题,2 和 10 全是*不一定代表丢失,也可能只是该机器禁止了ping返回(traceroute是依赖ping的)
CMPP协议,是建立在TCP协议基础上的,所以,网络上程序传输的数据包,不会出现半包,残包的现象。
因为,TCP是有连接,且可靠的。
楼主给出的是半包现象,就是说,只收到了一半的包。这样可以排除网络原因,因为,TCP通信,要么不通,要通就不会丢失数据(当然,断网会抛出异常,我指的是无IO异常的情况下)。
当然,楼主在32楼已经排除了网络情况。有个共识,需要先提出一下,就是,我们传输的数据包,实际上在传输的时候,会被操作系统拆分成很多个小的报文在网络设备之间传递,然后到达目的地后,接收端的操作系统会创建接收缓冲区,将这些小的报文重新还原成应传输的数据包。根据我的经验来判断,问题应该出现在应用程序本身上。
当然,我后面说的不一定就是绝对正确的,因为,楼主说的信息,我就只能想到这些,请达人们,就先别骂我了。
我们知道Socket编程,在读取IO信息的时候,是可以通过两种方式来读取的,一种是阻塞读、另一种是非阻塞读。
什么意思?就是说,对方向我们发送数据,会先由操作系统暂时存放到一个系统的接收缓冲区里面,我们程序在调用read方法读取时,其实是读取系统的接收缓冲区当中的数据。
举个例子:比如对方向我们发送128byte数据,目前系统接收缓冲区只收到32byte数据,后面的数据一会就到。在这个时候,我们调用read方法读取64byte数据时,如果采用的是阻塞读方式,那么程序会被阻塞(暂时停止)直到接收缓冲区中收到足够64byte的数据,然后才执行后面的代码;但若是非阻塞读方式的话,read方法会立即返回当前接收缓冲区中的32byte数据,并告知你只读取了32byte数据,这样,你要自己编写程序最终读够64byte数据,来达到你的最终目的。说了这么多,其实,也就是想说:你的客户端程序,在接收数据的时候,是一个字节一个字节的接收的。这个时候,有个特殊情况,就是当系统的接收缓冲区中已经被程序读空了(后面的数据一会就到),你再调用read方法,它返回的就是'\0'这个字节了。换句话说,就是一个字节一个字节的读取方法(read),并不能确定当前系统接收缓冲区中是否填有数据。Java提供了另一个方法,可以获得当前系统接收缓冲区中数据的多少。采用一个字节一个字节的读取数据,应该先判断系统接收缓冲区中是否填有数据,然后再读取想要的数据。为什么换个机房就丢信息了呢?这个很好解释,同在一个局域网中,数据的传输速度(注意不是速率)要快很多,因为,从对方到本计算机之间最多就有一两个中转设备,那么,数据包的延迟就会非常小。也就是说,对方调用flush方法的瞬间,你的系统接收缓冲区就已经收到的所有的本次的数据,这样程序一个字节一个字节的读,就能读出一个完整的数据包。
换到其他机房,中间的中转设备就多了,操作系统接收的报文,就会有个一个较大的延迟了,这样,接收缓冲区的数据就会存在半包的状况(实际上,你让程序等到缓冲区中有个完整包的数据时再读就可以避免读半包的了),这时候,你一个字节一个字节的读取缓冲区的数据,就会有半包的现象了。
改进方案:楼主找编程的人员修改程序,让程序先判断系统接收缓冲区的状况,再进行读取,这样就可以避免楼主说的奇怪问题了。实际上,如果楼主有办法让程序在读取数据包前等上一两秒(网络状况差的话等上五六秒),然后在读,肯定就没有这个怪问题了。为什么同一种操作系统没这问题,换个操作系统(不同操作系统之间)就会出现这个怪问题 ?
这个原因很简单,一想就明白,不同操作系统,数据的接收缓冲区大小不同呗。
打个比方(真实情况可能不是这样滴):如果你要发的数据包是128Kbyte,人家接收方默认的系统缓冲区大小就是32Kbyte,除非你的程序要显示的一次读取128K的数据,否则,一个字节一个字节的读取接收缓冲区的数据,总会出现当前读完缓冲区的数据后面的数据还没填入的情况。然后,后面再读,就是一串'\0'字节的情况了。根本上解决这个问题,就是要从程序上着手,协议绝对没有问题,问题在于程序员的理论知识、编程经验、相关API的使用等方面有所欠缺,解决这个问题,也是增长经验的一个过程。
当然,如果想糊弄过去的话,倒是可以考虑一个治标不治本的方法(当然,这个方法不一定能解决楼主的怪问题),就是想办法修改接收方(linux)操作系统的接收缓冲区的大小,调大一些。验证我上面说的是否是在胡说,可以通过安装一些操作系统的抓包工具进行校验,不过,看这些二进制的东西是很头疼的一件事情,如果接收端的程序再接收到半包的时候,么有停下,还能等到后面的数据也接收的话,抓包工具没问题能检测出来,发送方发送的是完整的数据。