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:
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
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
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
I tried to do the whole thing with StreamReader/Writers. Now I am not even getting a síngle Message:
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
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
Forgot to flush the Messages.
Imports System.IO
Imports System.Net
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 Ip As IPAddress, ByVal Port As Integer)
Server = New TcpListener(Ip, 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)
Writer.AutoFlush = True
End Sub
Public Overrides Sub Start(ByVal Ip As IPAddress, ByVal Port As Integer)
Me.Init(Ip, Port)
Me.Open()
End Sub
Public Overrides Sub Write(ByVal Message As String)
Writer.WriteLine(Message)
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 Close()
Try
Client.Close()
Catch ex As Exception
End Try
Try
Server.Stop()
Catch ex As Exception
End Try
End Sub
End Class
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)
Writer.AutoFlush = True
End Sub
Public Overrides Sub Start(ByVal Ip As IPAddress, ByVal Port As Integer)
Me.Init()
Me.Open(Ip, Port)
End Sub
Public Overrides Sub Write(ByVal Message As String)
Writer.WriteLine(Message)
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 Close()
Try
Socket.Close()
Catch ex As Exception
End Try
End Sub
End Class
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.