【问题标题】:Proper implementation of multi-threaded + socket application多线程+socket应用的正确实现
【发布时间】:2011-07-10 18:34:38
【问题描述】:

我有一个服务器和一个客户端应用程序,下面是它当前的实现方式:服务器有一个循环,在它自己的线程中,它通过 TcpListener 监听新连接。如果有人连接,它会将 TcpClient 传递给一个循环,该循环专门监听该 TcpClient,并通过 NetworkStream 处理与该用户的所有交互。

在客户端,我有一个连接到服务器的 TcpClient。我的理解是我需要将它分支到不同的线程,因为任何 IO 都会将其置于阻塞模式,我不能让它停止主线程。

到目前为止,我理解正确吗?有没有更简单的方法来确保异步通信而无需停止任一程序的主线程?

无论哪种方式,对于我的主要问题:如何确保所有这些线程和套接字都得到正确处理?如果程序在仍处于阻塞模式时退出,它似乎会冻结。那么如何中止套接字上的所有 IO 并告诉子线程中的无限循环我们已经完成了?

顺便说一句,这也是一个 Unity3d 项目,以防万一发生任何变化。

【问题讨论】:

    标签: c# multithreading networking unity3d


    【解决方案1】:

    将每个新连接移交给自己的线程可能会限制您的可扩展性。此外,没有理由要求客户端中的 I/O 进行线程切换。

    您可以使用异步 I/O 解决这两个问题。 BeginConnect/EndConnect 在客户端,BeginRead/EndRead, BeginWrite/EndWrite 在服务器端用于读写。

    然后一切都可以由事件驱动,而无需您自己的新线程。连接完成首先触发异步读取,然后每个读取完成都会在该套接字上发布一个新的异步读取调用 - 无论如何,写入始终是由您的 POV 确定的。

    关闭您的套接字将导致挂起的读取/写入操作退出并出现错误,然后您应该能够干净地退出该进程。请注意实施适当的锁定(可能只需要lock())以确保套接字在关闭后不会在任何地方使用。

    【讨论】:

    • 你给了我很多研究!谢谢,我想我可能在做一些非常不切实际的事情。
    【解决方案2】:

    您应该有两个单独的线程,一个用于TcpListener,另一个用于在其上运行的TcpClient。初始化新线程时,将其IsBackground 属性设置为true,这样如果应用程序终止,它也会终止。

    Thread listenerThread = new Thread(ListenerLoop);
    listenerThread.IsBackground = true;
    listernerThread.Start();
    

    如果您使用 4.0 或 ThreadPool.QueueUserWorkItem 代替线程,则可以使用 Task

    【讨论】:

    • 不是说N+1个线程吗?一个给听众,一个给每个客户?
    • @EJP:是的,每个 tcpClient 一个。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-08-23
    • 1970-01-01
    • 1970-01-01
    • 2020-01-01
    • 1970-01-01
    • 2011-07-25
    • 2015-10-27
    相关资源
    最近更新 更多