Error404 Error404 - 3 months ago 24
Vb.net Question

Tcp Connection only reads one message

I am trying to create a simple Game which needs a TcpConnection.

So I created a Server class which wraps the TcpListener, same goes with Client and TcpClient. But when I attach my Listener Sub and send Messages it only gets called on the first one:

Server



Imports System.Net.Sockets

Public Class Server
Inherits ConnectionPartner

Private Server As TcpListener
Private Client As TcpClient
Private Stream As NetworkStream
Private Port As Integer

Public Sub Init(ByVal port As Integer)
Server = New TcpListener(port)
End Sub

Public Sub Open()
Server.Start()
Client = Server.AcceptTcpClient()
Stream = Client.GetStream()
End Sub

Public Overrides Sub Write(ByVal Message As String)
Dim Bytes() As Byte = Encoder.GetBytes(Message)
Me.Write(Bytes)
End Sub
Public Overrides Sub Write(ByVal Message() As Byte)
If Stream Is Nothing Then Return
Stream.Write(Message, 0, Message.Length)
End Sub

Public Overrides Sub Listen(ByVal Handler As Action(Of String))
Listen(Sub(ByVal Message() As Byte)
Handler(Encoder.GetString(Message))
End Sub)
End Sub
Public Overrides Sub Listen(ByRef Handler As Action(Of Byte()))
Dim Buffer(Client.ReceiveBufferSize()) As Byte

While (True)
Utils.Log("Listening")
Client.GetStream().Read(Buffer, 0, Buffer.Length)
Handler(Buffer)
End While
End Sub

Public Sub Close()
Try
Client.Close()
Catch ex As Exception

End Try
Try
Server.Stop()
Catch ex As Exception

End Try
End Sub

End Class


Client



Imports System.Net
Imports System.Net.Sockets

Public Class Client
Inherits ConnectionPartner

Private Socket As TcpClient
Private Stream As NetworkStream
Private Port As Integer

Public Sub Init()
Socket = New TcpClient()
End Sub

Public Sub Open(ByVal Ip As IPAddress, ByVal Port As Integer)
Socket.Connect(Ip, Port)
Stream = Socket.GetStream()
End Sub

Public Overrides Sub Write(ByVal Message As String)
Dim Bytes() As Byte = Encoder.GetBytes(Message)
Me.Write(Bytes)
End Sub
Public Overrides Sub Write(ByVal Message() As Byte)
If Stream Is Nothing Then Return
Stream.Write(Message, 0, Message.Length)
End Sub

Public Overrides Sub Listen(ByVal Handler As Action(Of String))
Listen(Sub(ByVal Message() As Byte)
Handler(Encoder.GetString(Message))
End Sub)
End Sub
Public Overrides Sub Listen(ByRef Handler As Action(Of Byte()))
Dim Buffer(Socket.ReceiveBufferSize()) As Byte

While (True)
Utils.Log("Listening")
Stream.Read(Buffer, 0, Buffer.Length)
Handler(Buffer)
End While
End Sub

Public Sub Close()
Try
Socket.Close()
Catch ex As Exception

End Try
End Sub

End Class


My Test Class



Imports System.Net
Imports System.Threading

Class MainWindow

Private Server As Server = New Server()
Private Client As Client = New Client()
Private C As Connection
Private Port As Integer = My.Resources.Port

Private Sub button_client_init_Click(sender As Object, e As RoutedEventArgs) Handles button_client_init.Click
Client.Init()
End Sub

Private Sub button_client_start_Click(sender As Object, e As RoutedEventArgs) Handles button_client_start.Click
Client.Open(Dns.GetHostEntry("localhost").AddressList(1), Port)
End Sub

Private Sub button_client_write_Click(sender As Object, e As RoutedEventArgs) Handles button_client_write.Click
Client.Write("bar")
End Sub

Private Sub button_client_listen_Click(sender As Object, e As RoutedEventArgs) Handles button_client_listen.Click
Dim T As Thread = New Thread(Sub()
Client.Listen(Sub(ByVal M As String)
Log("Client:" & M)
End Sub)
End Sub)
T.Start()
End Sub

Private Sub button_server_init_Click(sender As Object, e As RoutedEventArgs) Handles button_server_init.Click
Server.Init(Port)
End Sub

Private Sub button_server_start_Click(sender As Object, e As RoutedEventArgs) Handles button_server_start.Click
Dim T As Thread = New Thread(Sub()
Server.Open()
End Sub)
T.Start()
End Sub

Private Sub button_server_write_Click(sender As Object, e As RoutedEventArgs) Handles button_server_write.Click
Server.Write("foo")
End Sub

Private Sub button_server_listen_Click(sender As Object, e As RoutedEventArgs) Handles button_server_listen.Click
Dim T As Thread = New Thread(Sub()
Server.Listen(Sub(ByVal M As String)
Log("Server: " & M)
End Sub)
End Sub)
T.Start()
End Sub

End Class





Edit:



I tried to do the whole thing with StreamReader/Writers. Now I am not even getting a síngle Message:

Server



Imports System.IO
Imports System.Net.Sockets

Public Class Server
Inherits ConnectionPartner

Private Server As TcpListener
Private Client As TcpClient
Private Reader As StreamReader
Private Writer As StreamWriter
Private Port As Integer

Public Sub Init(ByVal port As Integer)
Server = New TcpListener(port)
End Sub

Public Sub Open()
Server.Start()
Client = Server.AcceptTcpClient()
Dim Stream As NetworkStream = Client.GetStream()
Reader = New StreamReader(Stream)
Writer = New StreamWriter(Stream)
End Sub

Public Overrides Sub Write(ByVal Message As String)
Writer.WriteLine(Message)
End Sub
Public Overrides Sub Write(ByVal Message() As Byte)
End Sub

Public Overrides Sub Listen(ByVal Handler As Action(Of String))
While True
Dim Message As String = Reader.ReadLine()
Handler(Message)
End While
End Sub
Public Overrides Sub Listen(ByRef Handler As Action(Of Byte()))
End Sub

Public Sub Close()
Try
Client.Close()
Catch ex As Exception

End Try
Try
Server.Stop()
Catch ex As Exception

End Try
End Sub


End Class


Client



Imports System.IO
Imports System.Net
Imports System.Net.Sockets

Public Class Client
Inherits ConnectionPartner

Private Socket As TcpClient
Private Reader As StreamReader
Private Writer As StreamWriter
Private Port As Integer

Public Sub Init()
Socket = New TcpClient()
End Sub

Public Sub Open(ByVal Ip As IPAddress, ByVal Port As Integer)
Socket.Connect(Ip, Port)
Dim Stream As NetworkStream = Socket.GetStream()
Reader = New StreamReader(Stream)
Writer = New StreamWriter(Stream)
End Sub

Public Overrides Sub Write(ByVal Message As String)
Writer.WriteLine(Message)
End Sub
Public Overrides Sub Write(ByVal Message() As Byte)
End Sub

Public Overrides Sub Listen(ByVal Handler As Action(Of String))
While True
Dim Message As String = Reader.ReadLine()
Handler(Message)
End While
End Sub
Public Overrides Sub Listen(ByRef Handler As Action(Of Byte()))
End Sub

Public Sub Close()
Try
Socket.Close()
Catch ex As Exception

End Try
End Sub


End Class

usr usr
Answer

TCP does not provide messages at all. It provides a boundaryless stream of bytes. When you Read you can get back any number of bytes as low as one. You code needs to assume arbitrary chunking. Here, you are assuming that you get a full buffer each time.

You can use BinaryReader.ReadBytes to read an exact number of bytes. StreamReader/Writer makes text-based protocols much easier.

ReceiveBufferSize is not the number of bytes incoming. It's value is meaningless, don't look at it.