How to handle exceptions in Socket programming VB.net - 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.

Related

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

client can not connect againt to my Socket Server - VB.NET

I have a thread and a socket server for listening to client. Client software is not for me and it is a Laboratory Software that sends data to my program.
when listening starts there is no problem but when the client software is closed and reopened, that can not send any data to my software.
My listener must be run every time like a service.
This is my code:
Delegate Sub WriteMsgHandle(ByVal Msg As String)
Dim handler As WriteMsgHandle
Dim THS As ThreadStart
Dim TH As Thread
Private Sub btnListen_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnListen.Click
Try
btnListen.Enabled = False
THS = New ThreadStart(AddressOf Listen)
TH = New Thread(THS)
TH.Start()
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub
Public Sub Listen()
Dim bytesReceived As Integer = 0
Dim recv() As Byte = New Byte(1) {}
Dim clientSocket As Socket
Dim listenerSocket As New Socket _
(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
Dim IPHost As IPHostEntry = Dns.GetHostEntry(Dns.GetHostName())
Dim localadd As IPAddress = IPAddress.Parse(txt_ip.Text)
Dim ipepServer As IPEndPoint = New IPEndPoint(localadd, txt_port.Text)
handler = AddressOf WriteMsg
listenerSocket.Bind(ipepServer)
listenerSocket.Listen(-1)
clientSocket = listenerSocket.Accept()
Dim msgcount As Integer = 0
If clientSocket.Connected Then
MsgBox("Connected")
Do
bytesReceived = clientSocket.Receive(recv)
Dim Msg As String
Msg = Encoding.ASCII.GetString(recv)
Invoke(handler, Msg)
Loop While bytesReceived <> 0
End If
End Sub
You're only accepting once. You need to accept in a loop.
If clientSocket.Connected Then why did you add this? Delete that check. The socket was just accepted so it is connected. Even if it was disconnected do you want to just ignore that error condition?!
The receive loop is correct.
You probably want to start each accepted client on a new thread (or use async IO).

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

how to listen on port 25 with vb.net

I'm basically trying to write a spam filter for incoming email on a mail server. I'd like to write a VB.NET program that can listen for any incoming mail on port 25 and then run my script on it and then pass it to the mail server running on a different port.
What do I need to do to have my program just sit and wait for a message to come in on port 25 and then react to it?
Thanks.
Here, as an example, is part of a socket listening service I modified from a tutorial a while ago in VB.NET. Basically, a socket listens for traffic on port 25 when the service is started, accepts a connection and then assigns that connection to a new thread, sends a response, and then closes the TCP connection.
Dim serverSocket As New TcpListener(IPAddress.Any, "25")
Dim ipAddress As System.Net.IPAddress = System.Net.Dns.Resolve(System.Net.Dns.GetHostName()).AddressList(0)
Dim ipLocalEndPoint As New System.Net.IPEndPoint(IPAddress, 25)
Protected Overrides Sub OnStart(ByVal args() As String)
Dim listenThread As New Thread(New ThreadStart(AddressOf ListenForClients))
listenThread.Start()
End Sub
Protected Overrides Sub OnStop()
' Add code here to perform any tear-down necessary to stop your service.
End Sub
Private Sub ListenForClients()
serverSocket = New TcpListener(ipLocalEndPoint)
serverSocket.Start()
While True
Dim client As TcpClient = Me.serverSocket.AcceptTcpClient
Dim clientThread As New Thread(New ParameterizedThreadStart(AddressOf HandleClientComm))
clientThread.Start(client)
End While
End Sub
Private Sub HandleClientComm(ByVal client As Object)
Dim tcpClient As TcpClient = DirectCast(client, TcpClient)
Dim clientStream As NetworkStream = tcpClient.GetStream
Dim message As Byte() = New Byte(4095) {}
Dim bytesRead As Integer
While True
If (bytesRead = 0) Then
Exit While
End If
Dim encoder As New asciiencoding()
Dim serverResponse As String = "Response to send"
'Response to send back to the testing client
Dim sendBytes As [Byte]() = encoding.ascii.getbytes(serverResponse)
clientStream.Write(sendBytes, 0, sendBytes.Length)
End While
tcpClient.Close()
End Sub

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.