TCP server, why is the send message / string not recognized correctly? - vb.net

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

Related

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.

Delay when displaying a message received by a Telnet client

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

Fast TCP receive

I'm working on a TCP client. but for some reason it is not fast enough receiving data. If the server sends a string (about 140 characters) every 50ms it works fine, but it I change it to 10ms (or lower) the Client doesn't display every string.
I tried the same with another TCP chat program, and there 1ms was no problem.
So it should be possible ;-)
Below my code:
Imports System.Net, System.Text
Imports System.Net.Sockets
Imports System.IO
Imports System.Xml
Imports System.Globalization
Imports System.ComponentModel
Imports System.Management
Imports System.Text.RegularExpressions
Public Class Client
Dim t As New TcpClient
Private Sub Client_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Control.CheckForIllegalCrossThreadCalls = False
Try
t.Connect("127.0.0.1", "50020")
If t.Connected Then
t.GetStream.BeginRead(New Byte() {0}, 0, 0, AddressOf doread, Nothing)
login()
StatusStrip1.BackColor = Color.LightGreen
End If
Catch ex As Exception
Application.Restart()
End Try
End Sub
Sub login()
senddata("LOGIN|")
End Sub
Sub doread(ByVal ar As IAsyncResult)
Try
If t.Connected = True Then
Dim sr As New StreamReader(t.GetStream)
Dim msg As String = sr.ReadLine()
TextBox1.Text = (msg & vbCr & vbLf) & TextBox1.Text
t.GetStream.BeginRead(New Byte() {0}, 0, 0, AddressOf doread, Nothing)
End If
Catch ex As Exception
Application.Restart()
End Try
End Sub
Sub senddata(ByVal message As String)
Dim sw As New StreamWriter(t.GetStream) 'declare a new streamwriter
sw.WriteLine(message) 'write the message
sw.Flush()
End Sub
End Class
You might not be aware of the fact that TCP connections represent a stream of bytes. Messages/packets are not preserved. You might receive as little as one byte at a time.
You assume that you are receiving whole lines.
Also, this hybrid use of binary reads and StreamReader cannot work for many reasons. One of them is that StreamReader buffers internally. Each time you create a new one you throw buffer contents away.
Why are you checking t.Connected all the time? If false, you simply do nothing. This is worse than not checking at all. Don't blindly copy code from the web (I know that you copied this because this broken pattern is all over the web and nobody would normally think of doing this).
Application.Restart
??? That's not an appropriate error strategy. Better: Dispose of all resources and show a message box.
This is really, really broken. Unsalvagable. Need to rewrite.
Simply do this on a background thread:
var sr = new StreamReader(...);
while (true) {
var line = sr.ReadLine();
if (line == null) break;
Invoke(new Action(() => TextBox1.Text += line));
}
Or anything equivalent.

VB.NET TCPClient/Server Issue- Sending on a Timer

So my program starts out by counting how many processes of "XProcess" and has a timer to check every 1 second, which works great! I have the input of the count going into Setting variable. I then have a sub routine that takes that Setting variable, along with a IF statement to output that the TCPClient is sending the string ("One Process").
Well the issue is, I have no event to use with the sub routine and so I tied it in with the timer to send the message out every 1 second. The TCPClient sends it to a local address(127.0.0.1) right now, and sends it to a Textbox. Well PROBLEM!!!
It repeats ("One Process") over and over and over, which I can see why this happens.
So with the Code below, how can the TCPClient send an notification of how many processes of "XProcess" to the TCPServer and the TCPSERVER to spit out that 1 or more processes are running ? (with out the SERVER repeating the string (integer works as wel) over and over again)
The below works, but repeats how many processes are running as a string.
MainWindow.xaml.vb
Imports System.Windows.Threading
Imports System.Net.Sockets
Public Class MainWindow
Private Run_ProgramRunCheck_timer As New DispatcherTimer
Private Run_RecieveCheck_timer As New DispatcherTimer
Dim processCount As Integer
Private Sub Window_Loaded(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles MyBase.Loaded
ServerStart()
'Check for program changes every second
' Set interval for timer
Run_ProgramRunCheck_timer.Interval = TimeSpan.FromMilliseconds(1000)
'Start timer on button click
Run_ProgramRunCheck_timer.Start()
AddHandler Run_ProgramRunCheck_timer.Tick, AddressOf __ProgramCheck
'Check for Message Recieve every second
' Set interval for timer
Run_RecieveCheck_timer.Interval = TimeSpan.FromMilliseconds(1000)
'Start timer on button click
Run_RecieveCheck_timer.Start()
AddHandler Run_RecieveCheck_timer.Tick, AddressOf _RecieveMessageConvert
TCPClientSender()
End Sub
Public Sub __ProgramCheck()
'This sub will be checked every 1 seconds for changes
'Count number of processes
processCount = Process.GetProcessesByName("tvnviewer").Count()
My.Settings.TotalProcesses = processCount
End Sub
Public Sub TCPClientSender()
My.Settings.TotalProcesses = 0
If My.Settings.TotalProcesses = 1 Then
Dim port As Int32 = 50000
Dim client As New TcpClient("127.0.0.1", port)
' Translate the passed message into ASCII and store it as a Byte array.
Dim data As [Byte]() = System.Text.Encoding.ASCII.GetBytes("One Process")
' Get a client stream for reading and writing.
' Stream stream = client.GetStream();
Dim stream As NetworkStream = client.GetStream()
' Send the message to the connected TcpServer.
stream.Write(data, 0, data.Length)
End If
End Sub
Public Sub _RecieveMessageConvert()
TextBlock1.Text = My.Settings.StoreSentMessage
End Sub
End Class
TCPServer.vb
Imports System.Net
Imports System.Threading
Imports System.Net.Sockets
Imports System.IO
Public Module TCPServer
Dim Server = New TcpListener(IPAddress.Any, 50000) ' <-- Listen on Port 50,000
Dim Client As New TcpClient
Private ServerThread As Thread = Nothing
Dim Message As String = ""
Private Threads As New List(Of Thread)
Public Sub ServerStart()
ServerThread = New Thread(AddressOf ConnectionListener)
ServerThread.IsBackground = True
ServerThread.Start()
End Sub
Private Sub ConnectionListener()
Try
Server.Start()
While True
Dim client As TcpClient = Server.AcceptTcpClient ' Blocks until Connection Request is Received
Dim Reader As New StreamReader(client.GetStream())
While Reader.Peek > -1
Message = Message + Convert.ToChar(Reader.Read()).ToString
End While
My.Settings.StoreSentMessage = Message
End While
Catch ex As Exception
End Try
End Sub
End Module
Dont you just want to do this:
Dim data As [Byte]() = System.Text.Encoding.ASCII.GetBytes(My.Settings.TotalProcesses)
I dont know how you ever get it to say "One Process" when you set the value to zero and then check if the value is 1 on the next line???
My.Settings.TotalProcesses = 0
If My.Settings.TotalProcesses = 1 Then

Communication Server -> Client not happening

I have two applications running on different computers, one of them is a client and the other one is a server, the communication on Client -> Server works perfectly, although it doesn't on the opposite direction.
Server code:
Imports System.IO
Imports System.Net
Public Class Form1
Dim listener as Net.Sockets.TcpListener
Dim listenThread as Threading.Thread
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
listener = New Net.Sockets.TcpListener(Net.IPAddress.Any, 32111)
listener.Start()
listenThread = New Threading.Thread(AddressOf DoListen)
listenThread.IsBackground = True
listenThread.Start()
End Sub
Private Sub DoListen()
Dim sr As IO.StreamReader
Dim sw As IO.StreamWriter
Do
Try
Dim client As Net.Sockets.TcpClient = listener.AcceptTcpClient
sr = New IO.StreamReader(client.GetStream)
sw = New IO.StreamWriter(client.GetStream)
Dim Lines As String() = sr.ReadToEnd.Split(New Char() {","c}) 'get client data
sr.Close()
sw.Write("Message123") ' try to send data to client
sw.Close()
Catch
End Try
Loop
End Sub
End Class
Client code:
Public Class Form1
Dim Command As String
Dim thread As Threading.Thread
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
thread = New Threading.Thread(AddressOf MyProcess)
thread.IsBackground = True
thread.Start()
End Sub
Private Sub Send(ByVal Command As String)
Try
Dim client As New System.Net.Sockets.TcpClient
client.Connect(TextBox1.Text, 32111)
Dim writer As New IO.StreamWriter(client.GetStream)
writer.Write(Command)
writer.Flush()
client.Close()
MsgBox("Command has been sent successfully")
Catch ex As Exception
End Try
End Sub
Private Sub MyProcess()
Do
Dim client As New System.Net.Sockets.TcpClient
client.Connect("192.168.1.2", 32111)
Dim reader As New IO.StreamReader(client.GetStream)
MessageBox.Show(reader.ReadToEnd)
reader.Close()
client.Close()
Loop
End Sub
End Class
The thing is that nothing happens, the MessageBox doesn't appear on the client saying "Message123".
Each time the client creates a new socket and connects to it, it opens an entirely new channel of communication between the two applications. In your example, the server is returning a message on the first socket, but on the client it does not try to read from the first socket. instead, it opens a second socket and reads from that. You need to change it so that you are reading from the same socket on which you sent the request message.
If you think about it, you are making an assumption which can't possibly be true. You are assuming that there can only be one valid socket from your client machine to the server on that port. However obviously this is not true. You can run many separate FTP clients and to the same server, for instance. Each application can open as many sockets to the same port on the same server as they want to, and they are all completely independent from each other.