Non-blocking socket operation cannot be performed immediately on send

I am writing a server for a game and I want to be able to handle thousands of concurrent users. For this reason, I went with non-blocking sockets and used the polling method. However, I am creating multiple threads to handle databases and web calls, and some of those threads will send a response to the user. On one of these threads, when I submit, I receive the error "Nonblocking socket operation could not be performed immediately." What could be causing this problem? I am assuming this because the poll happens at the same time as the call to send. If I used beginAsync, would this error stop? I was thinking about blocking a socket, but I don't want my main thread to be blocked for this.

+3


source to share


4 answers


I don't know what non-blocking-polling socket calls you are using, but I would recommend using Async socket calls (instead of Begin). For more information on the difference between Async vs Begin calls, see: What is the difference between BeginConnect and ConnectAsync?

Asynchronous calls will automatically "poll" at the OS level, which will be much more efficient than your polling. In fact, they use I / O completion ports, which are probably the fastest and most efficient thing you can use on Windows to handle a lot of client connections / requests.

As far as the error goes, I would think this is normal non-blocking socket operation, so you just need to handle it gracefully.

Update



Perhaps your server should do something like this:

// 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);
    }
}

      

Sample code provided by the code project: http://www.codeproject.com/Articles/22918/How-To-Use-the-SocketAsyncEventArgs-Class

+3


source


When a non-blocking socket tries to read data but finds nothing, you will get this error: The socket would like to wait for data but cannot, because it must return immediately, being non-blocking.



I suggest you switch to blocking sockets, figure out why the data is missing, adjust accordingly, and then switch back to non-blocking. Or you can handle the error and retry the operation.

+1


source


I was also getting this exception when submitting data and just found a solution.

You are getting an exception because the socket send buffer is full. Since you are trying to send data using a non-blocking dispatch, an exception is thrown so you know you MUST send it using a blocking dispatch.

No data is sent after an exception is thrown, so you must resubmit it. Your custom challenge to challenge now becomes:

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;
    }
}

      

It would be nice to increase the SendBufferSize socket. By default I think it is 8kb. For my needs, I had to increase it to 2MB, and then the "Send" call no longer threw this exception.

+1


source


This exception is too general. On MSDN,

If you receive a SocketException, use the SocketException.ErrorCode property to get the specific error code. After you receive this code, refer to the documentation for Windows Sockets version 2 error codes in the MSDN Library for a detailed description of the error.

The socket error codes are here .

-1


source







All Articles