当我在处理类似问题时遇到此帖子时,我将为正在处理此问题或类似问题的任何人提供以下内容。我希望这可以节省其他人一些时间。
我还要感谢 @Roman R. 的上述评论和 @Rom098 跟进的评论,指出缓冲区大小的变化也帮助了他/她。
使用带有 UDP 的 Windows 套接字以低数据速率在多个终端之间进行数据通信的应用程序在 Windows XP 上运行良好,但随着迁移到 Windows 7,我们开始遇到网络消息被丢弃的问题。
该架构是客户端通过发送和接收一系列UDP消息与服务器终端进行对话,客户端保持自己的状态。客户端有一个线程,即客户端线程,它处理用户输入以及向服务器终端发送和接收消息。服务器终端有一个线程,服务器线程,它处理来自其他终端的请求消息以及它自己的客户端线程。简单的消息序列如下所示:
- 客户端向服务器端发送请求消息
- 服务器终端响应确认消息
- 服务器端处理请求并向客户端发送响应消息
- 客户端向服务器端发送确认
查看上面的 cmets,我们使用调试器检查,发现 Windows 7 的默认 WinSock 接收和发送缓冲区大小为 8K(8192 字节)。在 Internet 上查找,似乎 Windows XP 对网络流量的处理速度更高。
我们对处理通信的网络层进行了两项更改。
第一种是使用setsockopt()函数将接收和发送缓冲区的大小加倍,使用以下代码。
iOptLen = sizeof(INT);
error = getsockopt (iSocket, SOL_SOCKET, SO_RCVBUF, (PCHAR)(&iOpt), &iOptLen);
if (error < 0) {
error = WSAGetLastError();
} else if (iOpt < 1024 * 16) {
iOpt = 1024 * 16;
error = setsockopt(iSocket, SOL_SOCKET, SO_RCVBUF, (const PCHAR)(&iOpt), sizeof(iOpt));
if (error < 0) {
error = WSAGetLastError();
}
}
iOptLen = sizeof(INT);
error = getsockopt (iSocket, SOL_SOCKET, SO_SNDBUF, (PCHAR)(&iOpt), &iOptLen);
if (error < 0) {
error = WSAGetLastError();
} else if (iOpt < 1024 * 16) {
iOpt = 1024 * 16;
error = setsockopt(iSocket, SOL_SOCKET, SO_SNDBUF, (const PCHAR)(&iOpt), sizeof(iOpt));
if (error < 0) {
error = WSAGetLastError();
}
}
我们所做的第二个更改是,如果客户端线程正在等待确认并且响应消息来自服务器终端,则将响应消息作为确认和响应的组合进行处理。我们所做的是假设确认消息在某个时间点被丢弃。
通过这两个更改,延迟不再明显,尽管我们的测量表明有时从服务器终端到客户端的确认消息仍然被丢弃。
另见
Change default socket buffer size under Windows 使用 Windows 注册表更改将默认缓冲区大小从 8K 修改为其他值。
What is the size of a socket send buffer in Windows? 与 TCP 相关,但提供了有关 setsockopt() 的其他信息。
Winsock UDP packets being dropped? 讨论了一个类似的问题,其中提供了许多答案,提供了额外的信息。
来自 Innominate.com 的Application Note: Windows 2000/XP TCP Tuning for High Bandwidth Networks 提供了一些有趣的信息,尽管可能有点过时,因为我知道在 Windows 7 中网络层已被重写。
来自 codeproject.com 上的 Michael Pan 的Real time communications over UDP protocol 有很多关于使用 UDP 的技术问题的详细信息。