很急,我有一个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.   

    是跨网段,确实带有防火墙 和经过N层路由,现在可以肯定应该不是程序的问题,我们在发环境下测过了,并且之前部署到生产环境都是好的,从路由表上看,很奇怪访问上服务器的ip 即然不经过了网关,这是为什么那位能解析一下,谢
      

  2.   

    【2010-01-23 21:21:14】【系统接收】CMPP_ACTIVE_TEST_RESP
    【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服务器传过来的数据,丢失..
      

  3.   

    即使是timeout了,你也会接收到异常呀,TCP怎么会不声不响的给你传错数据了呢。
      

  4.   

    发送和接收不一致这种情况应该很少发生啊
    而你traceroute 的结果并没有看出有什么问题,2 和 10 全是*不一定代表丢失,也可能只是该机器禁止了ping返回(traceroute是依赖ping的)
      

  5.   

    我有个猜测,不一定对,仅供参考。在发送大消息包时,可能一次没能发完整个包,而在发送消息的这端又没有继续发剩下的消息包。比方说,一次发10K的包,因为发送的缓存没空间了,结果只发了5K,但是发送端没有检查究竟发了多少,接着发下一个包,这样就会出问题。原来在同个网段,发送的时间短,相对而言一次能发送更多的数据。换个网段后发送时间长导致一次能发的数据量减少。这样可以解释为什么发小包没问题,发大包有问题,也能解释为什么原来同网段的时候发大包没问题,换网段后发大包就只能收一截。建议查一下SEND的返回值,看发包的时候是不是真的整个包都发出去了。
      

  6.   

    我把内部路由器去掉,直接通过cisco交换机连接上级路由,还是数据不完整。用cmpp模拟发送过来的数也出是一样的情况。我做了一下测试cmpp模拟服务器与cmpp客户端同在一个局域网时没发现数据不完整的情况。情事情.....
      

  7.   

    cmpp客户端的代码肯定没问题,因为之前是好的
      

  8.   

    对数据完整性做校验(比如CRC之类的),如果不完整就让服务器再重发。一直收到完整为止。
      

  9.   

    我现在在机房里,已证明不是网络问题,因为我用笔记本运行cmpp客户端已正常收发数据,但在服务器(linux)中运行cmpp客户端时仍然出现数据不完整的问题,郁闷中。在我们的redhat linux 5.2服务中有什么西能程序socket包的数据改了呢?
      

  10.   

    可以考虑用mina来负责底层网络传输。
      

  11.   

    怪事情,同样的网络环境,同样的程序,一台是windows的笔记本电脑,一台是linux的服务器,为什么在linux服务中读socket的数据不完整呢,怪,问题会出在那?大家帮忙一下....
      

  12.   

    谈一下我个人的理解。
    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)操作系统的接收缓冲区的大小,调大一些。验证我上面说的是否是在胡说,可以通过安装一些操作系统的抓包工具进行校验,不过,看这些二进制的东西是很头疼的一件事情,如果接收端的程序再接收到半包的时候,么有停下,还能等到后面的数据也接收的话,抓包工具没问题能检测出来,发送方发送的是完整的数据。
      

  13.   

    丢包丢到郁闷,有没有人用mina的?