TCP Client to Server communication
Asked Answered
O

1

0

All I'm looking for is a simple TCPClient/Listner example on Windows Form VB.Net. I'm a newbie and Microsoft TCPClient/Listner class examples are not what I am looking for. All I am looking is for the TCPClient to send a message and for a TCPListener to get the message and to send a message back "I got your message" ?

A little help would be great. I have some codes, but is only to send message to server and not back from server to client.. Any help will be very appreciated..

Olathe answered 5/2, 2016 at 21:29 Comment(1)
In addition to my answer, do note that it is the TcpClient that sends and receives data, not the TcpListener. The listener only handles incoming connections. So you'd use a TcpClient on both the client side and server side, but it's only the server side that uses a TcpListener.Claudineclaudio
C
12

TCP communication is stream-based, which means it doesn't handle any packets. Due to this, messages that you receive might be either partial or lumped together.

You could for example send:

Hello!

How are you?

But you might receive:

Hello!How are you?

or:

Hello!How ar

e you?

(or something similar)

To fix this you must apply something called "length-prefixing". Length-prefixing (or length prefixing) means that before you send a message, you put its length (amount of characters/bytes) in the beginning of it. By doing so, the endpoint will know exactly how many bytes to read for each message. Thus there will be no problems with messages being partial or lumped together.

This is not the most straightforward thing to do as a beginner, as to get it to work properly on both sides you have to structure your code just right. So I've created two classes that will take care of this for you. See the examples below on how to use them for simple text message-based communication.

Link to source: http://www.mydoomsite.com/sourcecodes/ExtendedTcpClient.zip

Link to C# source : http://www.mydoomsite.com/sourcecodes/ExtendedTcpClient%20CSharp.zip

EDIT (2019-11-08)

Some time ago I made an upgraded version of this with a bit better code structure and error handling. For those of you interested, the new code can be downloaded here (VB.NET only):

https://www.mydoomsite.com/sourcecodes/ExtendedTcpClient%202.0.zip

Example usage

Note that in those examples Client does not refer to the client side, but to the TcpClient.

Server side

  1. First declare a new variable for ExtendedTcpClient, and be sure to include WithEvents in the declaration.

    Dim WithEvents Client As ExtendedTcpClient
    
  2. Then you will need a TcpListener and a Timer to check for incoming connections.

    Dim Listener As New TcpListener("0.0.0.0", 5555) 'Listen for any connection on port 5555.
    Dim WithEvents Tmr As New System.Windows.Forms.Timer
    
  3. Then you need to subscribe to the timer's Tick event.

    Private Sub Tmr_Tick(sender As System.Object, e As System.EventArgs) Handles Tmr.Tick
    
    End Sub
    

    In there you check for incoming connections via the Listener.Pending() method. When you are to accept a connection you first declare a new instance of the ExtendedTcpClient. The class requires to have a form as its owner, in this application Me is the current form.
    Then you use the ExtendedTcpClient.SetNewClient() method with Listener.AcceptTcpClient() as its argument to apply the TcpClient from the listener. Put this code in the Tmr_Tick sub:

    If Listener.Pending() = True Then
        Client = New ExtendedTcpClient(Me)
        Client.SetNewClient(Listener.AcceptTcpClient())
    End If
    

    Now the client and server are connected to each other.

  4. Now you need to subscribe to the PacketReceived event of the client. Create a sub like so:

    Private Sub Client_PacketReceived(sender As Object, e As ExtendedTcpClient.PacketReceivedEventArgs) Handles Client.PacketReceived
    
    End Sub
    

    All received data are presented in an array of bytes. In the PacketReceived sub you can output the received packet as text into a TextBox. Just check if the packet header is PlainText and then you can convert the received packets contents (which is an array of bytes, accessed via e.Packet.Contents) to a string and put it in the TextBox.

    If e.Packet.Header = TcpMessagePacket.PacketHeader.PlainText Then
        TextBox1.AppendText("Message recieved: " & System.Text.Encoding.Default.GetString(e.Packet.Contents) & Environment.NewLine)
    End If
    

    System.Text.Encoding.Default.GetString() will convert a byte array to normal text.

  5. In the PacketReceived sub you can also make it send "Message received" to the client.

    Dim ResponsePacket As New TcpMessagePacket(System.Text.Encoding.Default.GetBytes("Message received."), TcpMessagePacket.PacketHeader.PlainText)
    ResponsePacket.Send(Client.Client) 'Get the ExtendedTcpClient's underlying TcpClient.
    
  6. Lastly, when closing the form you just need to disconnect the client.

    Private Sub ServerWindow_FormClosing(sender As Object, e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
        If Client IsNot Nothing Then Client.Disconnect()
    End Sub
    

And that's it for the server side.


Client side

  1. For the client side you will do pretty much the same as the server side, though you won't be needing a TcpListener nor a Timer.

    Dim WithEvents Client As New ExtendedTcpClient(Me) 'The current form as its owner.
    
  2. Connect to the server via the IP and port you've given the listener.

    Client.Connect("127.0.0.1", 5555) 'Connects to localhost (your computer) at port 5555.
    
  3. Now if you want to send text to the server you'd do something like this (in for example a button):

    Dim MessagePacket As New TcpMessagePacket(System.Text.Encoding.Default.GetBytes(TextBox2.Text), TcpMessagePacket.PacketHeader.PlainText)
    MessagePacket.Send(Client.Client)
    

    TextBox2 includes the text you want to send.

  4. Lastly, you will need to subscribe to the PacketReceived event here too to check for responses from the server. In there you receive text just like the server does.

    Private Sub Client_PacketReceived(sender As Object, e As ExtendedTcpClient.PacketReceivedEventArgs) Handles Client.PacketReceived
        If e.Packet.Header = TcpMessagePacket.PacketHeader.PlainText Then
            TextBox1.AppendText(System.Text.Encoding.Default.GetString(e.Packet.Contents) & Environment.NewLine) 'Prints for example "Message received." from the server.
        End If
    End Sub
    

And now everything should be working!

Link to a complete example project (only client-to-server): http://www.mydoomsite.com/sourcecodes/TCP%20Messaging%20System.zip

Link to C# example: http://www.mydoomsite.com/sourcecodes/CSharp%20TCP%20Messaging%20System.zip

If you want to add more headers to the class (the headers indicate to you what kind of data each packet contains), open TcpMessagePacket.vb and add more values in the PacketHeader enum (located in the region called Constants).

Hope this helps!


Screenshot from the example project

(Click the image for larger resolution)

ExtendedTcpClient example project output

Claudineclaudio answered 6/2, 2016 at 10:41 Comment(6)
Thnx, this is what i Need and you made great example, but in this example client send text to server, but I need when server get the message, to be able to answer to server, is this possible ?Olathe
@Olathe yes, the project doesn't include that but my tutorial does. See point 5 under Server side :). Just put that code in the server's PacketReceived sub.Claudineclaudio
Every time the PacketReceived event is called on either the server side or the client side it indicates that you've received a packet (a message, if the header is PlainText), so everything you need to do when you receive something you should do there. When you're going to send something you just declare a new TcpMessagePacket, fill it with bytes and then send it. - The classes are very optimized. I've sent large files using this code, without any problems.Claudineclaudio
However do note: Don't send too big packets. If you're going to send files or big data you should split it up into several packets of 8-32 KB in size. --- All that said, If you need any more examples/code stuff just let me know. :)Claudineclaudio
thank you very much, superb example. couldyou please tell me how it needs to be modified to do this: on button press, the client connects, sends a predefined message, and closes the connection. I have multiple clients, and on keypress they should tell the server that the button has been pressed and then leave the connection free for Others to connect.. thanks!Dionisio
@Dionisio : Glad my answer is still of help! What you ask is rather simple: To start with add a new header to the TcpMessagePacket.PacketHeader enumeration and call it whatever you want. Then when you click the button call Client.Connect(...), create a new empty packet: Dim ButtonPacket As New TcpMessagePacket(New Byte(-1) {}, TcpMessagePacket.PacketHeader.YOURHEADER), send it, and disconnect via Client.Disconnect(). Done! -- If anything's unclear or you have any more questions, feel free to ask!Claudineclaudio

© 2022 - 2024 — McMap. All rights reserved.