开发者

How to listen to standard in and a socket on the same thread in C#?

I'm trying to make a networked console based application, but it needs to be able to listen to standard input and input from a socket at the same time. In C++ I 开发者_如何学JAVAwould use the posix select() function to do this, but in C# it appears that the equivalent select function is for sockets only. Is there a way I can listen to both inputs in C# without resorting to multiple threads?


To wait on multiple inputs, you need a WaitHandle for each one, and then you call the static method WaitHandle.WaitAny.

But another option is to use async IO. Use the BeginXXXX to start read/receive operations. You supply a callback in each case which will be executed on completion. After you launch them, you wait on a monitor object, and in the callbacks you pulse that monitor object to notify completion. This is a very efficient form of multi-threading programming but you don't have to start any threads explicitly.

To get a raw Stream for standard input, use Console.OpenStandardInput.


I will start by saying that- no, you can not use Select() for StandardInput.

But, C# gives you a better way to listen to few I\O.

The async\await is a better way, because it lets to avoid blocking at all, even for the calling function.

In the following example, the program listening to the StandardInput with ReadAsync(), and in the meantime the PrintStaff() function prints the variable i to the console every 3 seconds.

example:

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

The advantages are

  • Readabilty: you can read the sequence easily.
  • Coding: The coding process is much more intuitive and close to the synchronous way.
  • Zero-threaded: You can run this Main as a "Listener" without the need of new thread. Unlike Select(), which requires you to stay blocked on Select(), here you can set the whole function as asynchronous, thus returning the control to caller method.

Note: In the example, Main() is not async, to simplify things, so it get "blocked" in the while loop. But you can make PrintStaff() async as well, and so the main, and await on PrintStaff(). In this case you are perfectly un-blocking the thread.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜