Delay when displaying a message received by a Telnet client - vb.net

I am trying to implement a Telnet client in VB.NET. I am following this code as example:
The program I'm implementing works as follows:
I click the button "Open Telnet" to open the Telnet session.
I write an instruction (string) in the text box on the left and then I click on Button1 to send the message to a Telnet server (an electronic board with an embedded Ethernet port).
The answer sent by the Telnet server is displayed in the text box on the left.
The problem I'm having with both the example and the implementation I'm doing is that the messages are displayed delayed. For example, if I send the string 1FFFFFF + vbCrLf I am supposed to receive a message from the server saying Unknown HMI code!. I have checked with Wireshark that the message is sent by the Telnet server just after I sent the instruction with the VB.NET program but it is shown in the text box on the right only if I click Button1 a second time (no matter what is written in the text box on the left).
Could you please tell me if there is something I'm missing in the code?
Below is my code:
Imports System
Imports System.IO
Imports System.Net.Sockets
Imports System.Security.Cryptography.X509Certificates
Imports System.Text
Imports System.Threading
Imports System.Net.Http
Imports System.Net.Security
Imports System.Net.IPAddress
Imports System.Net
Public Class Form1
' Create a TcpClient.
Dim client As New TcpClient
Dim stream As NetworkStream
' Function to write/read a TCP stream.
Shared Sub Connect(server As [String], message As [String])
Try
' Translate the passed message into ASCII and store it as a Byte array.
Dim data As [Byte]() = System.Text.Encoding.ASCII.GetBytes(message)
' Send the message to the connected TcpServer.
Form1.stream.Write(data, 0, data.Length)
Console.WriteLine("Sent: {0}", message)
' Buffer to store the response bytes.
data = New [Byte](256) {}
' String to store the response ASCII representation.
Dim responseData As [String] = [String].Empty
' Read the first batch of the TcpServer response bytes.
Dim bytes As Int32 = Form1.stream.Read(data, 0, data.Length)
responseData = System.Text.Encoding.ASCII.GetString(data, 0, bytes)
Console.WriteLine("Received: {0}", responseData)
Form1.TelnetRx.Text += responseData + vbCrLf
Form1.TelnetRx.Refresh()
Catch e As ArgumentNullException
Console.WriteLine("ArgumentNullException: {0}", e)
Catch e As SocketException
Console.WriteLine("SocketException: {0}", e)
End Try
Console.WriteLine(ControlChars.Cr + " Press Enter to continue...")
Console.Read()
End Sub
' Function to open a Telnet session.
Public Function OpenTelnetSession(server As String, Port As Int32) As Boolean
Dim ipAddress As IPAddress = Parse(server)
client.Connect(ipAddress, Port)
stream = Me.client.GetStream()
Return True
End Function
' Button to send a message.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Connect("192.168.8.110", TCP_Order.Text + vbCrLf)
End Sub
' Button to open the Telnet session.
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles OpenTelnet.Click
OpenTelnetSession("192.168.8.110", 10001)
End Sub
' Button to close the Telnet session.
Private Sub CloseTelnet_Click(sender As Object, e As EventArgs) Handles CloseTelnet.Click
End Sub
End Class

That because you are not reading the entire buffer of the response, you are just taking 256 bytes from it:
data = New [Byte](256) {} ' <-
Also you have to free the resource by closing the streams and the TcpClient once you receive the response. Always create the disposable objects by the Using statement to guarantee that.
Synchronous Example
The example below connects to an endpoint in synchronous blocking mode, the caller thread is blocked until a response is returned from the endpoint or an exception is thrown (connection timeout for example.)
Private Function Connect(server As String, port As Integer, Msg As String) As String
Using client As New TcpClient(server, port),
netStream = client.GetStream,
sr = New StreamReader(netStream, Encoding.UTF8)
Dim msgBytes = Encoding.UTF8.GetBytes(Msg)
netStream.Write(msgBytes, 0, msgBytes.Length)
Return sr.ReadToEnd
End Using
End Function
and the caller:
Private Sub TheCaller()
Dim resp As String = Nothing
Try
Dim server = "192.168.8.110"
Dim port = 10001
Dim msg = $"1FFFFFF{ControlChars.CrLf}{ControlChars.CrLf}"
resp = Connect(server, port, msg)
Catch ex As ArgumentNullException
resp = ex.Message
Catch ex As SocketException
resp = ex.SocketErrorCode.ToString
Catch ex As Exception
resp = ex.Message
Finally
If resp IsNot Nothing Then
UpdateStatus(resp)
End If
End Try
End Sub
Asynchronous Example
You may want to use an asynchronous operation since you are developing a WinForms application, and I don't think you want to block the UI thread. Here you need to call the Async methods of the TcpClient and the read/write streams:
Private Async Function ConnectAsync(server As String,
port As Integer, msg As String) As Task(Of String)
Using client As New TcpClient
Await client.ConnectAsync(server, port)
Using netStream = client.GetStream,
sw = New StreamWriter(netStream, Encoding.UTF8) With {.AutoFlush = True },
sr = New StreamReader(netStream, Encoding.UTF8)
Await sw.WriteLineAsync(msg)
Return Await sr.ReadToEndAsync()
End Using
End Using
End Function
and an Async caller:
Private Async Sub TheCaller()
Dim resp As String = Nothing
Try
Dim server = "192.168.8.110"
Dim port = 10001
Dim msg = $"1FFFFFF{ControlChars.CrLf}{ControlChars.CrLf}"
resp = Await ConnectAsync(server, port, msg)
Catch ex As ArgumentNullException
resp = ex.Message
Catch ex As SocketException
resp = ex.SocketErrorCode.ToString
Catch ex As Exception
resp = ex.Message
Finally
If resp IsNot Nothing Then
UpdateStatus(resp)
End If
End Try
End Sub
The UpdateStatus in the code snippets is just a method to append the responses into a TextBox..
Private Sub UpdateStatus(txt As String)
StatusTextBox.AppendText(txt)
StatusTextBox.AppendText(ControlChars.NewLine)
End Sub

Related

TCP server, why is the send message / string not recognized correctly?

This code is for a TCP server that executes something if a certain message is received.
My problem is that the received string doesn’t match the one inside the If statement.
If txt = "reset" Then
Label2.Text = "merda"
End If
Label1.Text = txt
All the messages I send are displayed in Label1 correctly but if I send the "reset" the IF statement doesn’t recognize the string and display "merda" on the label2.
There must be something else hidden in the string along with the display text but I don’t seem to understand what.
I’m using Hercules by HW Group to as client to send the messages. I’ve tried other software but the result is always the same
I ask for your advice fixing this.
Thanks
Imports System.Net
Imports System.Net.Sockets
Imports System.Text
Public Class Form1
Dim _server As TcpListener
Dim _listOfClients As New List(Of TcpClient)
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Try
_server = New TcpListener(IPAddress.Parse("127.0.0.1"), 1234)
_server.Start()
Threading.ThreadPool.QueueUserWorkItem(AddressOf NewClient)
Catch ex As Exception
MsgBox(ex.Message)
End Try
CheckForIllegalCrossThreadCalls = False
End Sub
Private Sub NewClient(state As Object)
Dim client As TcpClient = _server.AcceptTcpClient()
Try
_listOfClients.Add(client)
Threading.ThreadPool.QueueUserWorkItem(AddressOf NewClient)
While True
Dim ns As NetworkStream = client.GetStream()
Dim toReceive(1000) As Byte
ns.Read(toReceive, 0, toReceive.Length)
Dim txt As String = Encoding.ASCII.GetString(toReceive)
If txt = "reset" Then
Label2.Text = "merda"
End If
Label1.Text = txt
End While
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub
End Class

VB.NET TcpListener FORM NOT SHOWING

i'm using the above code to run a form with a tcplistener.
when the tcplistener recevie data from the client i need to write the data in in label1.text
i have tryed to use Shown instead of Load the form is showed but it the label text doesn't change.
How can i resolve this? any help will be appreciated.
thank you
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
TcpServer()
End Sub
Shared Sub TcpServer()
Dim server As TcpListener
server = Nothing
Try
Dim port As Int32 = 4000
Dim localAddr As IPAddress = IPAddress.IPv6Any 'IPAddress.Parse("192.168.61.9") 'IPAddress.Any
server = New TcpListener(localAddr, port)
server.Start()
Dim bytes(1024) As Byte
Dim data As String = Nothing
While True
Console.WriteLine("Waiting for a connection... ")
Dim client As TcpClient = server.AcceptTcpClient()
Console.WriteLine("Connected!")
data = Nothing
Dim stream As NetworkStream = client.GetStream()
Dim i As Int32
' Loop to receive all the data sent by the client.
i = stream.Read(bytes, 0, bytes.Length)
While (i <> 0)
' Translate data bytes to a ASCII string.
data = System.Text.Encoding.ASCII.GetString(bytes, 0, i)
Form1.Label1.Text = data
' Process the data sent by the client.
'data = data.ToUpper()
data = "aaa"
Dim msg As Byte() = System.Text.Encoding.ASCII.GetBytes(data)
' Send back a response.
stream.Write(msg, 0, msg.Length)
Console.WriteLine("Sent: {0}" + data)
i = stream.Read(bytes, 0, bytes.Length)
End While
' Shutdown and end connection
client.Close()
Form1.Refresh()
End While
Catch e As SocketException
MsgBox("SocketException: {0}", e.ToString)
Finally
server.Stop()
End Try
Console.WriteLine(ControlChars.Cr + "Hit enter to continue....")
Console.Read()
End Sub 'Main
Run TcpServer() on a new thread, or make use of BackGroundWorker Control which is part of winForms controls.

TCP / IP freezes if I un-listen without client connected to the server

I have a working TCP / IP server that can listen to one or many clients, it is working great! It can received and send data from one client.
My problem is whenever I clicked the listen button then un-listen by clicking again the button my application freeze. The only way to free my application from this freeze is to connect another client while my system is still in the process of un-listening.
The second problem involves receiving data from multiple clients, yes it can listen and allow multiple clients to be connected to the server but it doesn't received all the messages sent by the client, it only receives the message of the first client.
Here's what my system look like.
And here's my code
Imports System.Net.Sockets
Imports System.Net
Imports System.Threading 'Imports Threading Namespace
Imports System.Text
Imports System.Reflection
Public Class Form1
Dim stream As NetworkStream
Dim client As TcpClient
Dim port As Int32
Dim localAddr As IPAddress = IPAddress.Any
Dim server As TcpListener
Dim tcpClientThread As System.Threading.Thread
Dim PublicIP = String.Empty 'The IP and Port of the Client that connects to port 7700
Private Sub Tcpclient()
port = NUD_Tcp_Port.Value
' The statement of TCPClient function
server = Nothing
' Buffer for reading data
Dim bytes(1024) As Byte
Try
server = New TcpListener(localAddr, port) 'Set the TcpListener on port 13000.
server.Start() 'Start listening for client requests.
writeData(Server_IP_Port) 'Outputs the server's ip and port listening
'Perform a blocking call to accept requests.
'You could also user server.AcceptSocket() here.
client = server.AcceptTcpClient()
writeData("Connected: " & Client_IP_Port())
Dim data As String = Nothing 'The data we received from client, set the default value to nothing
stream = client.GetStream() 'Get a stream object for reading and writing
Dim i As Int32 = stream.Read(bytes, 0, bytes.Length) 'Loop to receive all the data sent by the client.
While (i <> 0)
'Translate data bytes to a ASCII string.
data = Encoding.ASCII.GetString(bytes, 0, i)
writeData("Received: " & data)
'Process the data sent by the client.
data = data.ToUpper()
Dim msg As Byte() = Encoding.ASCII.GetBytes(data)
i = stream.Read(bytes, 0, bytes.Length)
End While
Catch haha As SocketException
Console.WriteLine("SocketException: {0}", haha)
Finally
'server.Stop()
End Try
End Sub
Function Client_IP_Port() As String 'Gets the IP and port number of clients who connected to our server
If PublicIP = String.Empty Then
Try
' Get the clients IP address using Client property
Dim ipend As Net.IPEndPoint = client.Client.RemoteEndPoint
If Not ipend Is Nothing Then
PublicIP = ipend.Address.ToString & " : " & ipend.Port.ToString
End If
Catch ex As System.ObjectDisposedException
PublicIP = String.Empty
Catch ex As SocketException
PublicIP = String.Empty
End Try
End If
Return PublicIP
End Function
Function Server_IP_Port() 'Get the IP and port number of server that it listens
Dim IPListening = IPAddress.Parse(CType(server.LocalEndpoint, IPEndPoint).Address.ToString()).ToString
Dim PortListening = CType(server.LocalEndpoint, IPEndPoint).Port.ToString()
If IPListening = "0.0.0.0" Then
IPListening = "any IP Address"
End If
Return "Listening on " & IPListening & " : " & PortListening
End Function
Private Sub Tcp_Send(Msg_Send As String)
Dim sendBytes As [Byte]() = Encoding.ASCII.GetBytes(Msg_Send)
stream.Write(sendBytes, 0, sendBytes.Length)
writeData("Sent: " & Msg_Send)
End Sub
Public Sub StopListen() 'Function to telll to the server to stop listening
Try
client.Close()
Catch err As Exception
Console.WriteLine(err)
End Try
tcpClientThread.Abort()
server.Stop()
Btn_Listen.Text = "Listen"
End Sub
Private Sub Btn_Listen_Click(sender As Object, e As EventArgs) Handles Btn_Listen.Click
If Btn_Listen.Text = "Listen" Then
tcpClientThread = New System.Threading.Thread(AddressOf Me.Tcpclient)
tcpClientThread.Start()
Btn_Listen.Text = "Close"
Else
StopListen()
End If
End Sub
Private Sub writeData(ByVal data As Object)
If InvokeRequired Then
Invoke(New Action(Of Object)(AddressOf writeData), data)
Else
RichTextBox1.AppendText(Environment.NewLine & data)
End If
End Sub
Private Sub Btn_Send_Click(sender As Object, e As EventArgs) Handles Btn_Send.Click
Tcp_Send(TB_Tcp_Send.Text)
End Sub
End Class

Read ASync Network Stream

I've done a fair amount of searching and I'm sure I'm close, but I'm having problems and hoping someone can help.
I have an ethernet barcode scanner I need to be listening to constantly. I've tried using NetworkStream.Read in a separate thread, but then found out there is a 'BeginRead' function for async network streams. Problem is I can't get it working at all.
Here's the code I've got:
Public Class ScannerConnect
Private client As TcpClient
Property server As String
Property port As Int32 = 2005
Private data As [Byte]()
Sub Connect()
Try
client = New TcpClient(server, port)
Catch e As ArgumentNullException
Console.WriteLine("ArgumentNullException: {0}", e)
Catch e As SocketException
Console.WriteLine("SocketException: {0}", e)
End Try
End Sub 'Connect
Sub ListenASync()
stream = client.GetStream()
data = New [Byte](256) {}
stream.BeginRead(data, 0, data.Length, AddressOf ReadASync, stream)
End Sub
Private Sub ReadASync(ar As IAsyncResult)
Dim buffer As Byte() = TryCast(ar.AsyncState, Byte())
Dim bytesRead As Integer = stream.EndRead(ar)
Dim message As String = Encoding.ASCII.GetString(buffer, 0, bytesRead)
MsgBox(message)
stream.BeginRead(buffer, 0, buffer.Length, AddressOf ReadASync, buffer)
End Sub
End Class
It crashes on
Dim message As String = Encoding.ASCII.GetString(buffer, 0, bytesRead)
with error
Array cannot be null.
Any ideas what I'm doing wrong?
You passed stream (a NetworkStream) as the AsyncState parameter to BeginRead().
You can't cast that to a Byte() in the EndRead callback.

How to handle exceptions in Socket programming VB.net

I'm writing an client/server application using VB.net.
I used the code from MSDN to connect to a server :
' ManualResetEvent instances signal completion.
Private Shared connectDone As New ManualResetEvent(False)
Private Shared sendDone As New ManualResetEvent(False)
Private Shared receiveDone As New ManualResetEvent(False)
' The response from the remote device.
Private Shared response As String = String.Empty
Public Shared Sub Main()
' Establish the remote endpoint for the socket.
' For this example use local machine.
Dim ipHostInfo As IPHostEntry = Dns.Resolve(Dns.GetHostName())
Dim ipAddress As IPAddress = ipHostInfo.AddressList(0)
Dim remoteEP As New IPEndPoint(ipAddress, port)
' Create a TCP/IP socket.
Dim client As New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
' Connect to the remote endpoint.
client.BeginConnect(remoteEP, New AsyncCallback(AddressOf ConnectCallback), client)
' Wait for connect.
connectDone.WaitOne()
' Send test data to the remote device.
Send(client, "This is a test<EOF>")
sendDone.WaitOne()
' Receive the response from the remote device.
Receive(client)
receiveDone.WaitOne()
' Write the response to the console.
Console.WriteLine("Response received : {0}", response)
' Release the socket.
client.Shutdown(SocketShutdown.Both)
client.Close()
End Sub 'Main
The code works perfectly but it doesn't handle exceptions mainly timeout exception.
I changed it as follows:
Private ConnectionDone As New ManualResetEvent(False)
Public Function SendNetworkRequest(ByVal IPAddress As IPAddress, ByVal Port As Integer) As Boolean
Dim RemoteEndPoint As New IPEndPoint(IPAddress, Port)
'TCP/IP Socket
Dim Client As New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
'Start connection
Try
Client.BeginConnect(RemoteEndPoint, New AsyncCallback(AddressOf ConnectCallBack), Client)
ConnectionDone.WaitOne()
Catch ex As Exception
MsgBox(ex.Message)
End Try
Return True
End Function
Private Sub ConnectCallBack(ByVal Ar As IAsyncResult)
Dim Socket As Socket = CType(Ar.AsyncState, Socket)
Socket.EndConnect(Ar)
MsgBox("connected to " & Socket.RemoteEndPoint.ToString())
ConnectionDone.Set()
End Sub
But when executed with a wrong IP address and port to raise the exception, the application just stops without doing anything. Knowing that this function is called from a Form_Load event, even the following MsgBox("loaded") is not executed.
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
SendNetworkRequest(GV_ServerAddress, GV_ServerPort)
MsgBox("Loaded")
End Sub
does any on know the reason of this sudden exit ?
thank you in advance.