C#simultanous控制台输入和输出?

我正在编写一个服务器应用程序,我希望它是基于控制台的。 我需要用户能够输入不同的命令,但同时有可能在用户写入时将某些内容输出到控制台。 这会混淆缓冲区。 这样做有什么干净的方法吗?

谢谢。

我开始研究测试程序,以展示如何将控制台划分为输出区域和输入区域,输出区域随着输出区域扩展而输出更多。 它还不完美,但你可以将它发展成你正在寻找的答案:

static int outCol, outRow, outHeight = 10; static void Main(string[] args) { bool quit = false; System.DateTime dt = DateTime.Now; do { if (Console.KeyAvailable) { if (Console.ReadKey(false).Key == ConsoleKey.Escape) quit = true; } System.Threading.Thread.Sleep(0); if (DateTime.Now.Subtract(dt).TotalSeconds > .1) { dt = DateTime.Now; WriteOut(dt.ToString(" ss.ff"), false); } } while (!quit); } static void WriteOut(string msg, bool appendNewLine) { int inCol, inRow; inCol = Console.CursorLeft; inRow = Console.CursorTop; int outLines = getMsgRowCount(outCol, msg) + (appendNewLine?1:0); int outBottom = outRow + outLines; if (outBottom > outHeight) outBottom = outHeight; if (inRow <= outBottom) { int scrollCount = outBottom - inRow + 1; Console.MoveBufferArea(0, inRow, Console.BufferWidth, 1, 0, inRow + scrollCount); inRow += scrollCount; } if (outRow + outLines > outHeight) { int scrollCount = outRow + outLines - outHeight; Console.MoveBufferArea(0, scrollCount, Console.BufferWidth, outHeight - scrollCount, 0, 0); outRow -= scrollCount; Console.SetCursorPosition(outCol, outRow); } Console.SetCursorPosition(outCol, outRow); if (appendNewLine) Console.WriteLine(msg); else Console.Write(msg); outCol = Console.CursorLeft; outRow = Console.CursorTop; Console.SetCursorPosition(inCol, inRow); } static int getMsgRowCount(int startCol, string msg) { string[] lines = msg.Split('\n'); int result = 0; foreach (string line in lines) { result += (startCol + line.Length) / Console.BufferWidth; startCol = 0; } return result + lines.Length - 1; } 

我个人会使用事件处理程序管理一个同时处理输入和输出的控制台,创建一个类ScreenManager或其他什么,在该类中添加一个void RunProgram()方法,创建一个带有处理程序的事件和所需的变量来读取输入键“Console.ReadKey(bool).key”。

 static Consolekey newKey; 

在你的主程序上,创建你的类的实例“whatev你叫它”,然后创建该实例内部方法的线程,Thread coreThread = new Thread(delegate(){myinstance.myProgramMrthod()});

在你的主循环,直到线程启动并运行。 while(!Thread.IsAlive);

然后创建主程序循环。

 while (true) { } 

然后为安全,加入您的自定义线程,以便主程序不会继续,直到自定义线程关闭/处置。

 customThread.Join(); 

你现在有两个线程单独运行。

回到你的class级,在你的事件处理程序方法中创建一个开关。

 switch (newkey) { case Consolekey.enter Console.WriteLine("enter pressed"); break; ect, ect. default: Console.write(newkey); // writes character key that dont match above conditions to the screen. break; } 

坚持allyour逻辑与你想要处理键的方式。 如何在C#中使用多个修饰键可能会有所帮助。

在您的实例的方法RunProgram()或whatev中,您选择调用它,在您完成所需的任何代码之后,创建一个无限循环来检查密钥更改。

 while (true) { newKey = Console.ReadKey(true).Key; if (newKey != oldKey) { KeyChange.Invoke(); } } 

此循环存储按下的任何键,然后检查是否为新键,如果为true则触发事件。

你现在拥有你所寻找的核心,一个循环请求新密钥的字符串,而主循环可以自由显示你想要显示的任何文本。

我能想到的两个可修复的错误,一个是“默认”内部开关将打印到控制台的大写字母或字符串。 另一个是添加到控制台的任何文本都添加到光标点,因此它会添加到用户刚刚输入的文本中。

我会,因为我刚刚创建它,你如何管理文本被添加到控制台。 我再次使用一个事件。 我认为,我可以使用方法和function,但事件会增加程序的灵活性。

好的,所以我们希望能够在控制台上添加文本,而不会让我们输入的输入变得烦乱。 保持输入在底部;

创建一个具有带有字符串参数的签名的新委托,void委托myDelegate(字符串Arg)。 然后用这个委托创建一个事件,称之为newline,newinput,whatev你喜欢。

事件处理程序将采用字符串参数(重新显示控制台更新文本:您要在用户输入上方插入控制台)它将获取用户输入控制台的文本,存储它,然后打印出paramiter字符串到控制台上,然后打印用户输入underneith。

我个人选择在方法之外的顶部创建一个静态字符串,将其初始化为空,因为它经常被使用,你不想创建一个新的标识符,然后每次调用该方法时初始化变量,然后处置它在方法结束时,只是再次重新创建一个新的。

调用字符串“输入”或其他什么。

在keychange事件句柄的默认区域中添加输入+ = newkey。

在Consolekey.enter部分控制台写入输入然后输入= string.empty或string =“”。

在事件处理程序中添加一些逻辑。

 public void OnInsert(string Argument) { Console.CursorTop -= 1; // moves the cursor to far left so new input overwrites the old. // if arg string is longer, then print arg string then print input // string. if (Argument.Length > input.Length) { Console.WriteLine(Argument); Console.WriteLine(input); } else { // if the users input if longer than the argument text then print // out the argument text, then print white spaces to overwrite the // remaining input characters still displayed on screen. for (int i = 0; i < input.Length;i++ ) { if (i < Argument.Length) { Console.Write(Argument[i]); } else { Console.Write(' '); } } Console.Write(Environment.NewLine); Console.WriteLine(input); } } hope this helps some of you, its not perfect, a quick put together test that works enough to be built on. 

如果您需要在用户输入时允许输出到达,我建议将输出发送到新窗口。 因此,您可以拥有一个用于启动应用程序的窗口,然后它生成一个线程以打开一个新的控制台进行输入,然后它继续将任何输出消息发送到原始窗口。 如果您尝试将所有内容保存在同一窗口中,我认为您将遇到太多的资源锁定问题。

如果将服务器视为客户端/服务器应用程序,则此类问题会变得更简单。 让服务器与发送命令和接收输出的客户端管理应用程序建立“n”连接。 客户端应用程序可以完全分离输入和输出,一个线程处理输入,一个处理输出。

如果输入线程正在进入一行中,则输出线程可能会阻塞,而当该行被取消或提交时,输出线程可能会阻塞。

您是否尝试过调用OpenStandardInput ,读取任何输入并重置其位置,然后写入输出流。 然后,您可以再次调用OpenStandardInput并将数据填充回流中。

我认为,没有完美的方法来实现这一目标。 telnet做了什么(至少我使用的最后一个版本)没有打印任何输入(只是读取击键)并且只是在输出到达时打印输出。 另一种方法是在缓冲区中存储需要输出到控制台的任何数据,并且只有在用户输入命令后才打印它。 (你甚至可以给输出添加时间戳,使其更加明显。)我真的看不到更好的选择 – 你不可避免地会遇到使用同步I / O接口(即命令行)和后端的异步操作。