如何在线程应用程序的console.writeline中停止分解console.readline?

时间:2012-09-06 12:14:44

标签: c# .net vb.net console readline

最近,我开始使用VB.Net开发基于多线程控制台的应用程序,并且遇到(可解释的)错误。程序本身是一个服务器,它从不同线程的外部应用程序接收套接字连接。我还有一个单独的线程,它只是等待用户使用console.readline在应用程序中输入文本(这样就可以输入服务器命令,如HELP或STATUS)。

问题是程序从不同的套接字线程输出消息,如果我正在键入命令,它会被分解。如果我输入命令“status”,它将按预期工作,但是对于输入命令的用户,它会被分解,并且他们可能无法看到他们是否输入了错误的命令。例如:

staNew客户连接。
土族

我知道为什么会发生这种情况,但我很好奇是否有一个简单的解决办法来阻止它(不必在输入期间暂停其他线程)或者可能更简单的方法来允许输入控制台命令而不是移动了额外的应用程序输出。

5 个答案:

答案 0 :(得分:1)

一些建议:

  • 撰写邮件 在队列中而不是直接写入控制台。当用户 输入命令,从队列中提取所有最近的消息并转储 他们到控制台。
  • 将消息输出到其他人 控制台的区域,就像旧的BBS风格的聊天UI一样。有一节 消息的页面和另一个用于输入的页面和用户的结果 命令。这需要在控制台方面做更多的工作。
  • 将消息输出到单独的日志文件,用户可以使用tail或类似的东西,a或 应用程序和用户可以同时打开两个应用程序,一个显示 消息和其他交互式运行命令并查看输出。

答案 1 :(得分:1)

C Sharp等价物

using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Timers;

namespace testconsole
{
    class Program
    {
        private static bool Running = true;
        private static string Command = "";

        static void Main( string[] args )
        {
            while ( Running )
            {
                ReadInput();
            }//running
        }//main-----------------------------------------

        static void ReadInput()
        {
            ConsoleKeyInfo cki;

            cki = Console.ReadKey();

            if ( cki.Key == ConsoleKey.Escape )
            {
                Command = "";
            }
            else if (cki.Key == ConsoleKey.Backspace)
            {
                ClearConsole();
                if ( Command.Length > 0 )
                {
                    Command = Command.Substring( 0, Command.Length - 1 );
                }
                Console.CursorLeft = 0;
                Console.Write( Command );
            }
            else if ( cki.Key == ConsoleKey.Enter )
            {
                Console.CursorLeft = 0;
                ClearConsole();
                string TempCommand = Command;
                TextOut( Command );
                Command = "";
                //process tempcommand
                if ( TempCommand  == "quit")
                {
                    Running = false;
                }
                if ( TempCommand == "test" )
                {
                    TextOut("this is a test");
                }
            }
            else
            {
                Command += cki.KeyChar;
                Console.CursorLeft = 0;
                Console.Write( Command );
            }
        }//ReadInput-----------------------------------------

        static void ClearConsole()
        {
            for ( int i = 0; i < Command.Length; i++ )
            {
                Console.Write( " " );
            }
        }//ClearConsole-----------------------------------------

        static void TextOut( string Message )
        {
            if (Command != "")
            {
                ClearConsole();
            }
            Console.CursorLeft = 0;
            Console.WriteLine( Message );
            if ( Message != Command )
            {
                Console.Write( Command );
            }
        }//TextOut-----------------------------------------

    }//program
}//namespace

答案 2 :(得分:1)

这是一个稍微不同的版本,支持readlines上的前缀,并打包到它自己的类中以供重用。它还使用StringBuilder而不是字符串作为readline。

public static class Console2
{
    private static bool _isReading;
    private static string _currentPrefix;
    private static readonly StringBuilder CurrentReadLine = new StringBuilder();

    public static string ReadLine(string prefix = null)
    {
        _currentPrefix = prefix;
        _isReading = true;
        Console.Write(prefix);
        while (true)
        {
            ConsoleKeyInfo cki;

            cki = Console.ReadKey();

            if (cki.Key == ConsoleKey.Escape)
            {
                CurrentReadLine.Clear();
            }
            else if (cki.Key == ConsoleKey.Backspace)
            {
                if (CurrentReadLine.Length > 0)
                {
                    CurrentReadLine.Length--;
                }
                ClearConsole();
                Console.Write(prefix + CurrentReadLine);
            }
            else if (cki.Key == ConsoleKey.Enter)
            {
                Console.WriteLine();
                var result = CurrentReadLine.ToString();
                CurrentReadLine.Clear();
                _isReading = false;
                return result;
            }
            else
            {
                CurrentReadLine.Append(cki.KeyChar);
            }
        }
    }

    static void ClearConsole()
    {
        var length = Console.CursorLeft;
        Console.CursorLeft = 0;

        for (int i = 0; i <= length; i++)
        {
            Console.Write(" ");
        }
        Console.CursorLeft = 0;
    }

    public static void WriteLine(string format, params object[] args)
    {
        ClearConsole();

        Console.WriteLine(format, args);
        if (_isReading)
        {
            Console.Write(_currentPrefix + CurrentReadLine);
        }
    }
}

答案 3 :(得分:0)

使用集中式记录器并在用户输入时禁用输出。

答案 4 :(得分:0)

我知道这个问题大多是美学的,但这样的事情让我很烦。我讨厌回答我自己的问题,但实际上我根据其他人的一些意见想出了一个相当不错的解决方案。我将附上一个代码示例,以防将来有人想要做类似的事情。我知道可能有更好的方法来做到这一点,但这就是我所做的。

基本上我没有使用每个线程的console.writeline,而是创建了一个新的子例程(TextOut),后面有一些逻辑。我还更新了我的输入线程,将每个char读入共享字符串,而不是使用console.readline()。这是代码:

Private command As String = ""

Private Sub ConsoleInput()
    Dim cki As ConsoleKeyInfo
    cki = Console.ReadKey()
    If cki.Key = ConsoleKey.Escape Then
        command = "" 'Clear command
    ElseIf cki.Key = ConsoleKey.Backspace Then
        If Len(command) > 0 Then 'Make sure you don't go out of bounds
            For i As Integer = 0 To Len(command)
                Console.Write(" ") 'Clear output since new string will be shorter
            Next
            command = Left(command, Len(command) - 1) 'Shorten command by 1 char
        End If
        Console.CursorLeft = 0 'Set the cursor to the beginning of the line
        Console.Write(command) 'Write the command to the screen
    ElseIf cki.Key = ConsoleKey.Enter Then 'Command has been submitted, start checking
        Console.CursorLeft = 0 'Set the cursor to the beginning of the line
        For i As Integer = 0 To Len(command)
            Console.Write(" ") 'Clear output from command (hides the executed command)
        Next
        Dim tempCMD As String = command
        command = ""

        'If/then statements for validating command goes here

        command = "" 'Clear command to allow new input
    Else
        command += cki.KeyChar 'Add char to command string
        Console.CursorLeft = 0 'Set the cursor to the beginning of the line
        Console.Write(command) 'Write the command to the screen
    End If
    ConsoleInput() 'Loop for more input 
End Sub


Sub TextOut(ByVal message As String)
    If command <> "" Then
        For i As Integer = 0 To Len(command)
            Console.Write(" ") 'Clears output in case output is shorter than current command
        Next
        Console.CursorLeft = 0 'Sets cursor to beginning of row
    End If
    Console.WriteLine(message) 'Writes the current message to the screen
    If message <> command Then
        Console.Write(command) 'Writes the command back to the screen
    End If
End Sub