【问题标题】:Is BeginAcceptTcpClient thread safe? C#BeginAcceptTcpClient 线程安全吗? C#
【发布时间】:2019-09-20 11:26:12
【问题描述】:

我从TCP Asynchronous 服务器的世界开始,寻找一种同时处理多个连接的方法,我发现BeginAcceptTcpClient 可能是一个解决方案。

我找到了两种可能的方法来在服务器启动时使用BeginAcceptTcpClient 来接收连接。我的问题是:这两者之间有什么区别,哪一个是线程安全的(或者两者都是)。

第一路

在回调中调用BeginAcceptTcpClient。

static TcpListener socket = new TcpListener(IPAddress.Any, 4444);

public static void InitNetwork()
        {
            socket.Start();
            socket.BeginAcceptTcpClient(new AsyncCallback(OnClientConnect), null);
        }

private static void OnClientConnect(IAsyncResult ar)
        {
            TcpClient newclient = socket.EndAcceptTcpClient(ar);
            socket.BeginAcceptTcpClient(new AsyncCallback (OnClientConnect), null); // Call the Callback again to continue listening

            HandleClient.CreateConnection(newclient); //Do stuff with the client recieved
        }

第二种方式

使用AutoResetEvent。

static TcpListener socket = new TcpListener(IPAddress.Any, 4444);
private AutoResetEvent connectionWaitHandle = new AutoResetEvent(false);

public static void InitNetwork()
        {
            socket.Start();

            while(true)
            {
              socket.BeginAcceptTcpClient(new AsyncCallback(OnClientConnect), null);
              connectionWaitHandle.WaitOne(); // Wait until a client has begun handling an event
              connectionWaitHandle.Reset(); // Reset wait handle or the loop goes as fast as it can (after first request)
            }

        }

private static void OnClientConnect(IAsyncResult ar)
        {
            TcpClient newclient = socket.EndAcceptTcpClient(ar);
            connectionWaitHandle.Set(); //Inform the main thread this connection is now handled

            HandleClient.CreateConnection(newclient);  //Do stuff with the client recieved
        }

我正在寻找处理多个连接的正确方法(线程安全)。我很感激任何答案。

【问题讨论】:

    标签: c# .net multithreading tcp


    【解决方案1】:

    我更喜欢AcceptTcpClientAsync。它比BeginAcceptTcpClient 更简单,并且仍然是异步的。

    public async Task InitNetwork()
    {
        while( true )
        {
            TcpClient newclient = await socket.AcceptTcpClientAsync();
            Task.Run( () => HandleClient.CreateConnection( newclient ) );
        }
    }
    

    在内部,AcceptTcpClientAsync 使用Task.Factory.FromAsync 将BeginAcceptTcpClient 和EndAcceptTcpClient 包装到一个Task 对象中。

    public Task<TcpClient> AcceptTcpClientAsync()
    {
        return Task<TcpClient>.Factory.FromAsync(BeginAcceptTcpClient, EndAcceptTcpClient, null);
    }
    

    【讨论】:

    • 感谢您的推荐。 AcceptTcpClientAsync 线程安全吗?如果两个客户端同时连接会发生什么?我搜索并看到有些使用“if (task.IsFaulted) / task.Wait();”在 AcceptTcpClientAsync 之后。再次感谢您。
    • 我在我的项目中使用此方法在我的一个项目中管理多线程环境中的多个客户端,并且效果很好。防止在异步环境中使用task.Wait或其他同步的task方法,如果想捕获异常,可以在await AcceptTcpClientAsync 附近使用try-catch。
    • 如何使用Task类和async-await是一个很大的话题。如果您对这些东西的工作原理或如何正确使用它们感兴趣,请谷歌 async-await 或任务并行库
    • await 应该在 Task.Run 之前吗?我用谷歌搜索并找到了两种方法。在代码中显示此更正:[link] (docs.microsoft.com/en-us/dotnet/visual-basic/language-reference/…)
    • 如果您想等到任务完成,请使用 await。我猜CreateConnection 应该是 fire&forget 所以我没有使用 await
    猜你喜欢
    • 1970-01-01
    • 2021-01-15
    • 2010-11-24
    • 2019-05-23
    • 2011-01-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多