程序中继承的CSocket
长连接  TCP协议
不定长包  3个字节  2个字节   4个字节   6个字节的都有char *buff=new char[32];
memset(buff,0,sizeof(buff));
MySock.Receive(buff,sizeof(buff));接收完后,跟踪程序,发现buff 的数据为  0x004a14c0 "s屯屯屯屯"
前半部分 "s" 是正常接收到的数据。
后面的"屯屯屯屯"是怎么回事呢? 
 
运行抓包软件发现包的发送是正常的,但很多包粘在一起了。
但是Receive接收到的却是上面那样的数据。真是奇怪啊!

解决方案 »

  1.   

    回:PiggyXP(【小猪】●你快乐于是我快乐) 粘包问题:就是若干个包头尾相连接在一起发送出去,如两个4bytes的包连接成一个8bytes的包了。而不是分别一个包一个包发送的。这在Socket通信数据量大时会发生。主要是由于Socket要等发送缓冲区满了才发送,以提高效率。
      

  2.   

    很奇怪的是抓包发现有很多包是粘在一起的。而且所有的包都是完整的。
    而在VC++的QuickWatch里调试跟踪的时候发现buff里收到的包却都是单个的,但有些包不完整(如:只有一个包头),而且接收到的数据有部分是上面所说的情况:0x004a14c0 "s屯屯屯屯" 收到了一些垃圾数据!而并不见粘在一起的包。把接收缓冲区开大一些如 char *buff=new char[256];
    跟踪调试时可以看到buff里这样的数据:"s屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯s屯屯屯屯"
      

  3.   

    我想应该是send代码的问题你说的“屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯”一般在字符串里面的值没有被初始化或为空的时候就是这样
      

  4.   

    Send代码没有问题吧
    我抓包看到的数据都是正常的啊!
    接收端接收前也清空了接收缓冲区的(如上面的代码)
    不知道那些"屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯"是怎么收到的。请PiggyXP指教。
      

  5.   

    :"s屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯s屯屯屯屯"这里,空白以后的第二个s是第二个数据包里的内容吗?
      

  6.   

    "屯屯屯屯屯"啥也不是,你要是接收之前来一个memset(buf,0,sizeof(buf));就知道了。
      

  7.   

    第二个"s"是包的内容我的包有长度标志,第1个字节表示包的种类,第一个字节表示包的长度。
    这样接收吗?MySock.Receive(buff,buff[1]);
    我这样试了。接收不到数据。
    而且这样也不能解决粘包的问题啊!
    况且接收时还要收到"屯屯屯屯屯屯屯屯屯屯屯"的垃圾数据。明天就要交客户了!我完了…………******************************************************8
    下面是我查的关于粘包问题的资料TCP粘包是指发送方发送的若干包数据到接收方接收时粘成一包,从接收缓冲区看,后一包数据的头紧接着前一包数据的尾。 
    出现粘包现象的原因是多方面的,它既可能由发送方造成,也可能由接收方造成。发送方引起的粘包是由TCP协议本身造成的,TCP为提高传输效率,发送方往往要收集到足够多的数据后才发送一包数据。若连续几次发送的数据都很少,通常TCP会根据优化算法把这些数据合成一包后一次发送出去,这样接收方就收到了粘包数据。接收方引起的粘包是由于接收方用户进程不及时接收数据,从而导致粘包现象。这是因为接收方先把收到的数据放在系统接收缓冲区,用户进程从该缓冲区取数据,若下一包数据到达时前一包数据尚未被用户进程取走,则下一包数据放到系统接收缓冲区时就接到前一包数据之后,而用户进程根据预先设定的缓冲区大小从系统接收缓冲区取数据,这样就一次取到了多包数据。
    粘包情况有两种,一种是粘在一起的包都是完整的数据包,另一种情况是粘在一起的包有不完整的包。
      

  8.   

    那肯定是你接收数据的代码有问题啊既然你定义了包的种类和长度,就最好先把长度读出来然后根据长度来new 缓冲区,然后接收MySock.Receive(buff,buff[1]);你那样编码的话“屯屯屯屯屯屯屯屯屯屯屯”是很正常的,因为这些位置都是没有数据的啊,并非是垃圾数据,而是空的,什么都没有^_^
      

  9.   

    呵呵,牛人们都在深圳啊你把receive的代码贴一下,我帮你看看楼主不用着急,就是一个小问题而已,给你弄好了我再吃饭吧呵呵^_^
      

  10.   

    晕啊,我才看到,你怎么能这么写呢MySock.Receive(buff,buff[1]);应该是MySock.Receive(buff,1);才对啊呵呵,先收到数据包头得到下面数据的长度,然后再读取固定长度的就好了
      

  11.   

    CSocket是阻塞式的。它可以自动避免粘包问题吗?我的程序主要的问题是大数据量的时候要丢包!而问题的原因我认为就是粘包了
      

  12.   

    呵呵,一般来说如果你传输的数据报不是定长的,应该采用下面这种格式发送数据。
    int buflen = sizeof(buf);
    send(buflen, 4);
    send(buf, buflen);
    即先发送缓冲长度,再发送缓冲的数据。在接收方先接收长度
    int buflen;
    recv(&buflen, 4);
    得到长度后再接收真正的数据
    recv(buf, buflen);呵呵,其实 PiggyXP 都说了,我只是补充而已 ^_^
      

  13.   

    发送方是不能改的了。因为发送方是放在很多硬件里的运行在VxWorks嵌入式OS下。而我修改了接收部分
    /*****************************
    int len=0;
    char tempbuf[2];//第0个bytes为包的种类,第1个bytes为包的长度
    memset(tempbuf,0,sizeof(tempbuf));
    MySock.Receive(tempbuf,sizeof(tempbuf));
    len=tempbuf[1];//获得包的长度
    char *buff=new char[len];//按照长度分配空间
    memset(buff,0,sizeof(buff));
    MySock.Receive(buff,sizeof(buff));
    ****************************************/
    跟踪调试发现由于tempbuf第一次接收把包的前半部分接收了,buff只接收到了包的后半部分。
    len能正确获得包的长度。
    我把tempbuf的数据和buff的数据连接起来发现与接收的数据不正确。
    有,没有办法让tempbuf接收后数据仍然在缓冲区里。
    然后用buff就能正确接收
      

  14.   

    QuickWatch显示;
    tempbuf接收到的数据 "w烫" 
    buff接收到的数据""
    连接起来就是 "w烫"而正确的应该是 "w"如果按下面的代码来接收在通信数据量小时可以得到正确结果
    char *buff=new char[32];
    memset(buff,0sizeof(Buff));
    MySock.Receive(buff,sizeof(buff));
    但是如果Socket数据量大时就会有上面的问题。郁闷啊!!
      

  15.   

    memset(buff,0,sizeof(Buff));
    这句话有问题,你的意思本来是想将buff指向的32byte的位置全部置0,但是由于buff是个指针变量,所以sizeof(Buff)的值是4(一个指针变量的大小),所以你实际上只将buff指向的4byte的位置置为了0,而4byte之后的值这时仍为未知的,也就是你所看到的“屯”。你改为strlen就应该对了
      

  16.   

    哦,想起来了,由于你这时buff里面都是未知值,所以改成strlen也不对,就直接将sizeof(Buff)改成32就对了。
      

  17.   

    回 ffantasyYD(风之子):
    memset(buff,0,sizeof(buff)) 没有任何问题,这是完全正确的。
      

  18.   

    /*****************************
    int len=0;
    char tempbuf[2];//第0个bytes为包的种类,第1个bytes为包的长度
    memset(tempbuf,0,sizeof(tempbuf));
    MySock.Receive(tempbuf,sizeof(tempbuf));
    len=tempbuf[1];//获得包的长度
    char *buff=new char[len];//按照长度分配空间
    memset(buff,0,sizeof(buff));
    MySock.Receive(buff,sizeof(buff));
    ****************************************/既然已经知道了包的长度len,那在最后俩行程序中直接用len代替sizeof(buff)
    这样行不行呢?
      

  19.   

    别用char类型,用BYTE一样的,用BYTE有一个好处,在你打包的时候如果数据中包含‘\0’那么你在获取数据长度的时候就会返回错误!用BYTE可以避免这个问题,在你接收数据的时候同样可以避免这个问题,这个时候你只要有个校验和,或者数据包长度,就可以避免你遇到的问题了
      

  20.   


    楼主为什么要这样呢?
    memset(buff,0,sizeof(buff));
    MySock.Receive(buff,sizeof(buff));直接这样不就完了末?memset(buff,0,len);
    MySock.Receive(buff,len);但是因为你的发送端代码不能修改了
    那就只能你自己手动把两部分拼接起来了呵呵buff只能收到后半部分了^_^
      

  21.   

    to alec626(月吻长河) :
    memset(buff,0,sizeof(buff)) 真的没有问题吗?那么请你运行下面程序段进行试验:
    char *buff=new char[32];
    //    memset(buff,0,sizeof(buff));
    printf("%d\n",sizeof(buff));我使用vc6.0编译运行,打印出来的结果是4,而不是32。除非你原本就只是想将4个字节置0而不是32字节,否则这里就有问题。