我正在为游戏编写服务器,我希望能够处理数千个并发用户。出于这个原因,我选择了非阻塞套接字并使用poll方法。但是,我确实创建了多个线程来处理数据库和Web调用,其中一些线程会向用户发送响应。在其中一个线程中,在发送时,我收到错误“无法立即完成非阻塞套接字操作”。什么可能导致这个问题?我想这是因为调用是在调用send的同时发生的。如果我使用beginAsync,是否需要停止此错误?我想锁定套接字,但我不希望我的主线程被阻止。
答案 0 :(得分:4)
我不知道您使用的是哪种非阻塞轮询套接字调用,但我建议您使用异步套接字调用(而不是Begin )。有关异步调用与开始之间区别的详细信息,请参阅:What's the difference between BeginConnect and 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
答案 1 :(得分:2)
当一个非阻塞套接字试图读取数据但没有找到时,你会得到那个错误:套接字想要等待数据,但不能,因为它必须立即返回,是非阻塞的。
我建议你切换到阻塞套接字,找出丢失数据的原因,然后相应地调整,然后恢复为非阻塞套接字。或者,您可以处理错误并重试操作。
答案 2 :(得分:1)
我在发送数据时也收到了这个例外,并找到了解决方案。
您得到异常,因为套接字的发送缓冲区已满。因为您尝试通过非阻塞发送来发送数据,所以会引发异常以通知您必须通过阻塞发送来发送数据。
引发异常后不会发送数据,因此您必须重新发送。您的个人发送电话现在变为;
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调用不再抛出异常。
答案 3 :(得分:-1)
这个例外太笼统了。根据MSDN,
如果收到SocketException,请使用 SocketException.ErrorCode 属性获取特定的错误代码。获取此代码后,请参阅MSDN库中的Windows套接字版本2 API错误代码文档,以获取错误的详细说明。
套接字错误代码为here。