我在使用winsock的C ++ CLI中为服务器编写了一个套接字。套接字使用异步方法来发送,接收和接受连接。在生产环境中实现我的套接字后,send函数停止工作,给出错误WSAEWOULDBLOCK。根据我对网络的研究,这意味着套接字IO的网络缓冲区已满或者网络太忙而无法在此时进行操作。但是,我还没有看到任何可以解决这个问题的具体解决方案。我的临时解决方案是围绕WSASend函数创建一个do-while循环,使线程为X量的MS休眠,然后再试一次。这导致了比前一个套接字(.NET套接字类)和大的延迟峰值更高的延迟。
我发送数据的代码如下:
void Connectivity::ConnectionInformation::SendData(unsigned char data[], const int length)
{
if (isClosed || sendError)
return;
Monitor::Enter(this->syncRoot);
try
{
sendInfo->buf = (char*)data;
sendInfo->len = length;
do
{
state = 0;
if (WSASend(connection, sendInfo, 1, bytesSent, 0, NULL, NULL) == SOCKET_ERROR)
{
state = WSAGetLastError();
if (state == WSAEWOULDBLOCK)
{
Thread::Sleep(SleepTime);
//Means the networking is busy and we need to wait a bit for data to be sent
//Might wanna decrease the value since this could potentially lead to lagg
}
else if (state != WSA_IO_PENDING)
{
this->sendError = true;
//The send error bool makes sure that the close function doesn't get called
//during packet processing which could cause a lot of null reffernce exceptions.
}
}
}
while (state == WSAEWOULDBLOCK);
}
finally
{
Monitor::Exit(this->syncRoot);
}
}
有没有办法使用例如WSAEventSelect方法,以便在我能够发送数据时获得回调?从MSDN上的文档中,等待数据方法也可能陷入此错误。任何人都有解决方案吗?
答案 0 :(得分:3)
错误代码WSAEWOULDBLOCK
表示您尝试在非阻塞套接字上操作,但无法立即完成操作。这不是一个真正的错误 - 这意味着您可以稍后重试或安排异步IO(这不会失败)。但这首先不是你想要的。让我解释一下:
您应该以两种方式之一使用套接字:
你正在混合两者,这两者都是最糟糕的。您创建了一个非阻塞套接字并以可能阻塞的方式使用它。
唉,我没有资格为本机代码套接字提供最佳实践。我建议你阅读所有docs for WSASend,因为它们似乎解释了所有这些。
现在,为什么这个奇怪的错误代码会存在?这是一种性能优化。您可以推测性地尝试同步发送(这非常快)。只有当它失败时,你应该安排一个异步IO。如果您不需要优化(您不需要),请不要这样做。
答案 1 :(得分:0)
正如@usr所说,我需要将LPWSAOVERLAPPED或LPWSAOVERLAPPED_COMPLETION_ROUTINE设置为一个值,以使操作无阻塞。但是,在测试之后,我发现我需要一个LPWSAOVERLAPPED对象才能调用完成例程。在MSDN上还提到了WSASend函数的文档,如果重叠对象和完成例程为NULL,则套接字将表现为阻塞套接字。
谢谢,祝大家圣诞快乐! :)