socket接包切数据时遇到的诡异问题

最近在写一个socket方面的小程序,遇见一个我个人觉得很诡异问题。
客户端发包我用php写的,代码很简单并且我也测试过,没有任何问题,我就不贴出来献丑了,调用接口为:
function send($socket, $data)
$data参数就是php客户端要发送给服务器的数据,这个send函数会把数据切割成一个一个的片段,并给每个片段增加协议头,然后调用socket_write发送给服务器。

服务器程序用c++写的,一个简单的测试代码,功能是:连接好socket后,先尝试接收固定长度的数据,这个数据就是协议头,从协议头中取出给定好的数据长度和数字签名,然后按照数据长度获取数据,拿到数据后再和数字签名比对看看是否合法,若合法则表明本次收包没问题,接续接受下一个包。。。。

整个流程很简单,下面我贴一下我写的c++代码:


       
       
  1. /**
  2.  * receive the data from the socket
  3.  *
  4.  * protocol format: [flag(1) | size(4) | md5(32) | data(size) ]
  5.  *
  6.  * @param socket
  7.  * @param data
  8.  */
  9. int Receive(int socket, std::string *data)
  10. {
  11.     while(1)
  12.     {
  13.         //first, get the protocol header
  14.         int total = HEADERSIZE;
  15.         char header[HEADERSIZE] = {'0'};
  16.         int howMany = 0;
  17.         while(total > 0)
  18.         {
  19.             howMany = read(socket, header + howMany, total);
  20.             if(howMany < 0)
  21.                 return -1;
  22.             total -= howMany;
  23.         }
  24.         //verify the flah
  25.         if('M' != header[0])
  26.             return -2;
  27.         //get the data size
  28.         char tmpLength[4];
  29.         strncpy(tmpLength, header+1, 4);
  30.         int length = atoi(tmpLength);
  31.         if(length <= 0)
  32.             return length;  //if the length < 0, means something wrong happen, or if the length = 0, means the data finish.
  33.         //get the data
  34.         char buffer[length];
  35.         //memset(buffer, '0', length);
  36.         howMany = 0;
  37.         while(length > 0)
  38.         {
  39.             howMany = read(socket, buffer + howMany, length);
  40.             if(howMany < 0)
  41.                 return -1;
  42.             length -= howMany;
  43.         }
  44.         //verify the data
  45.         std::string onePart(buffer);
  46.         MD5 md5(onePart);
  47.         std::string verification(md5.md5());
  48.         if(verification.compare(0, 32, header + 5, 32) != 0)
  49.             return -3;
  50.         //merge the part of data
  51.         data->append(onePart);
  52.     }
  53.     std::cout << std::endl;   //i really fucking do not know why must do this code .
  54.     return 0;
  55. }

注意看send方法的倒数第二行,我不明白为什么去掉这行,这个函数就会见鬼的在第二次(第一次竟ok)被调用时,return -3(也就是说没有通过签名验证),我排查了好久,发现只有我在为debug而增加打印代码的时候才会ok,去掉所有打印代码就又出现-3。这让我有点抓狂!最后发现只要增加个std::endl,好像就没问题了,这个std::endl是有着刷新缓冲区的作用(在记忆中有看到过),谁能来给我讲讲其中奥妙呢?

由于问题太诡异,没看明白我的描述的,可以跟帖留言,我是真心求解,不是来搞笑的,谢谢~

PS:顺便问问,c++字符串截取时,有时候最后一个字符会是007F,是为啥?我有截图:

请输入图片描述

补一下我的测试环境:
centOS6.3 x86_64

评论 (2) •   •  链接 •  2013-03-25 
  • 0
    现在能确定的是肯定是输出缓冲区的问题,但是不知道问题的本质是什么,我把倒数第二行改成:std::flush(std::cout); 也可以让程序正常,那么,为什么非要这么做才行呢? –  kazaff  2013-03-25
  • 0
    经过排查呢,我发现read()(也就是第43行)在调用后,可能返回的值(表示实际读取的长度)可能大于你设置的第三个参数(也就是应读取长度),糙了!我在第51行后面增加onePart = onePart.substr(0,length);(意思为把获取的内容只保留指定长度的内容),一切正常了,不管我怎么更改每个包的大小,都没问题,也不需要更新缓冲区了,阿西吧,tell me y?!!!
    发贴一下新的代码在答案里,让希望大家帮助我答疑
     –  kazaff  2013-03-25
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值