udp 接受数据不完整,如何解决? sniffer抓包,数据全部到达?

bobo55821912 2012-03-15 05:37:00
下面是本人写的客户端接收数据的代码,没有问题。程序情况如下:
服务器发送10M的数据,
客户端可以接收到前面大概1M 的数据然后就阻塞在recvfrom();
请问如何解决这种问题?
数据是局域网传输,本人用的是千兆网,网络畅通。
曾经测试过如果服务器发送完数据后等待一会,客户端可以接收到更多的数据。
希望大家有更好的解决办法?

fd_set fdRead;
fd_set fdSocket;
FD_ZERO(&fdSocket);
// FD_SET(socket, &fdSocket);
FD_SET(datasocket, &fdSocket);

timeval timeout;
timeout.tv_sec = RESPONSETIME;//RESPONSETIME = 2

while (true)
{
fdRead = fdSocket;
int nRet = ::select(0, &fdRead, NULL, NULL, &timeout);
if(nRet >0)
{
for(int i = 0; i<(int)fdSocket.fd_count; i++)
{
if (FD_ISSET(datasocket, &fdRead))
{
if (fdSocket.fd_array[i] == datasocket)
{
::recvfrom(datasocket, CommandData, sizeof(CommandData), 0, (sockaddr *)&RecvAddr, &n);
do
{
memset(recvimagedata, 0, RECVBUFFER);
recvlen = ::recvfrom(datasocket, recvimagedata, RECVBUFFER, 0, (sockaddr *)&RecvAddr, &n);
if(recvlen >8)
memcpy_s(psave, imagebuffersize, (recvimagedata + 8), recvlen - 8);
imagebuffersize -= recvlen;
psave += recvlen;
} while (imagebuffersize > 0);
::recvfrom(datasocket, CommandData, sizeof(CommandData), 0, (sockaddr *)&RecvAddr, &n);
}
}
}
}
}
...全文
891 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
Kevin_qing 2012-03-19
  • 打赏
  • 举报
回复
你用udp不自己构造协议,发送方怎么知道接受方收到数据没,光是盲目的发,接收方来不及收的话,数据就被抛弃了。


另外udp不会保证包的顺序到达,就算你收到数据,也要重新组合为原始的顺序才行。


bobo55821912 2012-03-18
  • 打赏
  • 举报
回复
[Quote=引用 15 楼 xianglitian 的回复:]
引用 14 楼 bobo55821912 的回复:

int nRet = ::select(0, &amp;fdRead, NULL, NULL, &amp;timeout);
我用的是select();有什么问题吗?是我理解错误,还是我select用法有问题?
不好意思
疏忽了
我的意思是用select设置异步调用
这样通过消息来触发接收时间
来多少读多少
这……
[/Quote]
有道理。不过这样会影响数据接收速度吧?
向立天 2012-03-16
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 bobo55821912 的回复:]

我将接收缓冲区设置成10M结果是数据全部接收
进一步测试:1.缓冲区设置大于或等于接收数据大小,数据可以完整接收
2.小于接收接收数据也可以完整接收,但是不是每次都能接收完整的数据;而且不能太小,最多不能小于400K,否则数据很难完整接收。
结论:1.设置合适缓冲区,对于裸udp很重要;尤其是在性能优先的情况下。
2.裸udp不适合传输大数据量文件。
……
[/Quote]
我记得没有超时设置
如果不想阻塞接收就用select模型
sparrow429 2012-03-16
  • 打赏
  • 举报
回复
我想问下,如果直接继承CSocket,跟楼主这样写,接受数据比较,哪个比较快啊
bobo55821912 2012-03-16
  • 打赏
  • 举报
回复
我将接收缓冲区设置成10M结果是数据全部接收
进一步测试:1.缓冲区设置大于或等于接收数据大小,数据可以完整接收
2.小于接收接收数据也可以完整接收,但是不是每次都能接收完整的数据;而且不能太小,最多不能小于400K,否则数据很难完整接收。
结论:1.设置合适缓冲区,对于裸udp很重要;尤其是在性能优先的情况下。
2.裸udp不适合传输大数据量文件。

对了想问问各位,我写的非阻塞模式有问题吗?当接收的数据不完整时,程序在recvfrom()处阻塞不跳出。我理解的意思是2秒后跳出recvfrom()。
向立天 2012-03-16
  • 打赏
  • 举报
回复
你的CommandData多大
ndy_w 2012-03-16
  • 打赏
  • 举报
回复
sniffer看到"数据到达"是底层,到达以后需要从网卡取出,放入缓冲区。如果缓冲区满,是不会等待上层取数据而导致缓冲区有空的,而是直接丢弃。
接收是应该很快的,看你接取数据之后的处理是否费时。因为网络快,而你的服务器又没有流控,所以很可能就是接收处理的速度赶不上发送的速度。
"服务器关闭连接"是TCP的概念。UDP不是面向连接的,是面向数据报。TCP会做流控,使服务器慢点发,让客户端有事件处理。
看你的需求是什么,也许该改用TCP,也许应该自己在UDP上做流控。
bobo55821912 2012-03-16
  • 打赏
  • 举报
回复
这个问题很棘手, 希望大家多多关注、讨论找出好的解决方法。
或者说有什么快速接收的编程方法。不妨说出来。
bobo55821912 2012-03-16
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 visualeleven 的回复:]
服务器发送数据太快,导致接收端的socket系统缓冲区快速充满,这样的结果是导致后续的数据丢失?
[/Quote]
四楼想法和我一致,因为测试过,只要服务器等待一会不退出,客户端还是可以接收完整的数据的。
网络编程有这么一句话:服务器关闭连接,客户端立即丢弃与其相关的数据。
客户端接收数据为什么这么慢,按道理服务器的数据要在网络上传输;而客户端只需执行接收语句就可以了,不存在接收慢于发送啊!虽然总体上接收会推迟,但是现在只接收到1M左右的数据。
纠正5楼,数据包用sniffer探测到,数据全部到达。
向立天 2012-03-16
  • 打赏
  • 举报
回复
[Quote=引用 14 楼 bobo55821912 的回复:]

int nRet = ::select(0, &fdRead, NULL, NULL, &timeout);
我用的是select();有什么问题吗?是我理解错误,还是我select用法有问题?
[/Quote]不好意思
疏忽了
我的意思是用select设置异步调用
这样通过消息来触发接收时间
来多少读多少
这样就不会阻塞了
bobo55821912 2012-03-16
  • 打赏
  • 举报
回复
int nRet = ::select(0, &fdRead, NULL, NULL, &timeout);
我用的是select();有什么问题吗?是我理解错误,还是我select用法有问题?
zmshy2128 2012-03-15
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 visualeleven 的回复:]
服务器发送数据太快,导致接收端的socket系统缓冲区快速充满,这样的结果是导致后续的数据丢失?
[/Quote]
当然要丢,udp嘛,发了不管对方能不能收
Eleven 2012-03-15
  • 打赏
  • 举报
回复
服务器发送数据太快,导致接收端的socket系统缓冲区快速充满,这样的结果是导致后续的数据丢失?
zmshy2128 2012-03-15
  • 打赏
  • 举报
回复
设置socket较大的收发缓冲区

int size = 1024*256;
setsockopt(m_ServerSock,SOL_SOCKET,SO_RCVBUF,(const char*)&size,sizeof(int));
setsockopt(m_ServerSock,SOL_SOCKET,SO_SNDBUF,(const char*)&size,sizeof(int));
hehening88 2012-03-15
  • 打赏
  • 举报
回复
有可能是套接口缓冲区大小限制,用SO_RCVBUF套接口选项来改变这个缓冲区大小试试。一家之言,只是个建议。
[menu_102] 70001=文件(&F) 40024=开始捕获(&S) 40025=停止捕获(&T) 40045=保存配置(&C) 40046=载入配置(&O) 40034=保存数据数据到文件 40035=载入数据数据文件 40039=导出 TCP/IP 流报告(&E) 40001=保存数据包摘要(&A) 40009=属性(&P) 40002=退出(&X) 70002=编辑(&E) 40031=复制(&C) 40007=全选(&A) 40015=全部取消选定(&D) 40032=下一项(&N) 40033=上一项(&P) 70003=查看(&V) 40005=显示网格线(&G) 40028=显示气球提示(&T) 40010=HTML 报告 - TCP/IP 流(&H) 40011=栏位设定(&N) 40012=自动调整栏的宽度(&A) 70004=选项(&O) 71001=显示模式(&M) 41101=自动(&A) 41102=ASCII(&S) 41103=16进制(&H) 71002=显示协议(&P) 41201=&TCP 41202=&UDP 41203=&ICMP 40027=显示 ASCII 码大于 127 的字符(&C) 40041=显示捕获时间(&T) 40042=将 IP 地址解析为主机名 40044=显示过滤设置 40040=高级选项(&A) 40043=捕获过滤设置 40026=选择设备(&O) 70005=帮助(&H) 40003=关于(&A) 41104=&URL 列表 [menu_104] 70001=Popup1 40010=生成 TCP/IP 流的 HTML 报告(&H) 40039=保存 TCP/IP 流报告(&E) 40001=保存数据包摘要(&A) 40011=栏位设定(&N) 40012=栏位自动宽度(&A) 40007=选择全部(&A) 40015=取消已选定(&D) 40031=复制(&C) 40032=下一项(&N) 40033=上一项(&P) 70002=Popup2 [dialog_105] caption=属性 1=确定 [dialog_108] caption=捕获选项 1007=原始套接字 (仅Windows 2000/XP) 1008=使用 WinPcap 包捕获驱动 1005=List1 1=确定 2=取消 1006=捕获方式 1009=选择网卡: 1045=选择网卡: [dialog_112] 1=确定 [dialog_113] caption=高级选项 1035=即时显示模式 - 捕获的同时列出 TCP/IP 会话 1011=每行字符数: 1013=显示时,在每 1025=显示 ASCII 字符 1026=在每行开头显示偏移量 1014=自动决定显示模式时要检查的字符数: 1032=不可显示的 ASCII 字符替换为: 1036=自动模式中, 若数据长度大于此限制则不显示16进制数据 1038=在下部面板中不显示数据长度大于此限制的项 1019=选择 1022=选择 1029=选择 1=确定 2=取消 1010=16进制显示选项 1015=个字符后插入额外的空格 1016=文字颜色 1017=源于本地主机的 TCP/IP 流的文字颜色: 1020=源于远程主机的 TCP/IP 流的文字颜色: 1030=捕获时间的文字颜色: 1031=常规显示选项 1034=捕获 1039=KB 1041=KB 1042=捕获同时显示 TCP/IP 会话内容开始的部分 1043=仅显示 TCP/IP 统计数据, 不在文件中保存捕获数据 1044=捕获时亦获取进程信息 1045=摘要模式 (每个连接之间不换行) [dialog_114] 1=确定 2=取消 3=清除 1037=输入一条或多条过滤规则, 以空格或回车分隔。以下是过滤字规则的几个例子: [dialog_1096] caption=栏位设定 1003=上移(&U) 1004=下移(&D) 1006=显示(&S) 1007=隐藏(&H) 1008=默认 1=确定 2=取消 1000=钩选要显示的内容, 用上移或下移按钮排列显示顺序 1002=栏位宽度(像素): [strings] 4=%d 个 TCP/IP 会话 5=, 选定 %d 个 6=创建本文件使用的是 7=选择保存文件的名称 8=数据包摘要 9=无法启动选定网卡上的包捕获。 10=该项所含数据长度超过 %d KB 限制。 11=可使用导出选项将此项保存到文件中。 12=此 TCP/IP 会话太大,无法在捕获同时显示。 13=停止捕获后将显示会话的完整内容。 14=正在加载... %d 15=已捕获 %d 个数据包 16=错误: 无法创建数据包文件! 17=正在捕获... 18=选择用于保存已捕获数据的文件名 19=载入存有数据数据的文件 20=确定要停止捕获并退出 SmartSniff 吗? 21=选择用于保存已捕获的数据包流的文件名称 22=数据包流报告 23=当前操作含有非常大的数据包流,载入过程可能很慢,要继续吗? 24=选择要保存的配置文件名 25=选择要载入的配置文件 51=捕获过滤选项 52=显示过滤选项 101=字节 501=文本文件 502=制表符分隔的文本文件 503=空格分隔的表格化文本文件 504=HTML 文件 - 水平方式 505=HTML 文件 - 垂直方式 506=XML 文件 521=ICMP 522=TCP 523=UDP 541=文本文件 542=HTML 文件 543=原始数据文件 601=SmartSniff 数据包文件 602=tcpdump/libpcap 文件 621=SmartSniff 配置文件 1001=编号 1002=协议 1003=本地地址 1004=远程地址 1005=本地端口 1006=远程端口 1007=数据包数量 1008=包含封装信息的总数据量 1009=捕获时间 1010=不含封装信息的数据量 1011=服务名称 1012=本地主机 1013=远程主机 1014=进程号 1015=进程文件名 1051=IP 地址 1052=设备名称

18,356

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 网络编程
c++c语言开发语言 技术论坛(原bbs)
社区管理员
  • 网络编程
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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