Search code examples
powershelltcpstreamreader

Powershell - How to set TCP Send Receive Line End Character? <CR> vs <LF>


I was trying to make a little TCP Client Send and Receive script to send actual date to an industrial camera. The device expects [date]<CR> as end char, and sends back OK<CR> or ER<CR> message.

I've found a base script for send here: https://riptutorial.com/powershell/example/18118/tcp-sender

I've added StreamReader function to it, test with Hercules SETUP Utility and it gives back a return message... if the end char is <LF>... But I need <CR> to send and receive also. Communication manual, page 527.

Function Send-TCPMessage { 
    Param ( 
            [Parameter(Mandatory=$true, Position=0)]
            [ValidateNotNullOrEmpty()] 
            [string] 
            $EndPoint
        , 
            [Parameter(Mandatory=$true, Position=1)]
            [int]
            $Port
        , 
            [Parameter(Mandatory=$true, Position=2)]
            [string]
            $Message
    ) 
    Process {
        # Setup connection 
        $IP = [System.Net.Dns]::GetHostAddresses($EndPoint) 
        $Address = [System.Net.IPAddress]::Parse($IP) 
        $Socket = New-Object System.Net.Sockets.TCPClient($Address,$Port) 
    
        # Setup stream wrtier 
        $Stream = $Socket.GetStream() 
        $Writer = New-Object System.IO.StreamWriter($Stream)
        $Reader = New-Object System.IO.StreamReader($Stream)

        # Write message to stream
        $Message | % {
            $Writer.WriteLine($_)
            $Writer.Flush()
        }

        $Response = $Reader.ReadLine()

        # Close connection and stream
        $Stream.Close()
        $Socket.Close()

        return $Response
    }
}

$retunMessage = Send-TCPMessage -Port 23 -Endpoint 127.0.0.1 -message "My first TCP message !"
Write-Host "Return Message = " $retunMessage

I was trying to test with Hercules SETUP Utility, and Google up the right parameter/setting for modify end character. With no success. Someone could help to identify, what parameters should I set to modify the end char to <CR>?


Solution

    • For writing with System.IO.StreamWriter, set its .NewLine property (before writing to the stream):

      $Writer.NewLine = "`r"  # CR
      
    • For reading with System.IO.StreamReader, you'll have to resort to character-by-character reading:

      # Read a line terminated by a single CR
      $lineBuf = [System.Text.StringBuilder]::new(80)
      while (($codePoint = $Reader.Read()) -ne -1 -and $codePoint -ne 13) {
        $null = $lineBuf.Append([char] $codePoint)
      }
      $Response = $lineBuf.ToString()
      
      • Note:

        • Normally, no extra effort is needed if your lines are terminated with CR only, because a line is defined as (from the System.IO.StreamReader reader's .ReadLine() docs; emphasis added):

          a sequence of characters followed by a carriage return (0x000d), a line feed (0x000a), a carriage return followed by a line feed, Environment.NewLine, or the end-of-stream marker.

          • In other words: CR alone, LF alone, and CRLF are all recognized as newlines.
        • With file input, use of .ReadLine() is sufficient. However, when communicating with devices / intermittent streams, the implication is that .ReadLine() doesn't return until either EOF is reached or at least one additional character after a CR can be read, because it has to examine that additional character for being a LF, given that a CRLF sequence is a newline too.

          • Thus, to prevent reading a line from possibly blocking indefinitely in your case, the character-by-character reading approach shown above is needed.