You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Socket关闭旧连接后接受新连接时ReceiveAsync抛出‘SocketAsyncEventArgs实例已存在异步操作’异常的问题求助

Why You're Seeing That "Asynchronous Socket Operation In Progress" Error

Let's break down exactly what's going wrong with your TCP echo server, then walk through step-by-step fixes to get it working reliably.

The Root Cause

Your code hits this error because you're reusing the same SocketAsyncEventArgs instance for multiple asynchronous operations—a strict no-no in .NET's SocketAsync model. Here's the play-by-play:

  1. When the first client connects, you create one readEventArgs in AcceptCallback and loop trying to call ReceiveAsync with it.
  2. When that client disconnects, you call accept() to wait for a new connection—but the original infinite while loop in AcceptCallback keeps running, still trying to use that same readEventArgs instance.
  3. When a new client connects, the old readEventArgs might still be tied to the dead client socket, or might still have an unfinished asynchronous operation in flight. Trying to reuse it triggers the exception.

On top of that, your loop logic for accepting connections and receiving data is broken:

  • The while(true) in accept() is unnecessary and blocks the thread from handling async events properly.
  • The infinite loop in AcceptCallback keeps trying to receive even after the client has disconnected.

Step-by-Step Fixes

Let's rewrite the problematic parts to follow async socket best practices.

1. Fix the accept() Method (Remove the Dead Loop)

AcceptAsync is designed to be asynchronous—you don't need to loop indefinitely. Instead, after handling a new connection, just re-initiate AcceptAsync to wait for the next one:

void accept()
{
    SocketAsyncEventArgs e = new SocketAsyncEventArgs();
    e.Completed += e_Completed;
    
    // Initiate async accept; if it completes synchronously, handle immediately
    bool raiseEvent = serverSocket.AcceptAsync(e);
    if (!raiseEvent)
    {
        AcceptCallback(e);
    }
}

2. Use Independent SocketAsyncEventArgs Per Client

Never reuse an SocketAsyncEventArgs instance across multiple operations or clients. Create a new one for each client's receive/send operations, and attach the client socket to the UserToken property to track it in callbacks:

private void AcceptCallback(SocketAsyncEventArgs e)
{
    // Immediately start waiting for the next connection (supports multiple concurrent clients)
    accept();

    Socket clientSocket = e.AcceptSocket;
    if (clientSocket == null) return;

    // Create a unique args instance for this client's receive operations
    SocketAsyncEventArgs readEventArgs = new SocketAsyncEventArgs();
    byte[] buffer = new byte[1024];
    readEventArgs.SetBuffer(buffer, 0, buffer.Length);
    readEventArgs.UserToken = clientSocket; // Attach client socket for later use
    readEventArgs.Completed += readEventArgs_Completed;

    // Start first receive operation
    bool raiseEvent = clientSocket.ReceiveAsync(readEventArgs);
    if (!raiseEvent)
    {
        ReceiveCallback(readEventArgs);
    }
}

3. Update ReceiveCallback to Handle Echo and Cleanup

When data is received, send it back asynchronously, and when the client disconnects, clean up resources properly:

private void ReceiveCallback(SocketAsyncEventArgs e)
{
    Socket clientSocket = e.UserToken as Socket;
    if (clientSocket == null) return;

    try
    {
        if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success)
        {
            // Create args for the echo send operation
            SocketAsyncEventArgs sendEventArgs = new SocketAsyncEventArgs();
            sendEventArgs.SetBuffer(e.Buffer, 0, e.BytesTransferred);
            sendEventArgs.UserToken = clientSocket;
            sendEventArgs.Completed += sendEventArgs_Completed;

            bool raiseEvent = clientSocket.SendAsync(sendEventArgs);
            if (!raiseEvent)
            {
                SendCallback(sendEventArgs);
            }
        }
        else
        {
            // Client disconnected; clean up resources
            clientSocket.Shutdown(SocketShutdown.Both);
            clientSocket.Close();
            e.Dispose();
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine($"Receive error: {ex.Message}");
        clientSocket?.Close();
        e.Dispose();
    }
}

4. Implement SendCallback to Resume Receiving

After sending the echo, initiate a new receive operation so the client can send more data:

void sendEventArgs_Completed(object sender, SocketAsyncEventArgs e)
{
    SendCallback(e);
}

private void SendCallback(SocketAsyncEventArgs e)
{
    Socket clientSocket = e.UserToken as Socket;
    if (clientSocket == null) return;

    try
    {
        if (e.SocketError == SocketError.Success)
        {
            // Prepare for next receive
            SocketAsyncEventArgs readEventArgs = new SocketAsyncEventArgs();
            byte[] buffer = new byte[1024];
            readEventArgs.SetBuffer(buffer, 0, buffer.Length);
            readEventArgs.UserToken = clientSocket;
            readEventArgs.Completed += readEventArgs_Completed;

            bool raiseEvent = clientSocket.ReceiveAsync(readEventArgs);
            if (!raiseEvent)
            {
                ReceiveCallback(readEventArgs);
            }
        }
        else
        {
            // Send failed; close the connection
            clientSocket.Shutdown(SocketShutdown.Both);
            clientSocket.Close();
        }
        e.Dispose();
    }
    catch (Exception ex)
    {
        Console.WriteLine($"Send error: {ex.Message}");
        clientSocket?.Close();
        e.Dispose();
    }
}

5. Remove the Unnecessary ManualResetEvent

The allDone event was used to sync the old infinite loop, but now we're using async callbacks to drive the flow—you can safely delete it from your code.

Final Notes

With these changes, your server will:

  • Handle multiple concurrent clients correctly
  • Allow clients to disconnect and reconnect without throwing errors
  • Properly clean up resources when clients disconnect

内容的提问来源于stack exchange,提问作者Ristea Stefan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.01 00:07:30