如何在 C# 中的同一线程上收听标准输入和套接字?

Posted

技术标签:

【中文标题】如何在 C# 中的同一线程上收听标准输入和套接字?【英文标题】:How to listen to standard in and a socket on the same thread in C#? 【发布时间】:2010-02-05 19:12:56 【问题描述】:

我正在尝试制作一个基于网络控制台的应用程序,但它需要能够同时监听标准输入和来自套接字的输入。在 C++ 中,我会使用 posix select() 函数来执行此操作,但在 C# 中,the equivalent select function 似乎仅用于套接字。有没有一种方法可以在 C# 中同时监听两个输入,而无需借助多个线程?

【问题讨论】:

【参考方案1】:

要等待多个输入,您需要为每个输入一个 WaitHandle,然后调用静态方法 WaitHandle.WaitAny。

但另一种选择是使用异步 IO。使用BeginXXXX 开始读取/接收操作。您在每种情况下都提供一个回调,该回调将在完成时执行。启动它们后,您等待监视器对象,并在回调中脉冲该监视器对象以通知完成。这是一种非常有效的多线程编程形式,但您不必显式启动任何线程。

要获取标准输入的原始流,请使用Console.OpenStandardInput。

【讨论】:

这似乎是一个很好的解决方案,我知道如何使用网络流来做到这一点,但是我如何使用标准输入来做同样的事情呢?【参考方案2】:

我首先要说的是-不,您不能将Select() 用于标准输入。

但是,C# 为您提供了一种更好的方式来收听少数 I\O。

async\await 是一种更好的方法,因为它可以完全避免阻塞,即使对于调用函数也是如此。

在以下示例中,程序侦听 StandardInput with ReadAsync(),同时 PrintStaff() 函数每 3 秒将变量 i 打印到控制台。

示例:

using System;
using System.Threading;
using System.IO;
using System.Text;

namespace AsyncExplore

    class Program
    
        static void Main(string[] args)
        
            ReadFromConsole();
            PrintStaff();
        

        private static void PrintStaff()
        
            int i = 0;
            while (true)
            
                Thread.Sleep(3000);
                Console.WriteLine(i++);
            
        

        private static async void ReadFromConsole()
        
            while(true)
            
                byte[] buffer = new byte[4000];
                
                using Stream stdin = Console.OpenStandardInput();
                
                //read from StandardInput without blocking, so the
                //control yields to Main,
                //and another function can run.
                    int numBytes = await stdin.ReadAsync(buffer, 0, 
                        buffer.Length);
                    
                
                //convert the bytes[] to string
                Console.WriteLine(Encoding.ASCII.GetString(buffer));
            
        
    


优点是

可读性:您可以轻松阅读序列。 编码:编码过程更直观,更接近同步方式。 零线程:您可以将此 Main 作为“侦听器”运行,而无需新线程。与 Select() 不同,Select() 需要您在 Select() 上保持阻塞状态,在这里您可以将整个函数设置为异步,从而将控制权返回给调用方方法。

注意:在示例中,Main() 不是async,为简化起见,因此它在while 循环中被“阻塞”。但是您也可以使PrintStaff() 异步,因此主要,await 在 PrintStaff() 上。在这种情况下,您可以完全解除对线程的阻塞。

【讨论】:

以上是关于如何在 C# 中的同一线程上收听标准输入和套接字?的主要内容,如果未能解决你的问题,请参考以下文章

android - 如何运行2个套接字到同一个IP和端口?

在 C 或 C++ 中的同一个套接字上同时读取和写入

使用套接字的 C# 线程

在收听来自stdin的C输入的同时收听UDP套接字

从不同线程在同一个套接字上发送和接收不起作用

如何在同一视图中收听不同控件上的点击手势?