发送时无法立即完成非阻塞套接字操作
本文关键字:操作 套接字 | 更新日期: 2023-09-27 18:29:01
我正在为游戏编写一个服务器,我希望能够处理数千个并发用户。出于这个原因,我选择了非阻塞套接字,并使用了轮询方法。但是,我确实创建了多个线程来处理数据库和web调用,其中一些线程将向用户发送响应。在其中一个线程中,在发送时,我收到错误"非阻塞套接字操作无法立即完成"。是什么原因导致了这个问题?我想这是因为在调用send的同时发生了轮询。如果我使用beginAsync,是否需要停止此错误?我想过锁定套接字,但我不希望我的主线程因此而被阻塞。
我不知道您使用的是哪种非阻塞轮询套接字调用,但我建议您使用异步套接字调用(而不是Begin)。有关异步调用与Begin之间差异的更多信息,请参阅:What';BeginConnect和ConnectAsync之间的区别是什么?
异步调用会在操作系统级别上自动进行"轮询",这将比轮询效率高得多。事实上,它们使用IO完成端口,这可能是Windows上处理大量客户端连接/请求时速度最快、效率最高的端口。
就错误而言,我认为这是非阻塞套接字的正常操作,所以您只需要优雅地处理它。
更新
您的服务器可能应该这样做:
// Process the accept for the socket listener.
private void ProcessAccept(SocketAsyncEventArgs e)
{
Socket s = e.AcceptSocket;
if (s.Connected)
{
try
{
SocketAsyncEventArgs readEventArgs = this.readWritePool.Pop();
if (readEventArgs != null)
{
// Get the socket for the accepted client connection and put it into the
// ReadEventArg object user token.
readEventArgs.UserToken = new Token(s, this.bufferSize);
Interlocked.Increment(ref this.numConnectedSockets);
Console.WriteLine("Client connection accepted.
There are {0} clients connected to the server",
this.numConnectedSockets);
if (!s.ReceiveAsync(readEventArgs))
{
this.ProcessReceive(readEventArgs);
}
}
else
{
Console.WriteLine("There are no more available sockets to allocate.");
}
}
catch (SocketException ex)
{
Token token = e.UserToken as Token;
Console.WriteLine("Error when processing data received from {0}:'r'n{1}",
token.Connection.RemoteEndPoint, ex.ToString());
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
// Accept the next connection request.
this.StartAccept(e);
}
}
代码项目提供的代码示例:http://www.codeproject.com/Articles/22918/How-To-Use-the-SocketAsyncEventArgs-Class
当一个非阻塞套接字试图读取数据但没有找到时,你会得到错误:套接字想等待数据,但不能,因为它必须立即返回,这是非阻塞的。
我建议您切换到阻塞套接字,找出数据丢失的原因,进行相应调整,然后恢复到非阻塞套接字。或者,您可以处理错误并重试该操作。
我在发送数据时也收到了这个异常,刚刚找到了解决方案。
由于套接字的发送缓冲区已满,因此会出现异常。因为您试图通过非阻塞发送发送数据,所以会引发异常,让您知道必须通过阻塞发送发送。
一旦出现异常,数据就不会被发送,所以你必须重新发送。你的个人发送呼叫现在变成;
try
{
m_socket.Send(buffer, bufferSize, SocketFlags.None);
}
catch (SocketException e)
{
if(e.SocketErrorCode == WouldBlock)
{
m_socket.Blocking = true;
m_socket.Send(buffer, bufferSize, SocketFlags.None);
m_socket.Blocking = false;
}
}
增加套接字的SendBufferSize也是一个好主意。默认情况下,我认为它是8kb。为了满足我的需要,我不得不将其增加到2MB,之后Send呼叫不再抛出该异常。
此异常过于普遍。根据MSDN,
如果收到SocketException,请使用SocketException.ErrorCode属性获取特定的错误代码。获得此代码后,请参阅MSDN库中的Windows Sockets版本2 API错误代码文档,以了解错误的详细说明。
套接字错误代码在这里。