问题描述
简单的单线程应用通过2或3个NIC发送UDP流量,以发送2GB或3GB流量。 在同一台PC上, Windows 10成功发送每个NIC 1GB ,而在Windows Server 2012/2016上仅获得:
-
发送到2个NIC时,每个NIC
- 〜550Mbps。 发送到3个NIC时,每个NIC
- 〜380Mbps。 发送到4个NIC时,每个NIC
- 〜270Mbps。
在Windows 10上将SO_SNDBUF设置为1可提供与Windows 2016/2012相同的性能
它看起来像Windows服务器跳过套接字缓冲区(用SO_SNDBUF设置),然后直接将其写入NIC 。Windows10是否将始终写入袜子缓冲区。
将代码更新为多线程(每个套接字1个线程),我在2016年也为每个NIC获得1Gbps。
对https://www.binarytides.com/udp-socket-programming-in-winsock/中的代码进行相同的更改:
#include<stdio.h>
#include<winsock2.h>
#include<string>
#include <vector>
#include <filesystem>
#pragma comment(lib,"ws2_32.lib") //Winsock Library
#define SERVER "127.0.0.1" //ip address of udp server
#define BUFLEN 63*1024 //Max length of buffer
#define PORT 8888 //The port on which to listen for incoming data
struct socket_data
{
SOCKET s;
struct sockaddr_in si_other;
std::string ip;
};
int main(int argc,char **argv)
{
int slen = sizeof(struct sockaddr_in);
char message[64 * 1024];
std::vector<socket_data> sd;
WSADATA wsa;
if (2 > argc)
{
printf("please provide list of destinations IP.\n");
printf("For example:\n %ls 22.22.22.255 11.11.11.255 12.12.12.255\n",std::experimental::filesystem::path(argv[0]).filename().c_str());
exit(EXIT_FAILURE);
}
for (size_t i = 1; i < argc; i++)
{
socket_data tmp;
tmp.ip = argv[i];
sd.push_back(tmp);
}
for (int i = 0; i < BUFLEN; ++i)
{
message[i] = i;
}
//Initialise winsock
printf("\nInitialising Winsock...");
if (WSAStartup(MAKEWORD(2,2),&wsa) != 0)
{
printf("Failed. Error Code : %d",WSAGetLastError());
exit(EXIT_FAILURE);
}
printf("Initialised.\n");
//create socket
for (int i = 0; i < sd.size(); ++i)
{
if ((sd[i].s = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP)) == SOCKET_ERROR)
{
printf("socket() Failed with error code : %d",WSAGetLastError());
exit(EXIT_FAILURE);
}
//setup address structure
memset((char *)&sd[i].si_other,sizeof(sd[i].si_other));
sd[i].si_other.sin_family = AF_INET;
sd[i].si_other.sin_port = htons(PORT);
sd[i].si_other.sin_addr.S_un.S_addr = inet_addr(sd[i].ip.c_str());
int sendbuff = 20*1024*1024;
setsockopt(sd[i].s,SOL_SOCKET,SO_SNDBUF,(char*)&sendbuff,sizeof(sendbuff));
}
//start communication
while (1)
{
for (int i = 0; i < sd.size(); ++i) {
//send the message
if (sendto(sd[i].s,message,BUFLEN - 1,(struct sockaddr *) &sd[i].si_other,slen) == SOCKET_ERROR)
{
printf("sendto() Failed with error code : %d",WSAGetLastError());
exit(EXIT_FAILURE);
}
}
}
for (int i = 0; i < 3; ++i)
{
closesocket(sd[i].s);
}
WSACleanup();
return 0;
}
解决方法
在 linux 上没有问题,我使用下面的代码为每个 NIC 获得 1Gbps。 对于 Windows 2016/2012,我设法使用连接的套接字解决了这个问题。我使用 ACE_SOCK_CODgram,但我确定使用上面相同的代码与 connect 可以工作(ACE_SOCK_CODgram 连接)。