UDP发送()到本地主机在Winsock下丢弃数据包
UDP send() to localhost under Winsock throwing away packets?
场景相当简单…不允许使用" sendto()
",所以使用" send()
"代替…
在winsock2.2
下,在一台运行Windows 7 Professional
的全新i7机器上正常运行…
使用SOCK_DGRAM
套接字,客户端和服务器控制台应用程序通过localhost
(127.0.0.1
)连接来测试事情…
必须使用固定大小的数据包…
客户端套接字使用connect()
,服务器套接字使用bind()
…
客户端通过一系列BLOCKING
send()
呼叫发送N个数据包。服务器只使用ioctlsocket
调用FIONREAD
,在while
循环中运行,以不断等待接收printf()
字节数…
数据包丢失,除非我把SLEEP()
相当多的时间…
我的意思是如果我不使用SLEEP()
,则接收套接字上的字节数在运行之间会有所不同…
已经玩了改变缓冲区大小,情况没有太大变化,除了现在没有溢出,但问题与延迟保持不变…
我看过很多关于send()
和recv()
之间问题的讨论,但在这种情况下,recv()
甚至没有参与…
的想法吗?
(注:
由于我无法控制的原因,我正在编程的约束是必需的,所以没有WSA
, .NET
, MFC
, STL
, BOOST
, QT
或其他东西)
这不是一个缓冲区溢出的问题,有三个原因:
- 输入和输出缓冲区都设置并检查为远远大于所有正在发送的信息。
- 没有
recv()
,只有通过ioctl()
调用检查传入缓冲区,recv()在用户输入后很长时间被调用。 - 当
send()
-s之间添加>40ms
的Sleep()
时,整个工作正常,即如果存在溢出,则没有数量的Sleep()
会有帮助(again, see point (2)
)
- 没有
包会丢失,除非我用相当数量的SLEEP()时间……我指的是接收套接字上的字节数如果我不使用SLEEP()…
这是预期的行为;正如其他人在评论中所说,UDP数据包可以并且确实因为任何原因而被丢弃。然而,在仅本地主机通信的上下文中,原因通常是某个地方的固定大小的数据包缓冲区已满,无法容纳传入的UDP数据包。请注意,UDP没有流量控制的概念,所以如果你的接收程序不能跟上你的发送程序,一旦缓冲区满了,丢包肯定会发生。
至于如何处理它,insert-a-call-to-sleep()解决方案并不是特别好,因为您没有很好的方法知道"正确的"睡眠持续时间应该是多少。(缩短一个sleep(),你仍然会丢失数据包;sleep()太长会导致数据传输速度变慢;当然,"最佳"值可能会因计算机而异,或以不明显的方式从一个时刻到下一个时刻而异)。
您可以做的一件事是切换到不同的传输协议,如TCP,或者(因为您只在本地主机内通信),一个简单的管道或套接字对。这些协议具有您正在寻找的无损FIFO语义,因此它们可能是这项工作的正确工具。
假设你需要使用UDP,然而,UDP数据包丢失对你来说将是一个不可避免的事实,但是你可以做一些事情来减少数据包丢失:
- send()在阻塞模式下,或者如果使用非阻塞的send(),一定要等到UDP套接字select()在调用send()之前为ready-for-write。(我知道你说你发送()在阻塞模式;我只是为了完整而包括这个) 让你的SO_RCVBUF设置在接收UDP套接字上尽可能大。缓冲区越大,它填满容量的可能性就越低。
- 在接收程序中,确保调用recv()的线程不做任何其他会阻止它返回下一个recv()调用的事情。特别是,没有阻塞操作(即使printf()也是一个阻塞操作,它会减慢线程的速度,特别是在Windows下,DOS提示符因加载时滚动缓慢而臭名昭著)
- 在一个单独的线程中运行接收器的网络recv()循环,除了调用recv()并将接收到的数据放入FIFO队列(或其他共享数据结构)之外什么都不做。然后,另一个线程可以在FIFO中执行检查和解析数据的时间要求较低的工作,而不必担心导致丢包。
- 以你能说服操作系统允许你运行的最高优先级运行UDP-receive线程。可以占用UDP-receive线程的其他任务越少,在这些延迟期间数据包被丢弃的机会就越少。
请记住,无论您如何聪明地减少UDP数据包丢失的机会,UDP数据包丢失仍然会发生。因此,无论如何,您需要提出一种设计,使您的程序即使在数据包丢失时仍能以合理有用的方式运行。这可以通过实现某种自动重发机制来实现,或者(取决于您想要实现什么)通过设计可以简单地忽略数据包丢失的协议来实现。
- boost::asio UDP 广播客户端仅接收"fast"数据包
- 如何使用发送数据包所花费的时间计算两个节点之间的距离?
- 发送固定大小的 UDP 数据包
- pcap_handler回调仅在使用 NPCAP v0.9991 时包含空数据包
- 在 c++ 中解析数据包数据的最佳方法是什么?
- 接受函数在发送数据包时等待
- 如何在 omnet++ 中发送自定义数据包?
- 数据包访问实践
- 在C++中创建一个简单的数据包路由器,如何跟踪"客户端"?
- 德拉吉诺 LG01-S 收到异常数据包并停止工作
- 将数据包从C++服务器发送到NodeJs服务器时出现MessagePack解码错误
- 使用C++将UDP数据包存储在Structure中
- Winsock 数据不是从 IP 检索的,而是从普通 URL 检索的
- FFmpeg av_read_frame从音频流返回数据包
- C++ 绕道 Winsock recv 挂钩 - 自定义数据包
- C++TCP Winsock服务器多次接收相同的数据包
- 为什么我在使用 winsock 时没有收到 UDP 数据包?
- Windows/Winsock UDP 数据包正在分组在一起
- UDP发送()到本地主机在Winsock下丢弃数据包
- 如何在 c++ 中使用 winsock 接收 udp 数据包