Windows 远程计算机上传输速度慢

Windows 远程计算机上传输速度慢,windows,performance,sockets,tcp,Windows,Performance,Sockets,Tcp,大家好 我正在制作一个IOCP服务器,到目前为止,我已经解决了大多数问题,但还有一个问题仍然存在,我不知道从哪里开始考虑。当我在我的机器上运行客户机/服务器时,一切都很好。它与Windows SDK示例的速度相匹配,可能会快一点,而且肯定会占用更少的CPU周期。但是,当我从单独的计算机上运行客户端时,传输速度上限为37 KB/s,往返延迟为200ms(而不是0)。现在,如果我将客户机连接到SDK示例服务器,我没有这个问题,因此我的代码有问题。据我所知,套接字的初始化方式与相同的选项完全相同。我也

大家好

我正在制作一个IOCP服务器,到目前为止,我已经解决了大多数问题,但还有一个问题仍然存在,我不知道从哪里开始考虑。当我在我的机器上运行客户机/服务器时,一切都很好。它与Windows SDK示例的速度相匹配,可能会快一点,而且肯定会占用更少的CPU周期。但是,当我从单独的计算机上运行客户端时,传输速度上限为37 KB/s,往返延迟为200ms(而不是0)。现在,如果我将客户机连接到SDK示例服务器,我没有这个问题,因此我的代码有问题。据我所知,套接字的初始化方式与相同的选项完全相同。我也在探查器中运行了我的服务器以检查瓶颈,但我找不到任何瓶颈。此外,我试过的计算机都连接到同一个千兆交换机(带有千兆适配器)。我知道这有点含糊不清,但那是因为我目前还不能指出问题所在,如果你们中的任何人能给我指出正确的方向,我将永远感激

干杯

-罗克西

编辑2: 在遵循Mike的建议后,我对代码进行了一些研究,发现当远程客户端大部分时间连接到服务器时,代码都在等待GetQueuedCompletionStatus。这表明IO请求只是需要很长时间才能完成,但我仍然不明白为什么。这仅在客户端位于远程计算机上时发生。我认为这与如何设置套接字或如何发布请求有关,但我看不出与示例代码有任何区别

有什么想法吗

编辑(添加示例代码):

好的,给你!但这并不漂亮

如果安装了Windows SDK,则可以使用iocpclient示例(Program Files\Microsoft SDK\Windows\v7.1\Samples\netds\winsock\iocp\client)连接到它,并将第73行的默认端口更改为5000

当我自己尝试时,我注意到奇怪的事情是,样本iocpclient似乎不会导致37KB/s的相同上限问题。。。但是,看起来示例代码的限制设置为800KB/s左右。如果有什么帮助的话,我会给客户发邮件

#pragma comment(lib, "Ws2_32.lib")

#include <WinSock2.h>
#include <stdio.h>

unsigned int connection = 0;
unsigned int upload = 0;
unsigned int download = 0;

#define IO_CONTEXT_COUNT 5

class NetClientHost
{
friend class gNetProtocolHost;
public:
enum Operation
{
    kOperationUnknown,
    kOperationRead,
    kOperationWrite,
};

struct ClientData
{
    SOCKET           socket;
};

struct IOContext
{
    WSAOVERLAPPED    overlapped;
    WSABUF           wsaReceiveBuf;
    WSABUF           wsaSendBuf;
    char            *buf;
    char            *TESTbuf;
    unsigned long    bytesReceived;
    unsigned long    bytesSent;
    unsigned long    flags;
    unsigned int     bytesToSendTotal;
    unsigned int     remainingBytesToSend;
    unsigned int     chunk;
    Operation        operation;
};

NetClientHost()
{
    memset((void *) &m_clientData, 0, sizeof(m_clientData));
}

NetClientHost::IOContext *NetClientHost::AcquireContext()
{
    while (true)
    {
        for (int i = 0; i < IO_CONTEXT_COUNT; ++i)
        {
            if (!(m_ioContexts + i)->inUse)
            {
                InterlockedIncrement(&(m_ioContexts + i)->inUse);
                //ResetEvent(*(m_hContextEvents + i));

                if ((m_ioContexts + i)->ioContext.TESTbuf == 0)
                    Sleep(1);

                return &(m_ioContexts + i)->ioContext;
            }
        }
        //++g_blockOnPool;
        //WaitForMultipleObjects(IO_CONTEXT_COUNT, m_hContextEvents, FALSE, INFINITE);
    }   
}

const ClientData *NetClientHost::GetClientData() const
{
    return &m_clientData;
};

void NetClientHost::Init(unsigned int bufferSize)
{   
    _InitializeIOContexts(bufferSize ? bufferSize : 1024);
}

void NetClientHost::ReleaseContext(IOContext *ioContext)
{
    int i = sizeof(_IOContextData), j = sizeof(IOContext);
    _IOContextData *contextData = (_IOContextData *) (((char *) ioContext) - (i - j));
    InterlockedDecrement(&contextData->inUse);
    //SetEvent(*(m_hContextEvents + contextData->index));
}   

struct _IOContextData
{
    unsigned int index;
    volatile long inUse;        
    IOContext ioContext;
};

ClientData                    m_clientData;
_IOContextData               *m_ioContexts;
HANDLE                       *m_hContextEvents;

void _InitializeIOContexts(unsigned int bufferSize)
{
    m_ioContexts = new _IOContextData[IO_CONTEXT_COUNT];
    m_hContextEvents = new HANDLE[IO_CONTEXT_COUNT];

    memset((void *) m_ioContexts, 0, sizeof(_IOContextData) * IO_CONTEXT_COUNT);

    for (int i = 0; i < IO_CONTEXT_COUNT; ++i)
    {
        (m_ioContexts + i)->index = i;

        (m_ioContexts + i)->ioContext.buf = new char[bufferSize];
        (m_ioContexts + i)->ioContext.wsaReceiveBuf.len = bufferSize;
        (m_ioContexts + i)->ioContext.wsaReceiveBuf.buf = (m_ioContexts + i)->ioContext.buf;
        (m_ioContexts + i)->ioContext.TESTbuf = new char[10000];
        (m_ioContexts + i)->ioContext.wsaSendBuf.buf = (m_ioContexts + i)->ioContext.TESTbuf;

        *(m_hContextEvents + i) = CreateEvent(0, TRUE, FALSE, 0);
    }
}
void _SetSocket(SOCKET socket)
{
    m_clientData.socket = socket;
}
};



bool WriteChunk(const NetClientHost *clientHost, NetClientHost::IOContext *ioContext)
{
int status;

status = WSASend(clientHost->GetClientData()->socket, &ioContext->wsaSendBuf, 1, &ioContext->bytesSent, ioContext->flags, &ioContext->overlapped, 0);
if (status == SOCKET_ERROR && WSAGetLastError() != WSA_IO_PENDING)
{
    // ...
    return false;
}

return true;
}

bool Write(NetClientHost *clientHost, void *buffer, unsigned int size, unsigned int chunk)
{
//__ASSERT(m_clientHost);
//__ASSERT(m_clientHost->GetClientData()->remainingBytesToSend == 0);

NetClientHost::IOContext *ioContext = clientHost->AcquireContext();

if (!chunk)
    chunk = size;

ioContext->wsaSendBuf.buf = ioContext->TESTbuf;

ioContext->operation                = NetClientHost::kOperationWrite;
ioContext->flags                    = 0;
ioContext->wsaSendBuf.buf = new char[size];
memcpy((void *) ioContext->wsaSendBuf.buf, buffer, chunk);
ioContext->wsaSendBuf.len           = chunk;    
ioContext->chunk                    = chunk;
ioContext->bytesToSendTotal         = size;
ioContext->remainingBytesToSend     = size;

return WriteChunk(clientHost, ioContext);
}



void Read(NetClientHost *clientHost)
{   
NetClientHost::IOContext *ioContext = clientHost->AcquireContext();
int status;

memset((void *) ioContext, 0, sizeof(NetClientHost::IOContext));
ioContext->buf = new char[1024];
ioContext->wsaReceiveBuf.len = 1024;
ioContext->wsaReceiveBuf.buf = ioContext->buf;

ioContext->flags = 0;
ioContext->operation = NetClientHost::kOperationRead;

status = WSARecv(clientHost->GetClientData()->socket, &ioContext->wsaReceiveBuf, 1, &ioContext->bytesReceived, &ioContext->flags, &ioContext->overlapped, 0);
int i = WSAGetLastError();
if (status == SOCKET_ERROR && WSAGetLastError() != WSA_IO_PENDING)
{
    // ...
}   
}

bool AddSocket(HANDLE hIOCP, SOCKET socket)
{
++connection;

int bufSize = 0;
LINGER lingerStruct;
lingerStruct.l_onoff = 1;
lingerStruct.l_linger = 0;
setsockopt(socket, SOL_SOCKET, SO_SNDBUF, (char *) &bufSize, sizeof(int));
setsockopt(socket, SOL_SOCKET, SO_RCVBUF, (char *) &bufSize, sizeof(int));
setsockopt(socket, SOL_SOCKET, SO_LINGER, (char *) &lingerStruct, sizeof(lingerStruct) ); 

NetClientHost *clientHost = new NetClientHost;

clientHost->_InitializeIOContexts(1024);
clientHost->Init(0);
clientHost->_SetSocket(socket);

// Add this socket to the IO Completion Port
CreateIoCompletionPort((HANDLE) socket, hIOCP, (DWORD_PTR) clientHost, 0);

Read(clientHost);
return true;
}

int read = 0, write = 0;

DWORD WINAPI WorkerThread(LPVOID param)
{
LPOVERLAPPED overlapped;
NetClientHost *clientHost;
HANDLE hIOCP = (HANDLE) param;
DWORD ioSize;
BOOL status;

while (true)
{
    status = GetQueuedCompletionStatus(hIOCP, &ioSize, (PULONG_PTR) &clientHost, (LPOVERLAPPED *) &overlapped, INFINITE);

    if (!(status || ioSize))
    {
        --connection;
        //_CloseConnection(clientHost);
        continue;
    }

    NetClientHost::IOContext *ioContext = (NetClientHost::IOContext *) overlapped;

    switch (ioContext->operation)
    {
    case NetClientHost::kOperationRead:
        download += ioSize;
        Write(clientHost, ioContext->wsaReceiveBuf.buf, ioSize, 0);
        write++;
        clientHost->ReleaseContext(ioContext);
        break;

    case NetClientHost::kOperationWrite:
        upload += ioSize;
        if (ioContext->remainingBytesToSend)
        {
            ioContext->remainingBytesToSend -= ioSize;
            ioContext->wsaSendBuf.len = ioContext->chunk <= ioContext->remainingBytesToSend ? ioContext->chunk : ioContext->remainingBytesToSend; // equivalent to min(clientData->chunk, clientData->remainingBytesToSend);
            ioContext->wsaSendBuf.buf += ioContext->wsaSendBuf.len;
        }

        if (ioContext->remainingBytesToSend)
        {       
            WriteChunk(clientHost, ioContext);
        }
        else
        {
            clientHost->ReleaseContext(ioContext);              
            Read(clientHost);
            read++;
        }
        break;
    }
}

return 0;
}

DWORD WINAPI ListenThread(LPVOID param)
{
SOCKET sdListen = (SOCKET) param;

HANDLE hIOCP = CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 0);
CreateThread(0, 0, WorkerThread, hIOCP, 0, 0);
CreateThread(0, 0, WorkerThread, hIOCP, 0, 0);
CreateThread(0, 0, WorkerThread, hIOCP, 0, 0);
CreateThread(0, 0, WorkerThread, hIOCP, 0, 0);

while (true)
{
    SOCKET as = WSAAccept(sdListen, 0, 0, 0, 0);
    if (as != INVALID_SOCKET)
        AddSocket(hIOCP, as);
}
}

int main()
{
SOCKET      sdListen;
SOCKADDR_IN si_addrlocal;   
int         nRet;   
int         nZero = 0;   
LINGER      lingerStruct;   

WSADATA wsaData;
WSAStartup(0x202, &wsaData);

sdListen = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_IP, NULL, 0, WSA_FLAG_OVERLAPPED);    
si_addrlocal.sin_family = AF_INET;   
si_addrlocal.sin_port = htons(5000);   
si_addrlocal.sin_addr.s_addr = htonl(INADDR_ANY);          
nRet = bind(sdListen, (struct sockaddr *)&si_addrlocal, sizeof(si_addrlocal));   
nRet = listen(sdListen, 5);

nZero = 0;   
nRet = setsockopt(sdListen, SOL_SOCKET, SO_SNDBUF, (char *) &nZero, sizeof(nZero));   
nZero = 0;   
nRet = setsockopt(sdListen, SOL_SOCKET, SO_RCVBUF, (char *)&nZero, sizeof(nZero));
lingerStruct.l_onoff = 1;   
lingerStruct.l_linger = 0; 
nRet = setsockopt(sdListen, SOL_SOCKET, SO_LINGER, (char *)&lingerStruct, sizeof(lingerStruct) );

CreateThread(0, 0, ListenThread, (LPVOID) sdListen, 0, 0);

HANDLE console = GetStdHandle(STD_OUTPUT_HANDLE);
while (true)
{
    COORD c = {0};
    SetConsoleCursorPosition(console, c);
    printf("Connections: %i                      \nUpload: %iKB/s               \nDownload: %iKB/s              ", connection, upload * 2 / 1024, download * 2 / 1024);
    upload = 0;
    download = 0;
    Sleep(500);
}



return 0;
}
#pragma注释(lib,“Ws2_32.lib”)
#包括
#包括
无符号整数连接=0;
无符号整数上传=0;
无符号整数下载=0;
#定义IO_上下文_计数5
类NetClientHost
{
好友类gNetProtocolHost;
公众:
枚举操作
{
我不知道,
科雷德,
我写,
};
结构客户端数据
{
插座;
};
结构IOContext
{
wsao重叠;
WSABUF wsaReceiveBuf;
WSABUF wsaSendBuf;
char*buf;
char*TESTbuf;
接收到未签名的长字节;
未签名的长拜登;
无符号长旗;
无符号整数bytesToSendTotal;
testosend保留的无符号整数;
无符号整数块;
手术操作;
};
NetClientHost()
{
memset((void*)和m_clientData,0,sizeof(m_clientData));
}
NetClientHost::IOContext*NetClientHost::AcquireContext()
{
while(true)
{
for(int i=0;iinUse)
{
联锁增量(&(m_ioContexts+i)->inUse);
//ResetEvent(*(m_hContextEvents+i));
if((m_ioContexts+i)->ioContext.TESTbuf==0)
睡眠(1);
返回和(m_ioContext+i)->ioContext;
}
}
//++g_区块池;
//WaitForMultipleObjects(IO_上下文_计数、m_hContextEvents、FALSE、无限);
}   
}
常量ClientData*NetClientHost::GetClientData()常量
{
返回&m_客户数据;
};
void NetClientHost::Init(无符号int-bufferSize)
{   
_初始化IOCONTEXTS(bufferSize?bufferSize:1024);
}
void NetClientHost::ReleaseContext(IOContext*IOContext)
{
int i=sizeof(_IOContextData),j=sizeof(IOContext);
_IOContextData*contextData=(_IOContextData*)((char*)ioContext)-(i-j));
联锁删除(&contextData->inUse);
//SetEvent(*(m_hContextEvents+contextData->index));
}   
结构IOContextData
{
无符号整数索引;
挥发性长菊糖;
IOContext-IOContext;
};
ClientData m_ClientData;
_IOContextData*m_ioContexts;
处理*m_hContextEvents;
void _InitializeIOContexts(无符号int-bufferSize)
{
m_ioContexts=new_IOContextData[IO_CONTEXT_COUNT];
m_hContextEvents=新句柄[IO_CONTEXT_COUNT];
memset((void*)m_ioContexts,0,sizeof(_IOContextData)*IO_CONTEXT_COUNT);
for(int i=0;i索引=i;
(m_ioContexts+i)->ioContext.buf=new char[bufferSize];
(m_ioContexts+i)->ioContext.wsaReceiveBuf.len=缓冲区大小;
(m_ioContexts+i)->ioContext.wsaReceiveBuf.buf=(m_ioContexts+i)->ioContext.buf;
(m_ioContexts+i)->ioContext.TESTbuf=newchar[10000];
(m_ioContexts+i)->ioContext.wsaSendBuf.buf=(m_ioContexts+i)->ioContext.TESTbuf;
*(m_hContextEvents+i)=CreateEvent(0,真,假,0);
}
}
空套(插座)
{
m_clientData.socket=套接字;
}
};
bool WriteChunk(常量NetClientHost*clientHost,NetClientHost::IOContext*IOContext)
{
智力状态;
status=WSASend(clientHost->GetClientData()->socket,&ioContext->wsaSendBuf,1,&ioContext->bytesSent,ioContext->flags,&ioContext->overlapped,0);
如果(状态==SOCKET\u ERROR&&WSAGetLastError()!=WSA\u IO\u PENDING)
{
// ...
返回false;
}
返回true;
}
bool写入(NetClientHost*clientHost,void*缓冲区,无符号整数大小,无符号整数块)
{
//__断言(m_clientHost);
//__断言(m_clientHost->GetClientData()->remainingBytesToSend==0);
NetClientHost::IOContext*IOContext=clientHost->Acq