如何使用PowerShell连接到TCP套接字以发送和接收数据?

15

我写了一个小的Powershell脚本。

它使用 .Net System.IO.StreamReader 和 System.IO.StreamWriter 来从/向TCP套接字读取和写入数据。

我想要用telnet方式连接到套接字并发送/接收命令。

我正在尝试使用System.IO.StreamReader中的ReadLine()方法读取行,但来自服务器的数据可能没有及时到达(?)或者我不知道。我没有使用异步命令。请帮忙解决这个问题!

以下是我的脚本:

$FTPServer = "localhost"
$FTPPort = "21"

$tcpConnection = New-Object System.Net.Sockets.TcpClient($FTPServer, $FTPPort)
$tcpStream = $tcpConnection.GetStream()
$reader = New-Object System.IO.StreamReader($tcpStream)
$writer = New-Object System.IO.StreamWriter($tcpStream)
$writer.AutoFlush = $true

while ($tcpConnection.Connected)
{
    while ($tcpStream.DataAvailable)
    {
        $reader.ReadLine()
    }

    if ($tcpConnection.Connected)
    {
        Write-Host -NoNewline "prompt> "
        $command = Read-Host

        if ($command -eq "escape")
        {
            break
        }

        $writer.WriteLine($command) | Out-Null
    }
}

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

这里是输出结果:

PS C:\Windows\System32\WindowsPowerShell\v1.0> test.ps1
220 Microsoft FTP Service
prompt> user username
331 Password required
prompt> pass password
230-Directory has 58,145,996,800 bytes of disk space available.
prompt> 
230 User logged in.
500 Command not understood.
prompt> help
214-The following commands are recognized (* ==>'s unimplemented).
    ABOR 
    ACCT 
    ADAT *
    ALLO 
    APPE 
    AUTH 
    CCC 
    CDUP 
    CWD 
    DELE 
    ENC *
    EPRT 
    EPSV 
    FEAT 
    HELP 
    HOST 
    LANG 
    LIST 
    MDTM 
    MIC *
    MKD 
    MODE 
    NLST 
    NOOP 
    OPTS 
    PASS 
    PASV 
    PBSZ 
    PORT 
    PROT 
    PWD 
    QUIT 
    REIN 
    REST 
    RETR 
    RMD 
    RNFR 
    RNTO 
    SITE 
prompt> escape

PS C:\Windows\System32\WindowsPowerShell\v1.0>

这里有一个例子(http://www.leeholmes.com/blog/2009/10/28/scripting-network-tcp-connections-in-powershell/)。它使用缓冲区实现IO。我认为在你的代码中,当等待用户输入时,你错过了TCP输入。此外,这个例子(http://thesurlyadmin.com/2013/04/04/using-powershell-as-a-telnet-client/)也是使用缓冲区实现的。 - Jan Chrbolka
4个回答

16

尝试使用缓冲区读取响应。代码如下所示:

$tcpConnection = New-Object System.Net.Sockets.TcpClient($FTPServer, $FTPPort)
$tcpStream = $tcpConnection.GetStream()
$reader = New-Object System.IO.StreamReader($tcpStream)
$writer = New-Object System.IO.StreamWriter($tcpStream)
$writer.AutoFlush = $true

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

while ($tcpConnection.Connected)
{
    while ($tcpStream.DataAvailable)
    {

        $rawresponse = $reader.Read($buffer, 0, 1024)
        $response = $encoding.GetString($buffer, 0, $rawresponse)   
    }

    if ($tcpConnection.Connected)
    {
        Write-Host -NoNewline "prompt> "
        $command = Read-Host

        if ($command -eq "escape")
        {
            break
        }

        $writer.WriteLine($command) | Out-Null
    }
    start-sleep -Milliseconds 500
}

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

3

我尝试了所有的解决方案... Chris的建议很有帮助,需要检查是否还有来自读者的信息。现在它可以正常工作了。

$FTPServer = "localhost"
$FTPPort = "21"

$tcpConnection = New-Object System.Net.Sockets.TcpClient($FTPServer, $FTPPort)
$tcpStream = $tcpConnection.GetStream()
$reader = New-Object System.IO.StreamReader($tcpStream)
$writer = New-Object System.IO.StreamWriter($tcpStream)
$writer.AutoFlush = $true

while ($tcpConnection.Connected) {
    while ($tcpStream.DataAvailable -or $reader.Peek() -ne -1 ) {
        $reader.ReadLine()
    }

    if ($tcpConnection.Connected) {
        Write-Host -NoNewline "prompt> "
        $command = Read-Host

        if ($command -eq "escape") {
            break
        }

        $writer.WriteLine($command) | Out-Null
        Start-Sleep -Milliseconds 10
    }
}

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

这里是输出:

220 Microsoft FTP Service
prompt> user username
331 Password required
prompt> pass password
230 User logged in.
prompt> help
214-The following commands are recognized (* ==>'s unimplemented).
    ABOR 
    ACCT 
    ADAT *
    ALLO 
    APPE 
    AUTH 
    CCC 
    CDUP 
    CWD 
    DELE 
    ENC *
    EPRT 
    EPSV 
    FEAT 
    HELP 
    HOST 
    LANG 
    LIST 
    MDTM 
    MIC *
    MKD 
    MODE 
    NLST 
    NOOP 
    OPTS 
    PASS 
    PASV 
    PBSZ 
    PORT 
    PROT 
    PWD 
    QUIT 
    REIN 
    REST 
    RETR 
    RMD 
    RNFR 
    RNTO 
    SITE 
    SIZE 
    SMNT 
    STAT 
    STOR 
    STOU 
    STRU 
    SYST 
    TYPE 
    USER 
    XCUP 
    XCWD 
    XMKD 
    XPWD 
    XRMD 
214 HELP command successful.
prompt> list
150 Opening ASCII mode data connection.
425 Cannot open data connection.
prompt> escape

PS C:\Users\gazsiazasz>

2
我发现仅使用NetworkStream DataAvailable属性是不够的,需要在进入第二个while循环之前进行一些推动。我已经测试过了,当通过telnet连接到CISCO设备时,它可以完美地工作。
$routerAddress = "192.168.10.126"
$port = "23"
$tcp = New-Object System.Net.Sockets.TcpClient($routerAddress,$Port)
$tcpstream = $tcp.GetStream()
$reader = New-Object System.IO.StreamReader($tcpStream)
$writer = New-Object System.IO.StreamWriter($tcpStream)
$writer.AutoFlush = $true

while ($tcp.Connected)
{       
    write-host ([char]$reader.Read()) -NoNewline

    while(($reader.Peek() -ne -1) -or ($tcp.Available)){        
        write-host ([char]$reader.Read()) -NoNewline
    }

    if ($tcp.Connected)
    {
        Write-Host -NoNewline "_"
        $command = Read-Host

        if ($command -eq "escape")
        {
            break
        }
        $writer.WriteLine($command) | Out-Null
    }     
}

$reader.Close()
$writer.Close()
$tcp.Close()

0
你的read line卡住的原因可能是因为你没有用'\n'来终止发送的字符串。
客户端代码:
[System.Net.Sockets.TcpClient] $tcpClient = [System.Net.Sockets.TcpClient]::new("localhost", "50001")

$tcpStream = $tcpClient.GetStream()
[System.IO.StreamReader] $reader = [System.IO.StreamReader]::new($tcpStream)
[System.IO.StreamWriter] $writer = [System.IO.StreamWriter]::new($tcpStream)

while ($tcpClient.Connected) {
    while ($tcpStream.DataAvailable) {
        $res = $reader.ReadLine()
        Write-Host $res
    }
}

服务器代码(nodejs)

const server = net.createServer(socket => {
    socket.write(
        "Testing !" +
            socket.remoteAddress +
            ":" +
            socket.remotePort +
            "\n"
    );
    socket.pipe(socket);
    console.log("Client connected!");
});
server.listen(50001, "localhost");

它只是工作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接