I have a simple program which sends/receives messages using TCP. For some reason, it receives the first message fine, but unless I close and reconnect with the client, the server doesn't receive any messages beyond the first from that client. I am providing a stripped down version of the code below (so please excuse the lack of exception handling).
Private TCPWriter As TcpClient
Private TCPListener As TcpListener
Private Sub Send(sender As Object, e As RoutedEventArgs)
Connect()
WriteTextToServer(MessageBox.Text)
End Sub
Private Sub Connect()
If TCPWriter Is Nothing Then
TCPWriter = New TcpClient
End If
If Not TCPWriter.Connected Then
TCPWriter.Connect(System.Net.IPAddress.Parse(IPBox.Text), PortBox.Text)
TCPWriter.NoDelay = True
End If
End Sub
Private Sub WriteTextToServer(inMsg As String)
Dim data() As Byte = Encoding.ASCII.GetBytes(inMsg + vbCrLf)
Dim ns As NetworkStream = TCPWriter.GetStream()
If ns.CanWrite Then
ns.Write(inMsg, 0, inMsg.Length - 1)
End If
End Sub
Private Sub ReadNewDataFromClient(ByVal inStatus As IAsyncResult)
Dim clientSocket As TcpClient
Dim datalen As Integer
Dim buf() As Byte
Dim message As String
clientSocket = CType(inStatus.AsyncState, TcpListener).EndAcceptTcpClient(inStatus)
clientSocket.ReceiveTimeout = 5000
datalen = clientSocket.Available
If datalen > 0 Then
'get all data at once ...
buf = New Byte(datalen - 1) {}
clientSocket.GetStream().Read(buf, 0, buf.Length)
message = Encoding.ASCII.GetString(buf, 0, buf.Count - 2)
Me.Dispatcher.Invoke(Sub() ReadNewDataFromClients.Add(ReadNewDataFromClients.Count.ToString + ": " + message))
End If
TCPListener.BeginAcceptTcpClient(New AsyncCallback(AddressOf ReadNewDataFromClient), Nothing)
End Sub
If I change the Connect() method to the below code, it will work but doesn't seem like the correct way to go about it.
Private Sub Connect()
If TCPWriter IsNot Nothing Then
TCPWriter.close
TCPWriter = nothing
Threading.Thread.Sleep(1000)
End If
TCPWriter = New TcpClient
If Not TCPWriter.Connected Then
TCPWriter.Connect(System.Net.IPAddress.Parse(IPBox.Text), PortBox.Text)
TCPWriter.NoDelay = True
End If
End Sub
What am I doing wrong?
You're using BeginAcceptTcpClient
to receive the next "message", this is used to accept a new connection (which is why it works when you disconnect/reconnect for each message). You should just use Read
/BeginRead
to read the next message.
This being said, you also need to understand that TCP is a stream protocol and as such, it has no concept of "messages", and perhaps most importantly, there is no reliable correspondence between the number of calls to Write
made by the sender and the number of calls to Read
required by the receiver to read the data sent.
If you want to use TCP for discrete messages, you need to send the data such that you can split it back up into the individual messages on the receiving end. This is usually done by means of "framing" the messages by prefixing them with a length indicator of a fixed size (e.g. 4 bytes).
You also need to ensure that you observe the return value of the Read
method, which will indicate how many bytes were actually read into the buffer.