在发送时无法立即完成非阻塞套接字操作

时间:2012-03-23 18:01:03

标签: c# sockets

我正在为游戏编写服务器,我希望能够处理数千个并发用户。出于这个原因,我选择了非阻塞套接字并使用poll方法。但是,我确实创建了多个线程来处理数据库和Web调用,其中一些线程会向用户发送响应。在其中一个线程中,在发送时,我收到错误“无法立即完成非阻塞套接字操作”。什么可能导致这个问题?我想这是因为调用是在调用send的同时发生的。如果我使用beginAsync,是否需要停止此错误?我想锁定套接字,但我不希望我的主线程被阻止。

4 个答案:

答案 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