bsd socket 接收缓冲长度不够时接收出错的问题

yang3wei 2013-07-24 09:57:27
协议在底层接收了一段长度为 1.5k (单位为byte)的数据
缓冲大小设置为 1k 分两次用 recv() copy 出来的时候,得到如下的数据(数据出现了错误,而且仅仅是一个字节出现了错误!!)

08121204626F73731A6*0973686F77206D6520746865206D6F6E65792C646677657765323133313332337273646661736632333266323366323366723332663266323366323364616177663233333433327172657766617364663479343533326531646164736661723233723233723233723272323372333264736166736466323372333272323372663266323366323364616177663233333433327172657766617364663479343533326531646164736661723233723233723233723272323372333264736166736466323372333272323372663266323366323364616177663233333433327172657766617364663479343533326531646164736661723233723233723233723272323372333264736166736466323372333272323372663266323366323364616177663233333433327172657766617364663479343533326531646164736661723233723233723233723272323372333264736166736466323372333272323372663266323366323364616177663233333433327172657766617364663479343533326531646164736661723233723233723233723272323372333264736166736466323372333272323372663266323366323364616177663233333433327172657766617364663479343533326531646164736661723233723233723233723272323372333264736166736466323372333272323372663266323366323364616177663233333433327172657766617364663479343533326531646164736661723233723233723233723272323372333264736166736466323372333272323372663266323366323364616177663233333433327172657766617364663479343533326531646164736661723233723233723233723272323372333264736166736466323372333272323372663266323366323364616177663233333433327172657766617364663479343533326531646164736661723233723233723233723272323372333264736166736466323372333272323372663266323366323364616177663233333433327172657766617364663479343533326531646164736661723233723233723233723272323372333264736166736466323372333272323372663266323366323364616177663233333433327172657766617364663479343533326531646164736661723233723233723233723272323372333264736166736466323372333272323372663266323366323364616177663233333433327172657766617364663479343533326531646164736661723233723233723233723272323372333264736166736466323372333272323372663266323366323364616177663233333433327172657766617364663479343533326531646164736661723233723233723233723272323372333264736166736466323372333272323372663266323366323364616177663233333433327172657766617364663479343533326531646164736661723233723233723233723272323372333264736166736466323372333272323372663266323366323364616177663233333433327172657766617364663479343533326531646164736661723233723233723233723272323372333264736166736466323372333272323372736164666166617766323332337264666173646666323334723331327232337233327266736164666177663266323372663233723332723332723332337233327233327232337232337261
缓冲大小设置为 2k 用 recv() 一次性将所有数据复制出来的时候(此时得到的是正确地数据):
08121204626F73731AE30973686F77206D6520746865206D6F6E65792C646677657765323133313332337273646661736632333266323366323366723332663266323366323364616177663233333433327172657766617364663479343533326531646164736661723233723233723233723272323372333264736166736466323372333272323372663266323366323364616177663233333433327172657766617364663479343533326531646164736661723233723233723233723272323372333264736166736466323372333272323372663266323366323364616177663233333433327172657766617364663479343533326531646164736661723233723233723233723272323372333264736166736466323372333272323372663266323366323364616177663233333433327172657766617364663479343533326531646164736661723233723233723233723272323372333264736166736466323372333272323372663266323366323364616177663233333433327172657766617364663479343533326531646164736661723233723233723233723272323372333264736166736466323372333272323372663266323366323364616177663233333433327172657766617364663479343533326531646164736661723233723233723233723272323372333264736166736466323372333272323372663266323366323364616177663233333433327172657766617364663479343533326531646164736661723233723233723233723272323372333264736166736466323372333272323372663266323366323364616177663233333433327172657766617364663479343533326531646164736661723233723233723233723272323372333264736166736466323372333272323372663266323366323364616177663233333433327172657766617364663479343533326531646164736661723233723233723233723272323372333264736166736466323372333272323372663266323366323364616177663233333433327172657766617364663479343533326531646164736661723233723233723233723272323372333264736166736466323372333272323372663266323366323364616177663233333433327172657766617364663479343533326531646164736661723233723233723233723272323372333264736166736466323372333272323372663266323366323364616177663233333433327172657766617364663479343533326531646164736661723233723233723233723272323372333264736166736466323372333272323372663266323366323364616177663233333433327172657766617364663479343533326531646164736661723233723233723233723272323372333264736166736466323372333272323372663266323366323364616177663233333433327172657766617364663479343533326531646164736661723233723233723233723272323372333264736166736466323372333272323372663266323366323364616177663233333433327172657766617364663479343533326531646164736661723233723233723233723272323372333264736166736466323372333272323372736164666166617766323332337264666173646666323334723331327232337233327266736164666177663266323372663233723332723332723332337233327233327232337232337261
接收相关的代码如下(接收的逻辑是放在子线程里面执行的):
void* RecvBytesThread::execute() {
// printf("RecvBytesThread::execute()\n");

SocketModule* t_pSocketModule = (SocketModule*)m_pSocketModule;
int t_iSocketFd = t_pSocketModule->getSocketFd();

int t_iRemain = 0;
int t_iDataSize = 0;
unsigned char* t_pArrCharFull = NULL;
// 在栈中建立的数组,用于盛放接收来的数据
unsigned char t_oArrCharBuf[BUFFER_SIZE];

do {
memset(t_oArrCharBuf, 0, sizeof(t_oArrCharBuf)); // sizeof(t_oArrayChar) = 1024

int tmp_iRecvLen = (int)::recv(t_iSocketFd, t_oArrCharBuf, sizeof(t_oArrCharBuf), 0);
// 检查网络链接(链接断开返回 0)、数据传输(接收出错返回 -1)是否出错~
if (tmp_iRecvLen <= 0) {
printf("Connection broken or receiving data from server failed!\n");
break;
}

printf("从协议存储中 copy 出了一段长度为 %d 的数据~\n", tmp_iRecvLen);

if (t_iRemain == 0) {
// 表示这是一次从头开始的接收~
t_iDataSize = bytes2int(t_oArrCharBuf);
if (t_iDataSize == tmp_iRecvLen - 4) {
// 发送过来数据规格小于缓冲规格的情况(只需 recv 一次即可执行解码)~
echo(t_oArrCharBuf + 4, t_iDataSize);

} else if (t_iDataSize > tmp_iRecvLen - 4) {
// 发送过来的数据规格大于缓冲规格的情况(需要 recv 多次后才能执行解码)~
t_pArrCharFull = new unsigned char[t_iDataSize]; // sizeof(t_pArrCharFull)
memset(t_pArrCharFull, 0, t_iDataSize);

memcpy(t_pArrCharFull, t_oArrCharBuf + 4, sizeof(t_oArrCharBuf) - 4);
t_iRemain = t_iDataSize - (tmp_iRecvLen - 4);
}
} else {
// 表示这不是一次从头开始的接收~
memcpy(t_pArrCharFull + (t_iDataSize - t_iRemain), t_oArrCharBuf, tmp_iRecvLen);
t_iRemain -= tmp_iRecvLen;
if (t_iRemain == 0) {
// 可以执行解码操作了~
echo(t_pArrCharFull, sizeof(t_pArrCharFull));
// 释放内存~
delete t_pArrCharFull;
t_pArrCharFull = NULL;
}
}

} while (true);

return NULL;
}

坐等高手帮看一下代码的问题出在哪里,提前感谢!
...全文
271 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
yang3wei 2013-07-24
  • 打赏
  • 举报
回复
引用 12 楼 dahuaixiaohuai 的回复:
不会吧,TCP是流式数据。
找到原因了,46行的那个 t_pArrCharFull 是一个指针,这样的话 取出来都是固定的长度 8,所以我在做数据解析的时候会出错。 至于A* 那个,我完全是被那个东西给误导了,那个字节数组转16进制字符串的方法存在问题 (也就是说,实际数据是没有问题的,只不过在转换成字符串的时候出现了错误)。 真心伤不起,看来以后不能过分信赖网上的一些东西啊。。。
yang3wei 2013-07-24
  • 打赏
  • 举报
回复
引用 8 楼 adlay 的回复:
你用什么方式打印的? 怎么会打出 6* 来? 两次不同的地方只有 BUFFER_SIZE 这个宏定义的数值不一样? 难道是你的内存这个地方有个坏点.....
找到原因了,46行的那个 t_pArrCharFull 是一个指针,这样的话 取出来都是固定的长度 8,所以我在做数据解析的时候会出错。 至于A* 那个,我完全是被那个东西给误导了,那个字节数组转16进制字符串的方法存在问题 (也就是说,实际数据是没有问题的,只不过在转换成字符串的时候出现了错误)。 真心伤不起,看来以后不能过分信赖网上的一些东西啊。。。
yang3wei 2013-07-24
  • 打赏
  • 举报
回复
引用 14 楼 adlay 的回复:
[quote=引用 11 楼 yang3wei 的回复:] [quote=引用 9 楼 gpshq 的回复:] 检查一下服务端send之前的内存数据。很好奇6*这个是个什么东西?
服务器端绝对没问题,6* 是因为数据出现错误所致,虽然说这个东西在16进制打印中显得比较诡异。[/quote] 如果你是用 printf("%02X" 这种来打印内存的, 不可能出现 * 哦.[/quote] 恩,不过这个不是问题的重点,除了打印,我还做过其他的验证(事实上我是在做其他验证时发现出错了才想到要打印16进制找问题原因的),数据确实出现错误了
www_adintr_com 2013-07-24
  • 打赏
  • 举报
回复
引用 11 楼 yang3wei 的回复:
[quote=引用 9 楼 gpshq 的回复:] 检查一下服务端send之前的内存数据。很好奇6*这个是个什么东西?
服务器端绝对没问题,6* 是因为数据出现错误所致,虽然说这个东西在16进制打印中显得比较诡异。[/quote] 如果你是用 printf("%02X" 这种来打印内存的, 不可能出现 * 哦.
yang3wei 2013-07-24
  • 打赏
  • 举报
回复
引用 12 楼 dahuaixiaohuai 的回复:
不会吧,TCP是流式数据。
我也觉得不会,但是事实它就试发生了,能帮看一下程序写法上有问题么?
一叶之舟 2013-07-24
  • 打赏
  • 举报
回复
不会吧,TCP是流式数据。
yang3wei 2013-07-24
  • 打赏
  • 举报
回复
引用 9 楼 gpshq 的回复:
检查一下服务端send之前的内存数据。很好奇6*这个是个什么东西?
服务器端绝对没问题,6* 是因为数据出现错误所致,虽然说这个东西在16进制打印中显得比较诡异。
yang3wei 2013-07-24
  • 打赏
  • 举报
回复
引用 8 楼 adlay 的回复:
你用什么方式打印的? 怎么会打出 6* 来? 两次不同的地方只有 BUFFER_SIZE 这个宏定义的数值不一样? 难道是你的内存这个地方有个坏点.....
................ boss 刚给买没几天的mac mini 新机啊,这个不太可能。。。
氰客 2013-07-24
  • 打赏
  • 举报
回复
检查一下服务端send之前的内存数据。很好奇6*这个是个什么东西?
www_adintr_com 2013-07-24
  • 打赏
  • 举报
回复
你用什么方式打印的? 怎么会打出 6* 来? 两次不同的地方只有 BUFFER_SIZE 这个宏定义的数值不一样? 难道是你的内存这个地方有个坏点.....
yang3wei 2013-07-24
  • 打赏
  • 举报
回复
引用 5 楼 adlay 的回复:
在进行组合前查看接收的原始数据呢? 排除下是组合操作产生的问题.
缓冲不够,多 recv 几次竟然会出这种问题,我也是百思不得其解,昨天下午到晚上+今天早上,一直没找到原因。 难道是多次 recv 的时候有什么必须要注意的点(我对 bsd socket 真心太不熟悉)?
yang3wei 2013-07-24
  • 打赏
  • 举报
回复
引用 5 楼 adlay 的回复:
在进行组合前查看接收的原始数据呢? 排除下是组合操作产生的问题.
是在组合前就查看了的,我再 recv 调用的下一行就打印了,可以排除其他操作导致该问题的可能
www_adintr_com 2013-07-24
  • 打赏
  • 举报
回复
在进行组合前查看接收的原始数据呢? 排除下是组合操作产生的问题.
yang3wei 2013-07-24
  • 打赏
  • 举报
回复
引用 1 楼 adlay 的回复:
那个位置是在组合两次 recv 结果的交接点上吗?
对了,我也修改过服务器端发过来的数据内容(大小不变,都是 1.5k),发现出错字节的位置也都是差不多的,比较靠前。
yang3wei 2013-07-24
  • 打赏
  • 举报
回复
引用 1 楼 adlay 的回复:
那个位置是在组合两次 recv 结果的交接点上吗?
这奇葩就奇葩在出错偏偏错在某个特定的字节上,而其他的数据却都是正常的
yang3wei 2013-07-24
  • 打赏
  • 举报
回复
引用 1 楼 adlay 的回复:
那个位置是在组合两次 recv 结果的交接点上吗?
不是,是在第一次接收的 1k 中出现的,第二次接收的 0.5k 没问题
www_adintr_com 2013-07-24
  • 打赏
  • 举报
回复
那个位置是在组合两次 recv 结果的交接点上吗?

64,701

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧