为什么我的 powershell 不读取我通过网络流发送的内容

Why Isn't my powershell reading what I send over the network stream

所以我用 C# 做了一个服务器,它接受套接字连接作为 TCP 客户端。

static void Main(string[] args)
{
    TcpListener listener = new TcpListener(Address, PORT);
    listener.Start();
    var client = listener.AcceptTcpClient();

    Console.WriteLine("Client has connected!");

    while (true)
    {
        Console.Write("Powershell Command: ");
        var cmd = Console.ReadLine();
        client.Client.Send(Encoding.ASCII.GetBytes(cmd));
    }
}

我正在尝试使用 Powershell 连接到它,并且连接正常。

$tcpConnection = New-Object System.Net.Sockets.TcpClient($args[0], $args[1])
$tcpStream = $tcpConnection.GetStream()
$reader = New-Object System.IO.StreamReader($tcpStream)
$writer = New-Object System.IO.StreamWriter($tcpStream)

$buffer = new-object System.Byte[] 1024
$encoding = new-object System.Text.AsciiEncoding 

while ($tcpConnection.Connected)
{
    while ($true)
    {
        $rawresponse = $reader.Read($buffer, 0, 1024)
        $rawresponse.Length
        $response = $encoding.GetString($buffer, 0, $rawresponse)  
        Write-Host $response
    }
}

$reader.Close()
$writer.Close()
$tcpConnection.Close()

问题是当我从服务器发送消息时,powershell 打印出来
0
所以只有一个 1 和一个空白 space。即使我发送字符串 "Test"

这是为什么?以及如何在我发送

时正确地打印出字符串 "Test"

您的代码中存在一些细微的错误:

缓冲区长度

首先,来自 StreamReader.Read(Char[], Int32, Int32) 方法的文档:

Returns

Int32

The number of characters that have been read, or 0 if at the end of the stream and no data was read. The number will be less than or equal to the count parameter, depending on whether the data is available within the stream.

您的 $rawresponse 已经包含写入缓冲区的字符数,因此您不需要使用 $rawresponse.Length。但是,为了让您保持警惕,PowerShell 会自动为所有变量添加默认值 LengthCount 属性,如果它们还没有的话 - 例如:

PS> $x = 4
PS> $x
4
PS> $x.Length
1
PS> $x.Count
1

所以你用行 $rawresponse.Length 输出变量的 PowerShell 的“长度”,而不是写入缓冲区的字符数。 (对于这种行为,我找不到很好的参考,但我相信它基本上是为了帮助处理管道中的对象)。

删除 .Length,您将显示正确的值。

缓冲区类型

另一个问题是这一行:

$buffer = new-object System.Byte[] 1024

如果我们回到 StreamReader.Read(Char[], Int32, Int32) 的文档,它说参数是:

public override int Read (char[] buffer, int index, int count);

请注意缓冲区是 char[],而不是 byte[]。如果您在 C# 中尝试这样做,您会遇到编译器错误,但 PowerShell 会尽力提供帮助,并会在调用 Read 方法时将您的 byte[] 变量转换为临时 char[] 变量。它 不会 ,但是,将结果转换回来并将其放入原始 byte[] 变量中,因此 Read 方法对临时缓冲区所做的任何更改迷路了。

如果您将代码更改为:

$buffer = new-object System.Char[] 1024

您将获得所需的输出,因为原始缓冲区已传递给 Read 方法:

response = 'test'

缓冲区长度(再次)

顺便说一句,你还应该在循环中读取你的缓冲区 为每个命令 直到 Read returns 0 因为不能保证它耗尽在一次读取中流式传输。有关示例,请参见上面 link 中的代码...