Communication Server -> Client not happening - vb.net

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.

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

Sending Files over IpV6

I want to send a file over the internet with a tcp connection. My code handles this for IpV4 well (creddits here go to http://technotif.com/creating-simple-tcpip-server-client-transfer-data-using-c-vb-net/, i just changed minor things to correct the file output)
I tried to use this with a friend of mine, but his router is uteer garbage, and it cant forward any ports whatsoever and wont even work with upnp. It is set to IpV6 as well, and as far as I know IPv6 doesnt need anymore port forwarding since every device has its own public ip.
sadly my program doesnt work with IPv6 adresses, and I have a hard time finding any information regarding this topic.
Here is my code:
Public Class Form1
Private nSockets As ArrayList
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim IPHost As IPHostEntry
IPHost = Dns.GetHostByName(Dns.GetHostName())
lblStatus.Text = "My IP address is " +
IPHost.AddressList(0).ToString()
nSockets = New ArrayList()
Dim thdListener As New Thread(New ThreadStart _
(AddressOf listenerThread))
thdListener.Start()
End Sub
Public Sub listenerThread()
Control.CheckForIllegalCrossThreadCalls = False
Dim tcpListener As New TcpListener(7080)
Dim handlerSocket As Socket
Dim thdstHandler As ThreadStart
Dim thdHandler As Thread
tcpListener.Start()
Do
handlerSocket = tcpListener.AcceptSocket()
If handlerSocket.Connected Then
lbConnections.Items.Add(
handlerSocket.RemoteEndPoint.ToString() +
"connected.")
SyncLock (Me)
nSockets.Add(handlerSocket)
End SyncLock
thdstHandler = New ThreadStart(AddressOf _
handlerThread)
thdHandler = New Thread(thdstHandler)
thdHandler.Start()
End If
Loop
End Sub
Public Sub handlerThread()
Dim handlerSocket As Socket
handlerSocket = nSockets(nSockets.Count - 1)
Dim networkStream As NetworkStream = New _
NetworkStream(handlerSocket)
Dim blockSize As Int16 = 16
Dim thisRead As Int16
Dim dataByte(blockSize) As Byte
SyncLock Me
' Only one process can access the
' same file at any given time
Dim fileStream As Stream
fileStream = File.OpenWrite("C:\Whatever.file")
While (True)
thisRead = networkStream.Read(dataByte,
0, dataByte.Length)
fileStream.Write(dataByte, 0, thisRead)
If thisRead = 0 Then Exit While
End While
fileStream.Close()
networkStream.Close()
End SyncLock
lbConnections.Items.Add("File Written")
handlerSocket = Nothing
End Sub
How do i make it IPv6 capable?
Forgot to put in my client, what do i have to change here to make it work? Since even with the changes to my server, its still not connecting properly.
Private Sub Sendfile()
Dim filebuffer As Byte()
Dim fileStream As Stream
fileStream = File.OpenRead(tbFilename.Text)
' Alocate memory space for the file
ReDim filebuffer(fileStream.Length)
fileStream.Read(filebuffer, 0, fileStream.Length)
' Open a TCP/IP Connection and send the data
Dim clientSocket As New TcpClient(tbServer.Text, 7080)
Dim networkStream As NetworkStream
networkStream = clientSocket.GetStream()
networkStream.Write(filebuffer, 0, fileStream.Length)
networkStream.Close()
End Sub
Your listener is currently listening to IPv4-address 0.0.0.0, which is the default when you only specify a port to the listener.
You need to use the TcpListener(IPAddress, Integer) overload and specify IPv6Any to listen to IPv6-addresses.
Dim tcpListener As New TcpListener(IPAddress.IPv6Any, 7080)
As a side note you should rather use a List(Of T) than an ArrayList. The latter is typeless and not as optimized for .NET as the former.

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).

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.

TCPClient disconnects after several hours

I've created a Windows service that waits for TCPClient connections and relays any messages to all connected clients (except the sender). My code is based on this example.
One client connects when an event is triggered, sends some progress updates and then disconnects. The other clients are front end applications that receive and display the update.
If these clients are left idle for several hours they seem to loose the connection without any error\warning. I cannot find any relevent timouts for idle periods, is there something I am missing?
Service Code:
Protected Overrides Sub OnStart(ByVal args() As String)
_Listener = New TcpListener(IPAddress.Any, 1314)
_Listener.Start()
ListenForClient()
_ConnectionMontior = Task.Factory.StartNew(AddressOf DoMonitorConnections, New MonitorInfo(_Listener, _Connections), TaskCreationOptions.LongRunning)
End Sub
Private Sub ListenForClient()
Dim info As New ConnectionInfo(_Listener)
_Listener.BeginAcceptTcpClient(AddressOf DoAcceptClient, info)
End Sub
Private Sub DoAcceptClient(result As IAsyncResult)
Try
Dim monitorInfo As MonitorInfo = CType(_ConnectionMontior.AsyncState, MonitorInfo)
If monitorInfo.Listener IsNot Nothing AndAlso Not monitorInfo.Cancel Then
Dim info As ConnectionInfo = CType(result.AsyncState, ConnectionInfo)
monitorInfo.Connections.Add(info)
info.AcceptClient(result)
ListenForClient()
info.AwaitData()
End If
Catch ex As Exception
WriteToEventLog("DoAcceptClient: " & ex.Message)
End Try
End Sub
Private Sub DoMonitorConnections()
Try
'Create delegate for updating output display
' Dim doAppendOutput As New Action(Of String)(AddressOf AppendOutput)
'Get MonitorInfo instance from thread-save Task instance
Dim monitorInfo As MonitorInfo = CType(_ConnectionMontior.AsyncState, MonitorInfo)
'Implement client connection processing loop
Do
'Create temporary list for recording closed connections
Dim lostConnections As New List(Of ConnectionInfo)
'Examine each connection for processing
For Each info As ConnectionInfo In monitorInfo.Connections
If info.Client.Connected Then
'Process connected client
If info.DataQueue.Count > 0 Then
'The code in this If-Block should be modified to build 'message' objects
'according to the protocol you defined for your data transmissions.
'This example simply sends all pending message bytes to the output textbox.
'Without a protocol we cannot know what constitutes a complete message, so
'with multiple active clients we could see part of client1's first message,
'then part of a message from client2, followed by the rest of client1's
'first message (assuming client1 sent more than 64 bytes).
Dim messageBytes As New List(Of Byte)
While info.DataQueue.Count > 0
messageBytes.Add(info.DataQueue.Dequeue)
End While
'Relay the message to all clients except the sender
For Each inf As ConnectionInfo In monitorInfo.Connections
If inf.Client.Connected Then
Dim msg As String = info.Client.Client.RemoteEndPoint.ToString & "|" & System.Text.Encoding.ASCII.GetString(messageBytes.ToArray)
If Not inf.Client.Client.RemoteEndPoint.ToString = msg.Split("|")(0) Then
inf.Client.Client.Send(messageBytes.ToArray)
End If
End If
Next
End If
Else
'Record clients no longer connected
lostConnections.Add(info)
End If
Next
'Clean-up any closed client connections
If lostConnections.Count > 0 Then
While lostConnections.Count > 0
monitorInfo.Connections.Remove(lostConnections(0))
lostConnections.RemoveAt(0)
End While
End If
'Throttle loop to avoid wasting CPU time
_ConnectionMontior.Wait(1)
Loop While Not monitorInfo.Cancel
'Close all connections before exiting monitor
For Each info As ConnectionInfo In monitorInfo.Connections
info.Client.Close()
Next
monitorInfo.Connections.Clear()
Catch ex As Exception
WriteToEventLog("DoMonitorConnections" & ex.Message)
End Try
End Sub
Client Code:
_ServerAddress = IPAddress.Parse(ServerIP)
_Connection = New ConnectionInfo(_ServerAddress, 1314, AddressOf InvokeAppendOutput)
_Connection.AwaitData()
ConnectionInfo Class:
Public Class ConnectionInfo
Private _AppendMethod As Action(Of String)
Public ReadOnly Property AppendMethod As Action(Of String)
Get
Return _AppendMethod
End Get
End Property
Private _Client As TcpClient
Public ReadOnly Property Client As TcpClient
Get
Return _Client
End Get
End Property
Private _Stream As NetworkStream
Public ReadOnly Property Stream As NetworkStream
Get
Return _Stream
End Get
End Property
Private _LastReadLength As Integer
Public ReadOnly Property LastReadLength As Integer
Get
Return _LastReadLength
End Get
End Property
Private _Buffer(255) As Byte
Public Sub New(address As IPAddress, port As Integer, append As Action(Of String))
_AppendMethod = append
_Client = New TcpClient
_Client.Connect(address, port)
_Stream = _Client.GetStream
End Sub
Public Sub AwaitData()
_Stream.BeginRead(_Buffer, 0, _Buffer.Length, AddressOf DoReadData, Me)
End Sub
Public Sub Close()
If _Client IsNot Nothing Then _Client.Close()
_Client = Nothing
_Stream = Nothing
End Sub
Private Const MESSAGE_DELIMITER As Char = ControlChars.Cr
Dim sBuilder As New System.Text.StringBuilder
Private Sub DoReadData(result As IAsyncResult)
Dim info As ConnectionInfo = CType(result.AsyncState, ConnectionInfo)
Try
If info._Stream IsNot Nothing AndAlso info._Stream.CanRead Then
info._LastReadLength = info._Stream.EndRead(result)
If info._LastReadLength > 0 Then
Dim message As String = System.Text.Encoding.UTF8.GetString(info._Buffer, 0, info._LastReadLength)
If (message.IndexOf(MESSAGE_DELIMITER) > -1) Then
Dim subMessages() As String = message.Split(MESSAGE_DELIMITER)
sBuilder.Append(subMessages(0))
If Not info._Client.Client.LocalEndPoint.ToString = sBuilder.ToString.Split("|")(0) Then
info._AppendMethod(sBuilder.ToString)
End If
sBuilder = New System.Text.StringBuilder
If subMessages.Length = 2 Then
sBuilder.Append(subMessages(1))
Else
For i As Integer = 1 To subMessages.GetUpperBound(0) - 1
'MessageBox.Show(subMessages(i))
info._AppendMethod(subMessages(i))
Next
sBuilder.Append(subMessages(subMessages.GetUpperBound(0)))
End If
Else
sBuilder.Append(message)
End If
End If
End If
info.AwaitData()
Catch ex As Exception
info._LastReadLength = -1
End Try
End Sub
End Class
TCP does not guarantee that a side not trying to send data can detect a loss of the connection. You should have taken this into account when you designed your application protocol.
What you are seeing is most commonly caused by NAT or stateful firewalls. As a practical matter, if you don't send data at least every ten minutes, you can expect at least some clients to get disconnected. Their NAT devices or stateful firewalls simply forget about the connection. Neither side notices until it tries to send data.
I would suggest creating some kind of dummy message that the server sends to all its clients every five minutes. Basically, this is just some small chunk of data that can be uniquely identified as serving only to keep the connection alive.
Each client responds to the dummy message by sending a dummy message back to the server. If a client doesn't receive a dummy message in ten minutes, it should consider the connection lost, close it, and try to connect again.
The mere act of trying to send the dummy message will cause the server to detect any lost connections, but you should probably also consider as dead any connection to a client that hasn't responded to a dummy message by the time you're ready to send the next one. The client will know a connection is lost when it doesn't receive the dummy message. The exchange of messages will keep the NAT/firewall entry alive.