Free Web Hosting Provider - Web Hosting - E-commerce - High Speed Internet - Free Web Page
Search the Web

vbProgramming | Tutorials | Networking | Setting up a Local TCP Server
    vbProgramming 
Tutorials | Networking | Setting up a Local TCP Server
 
     

vbProgramming Home :: vbProgramming Forums :: Tutorials :: Contact :: Links 

 

I

This tutorial will discuss the advantage of TCP over UDP, and set up a basic local server.

TCP vs. UDP
There's two different protocols which you use when you do networking: TCP and UDP.

TCP is a protocol which is used to guarantee data arrival to its location.
UDP is a protocol whose data is not guaranteed to arrive to its location.

You might think it's a no brainer, TCP wins.

That's not the case. UDP is much much much faster than TCP. It's used in most First Person Shooter online games, because you're getting and sending the player position...etc many times per minute. Also, if you used a TCP Protocol, it would keep trying to send that data until it arrives there.

Our local server will be used to send String messages, sort of like a chat program. Now obviously, since this is a very low rate of data, and since we don't need lightning fast speed in our 'chat program' (which we will, eventually, make) - we'll use TCP.

Introduction
You might be wondering why the introduction is not in the beginning. As a matter of fact, that's what I'm asking myself right now.

So far I've introduced you to two different protocols without even explaining what a protocol is. The Thesaurus in Microsoft Word defines it as:
-Procedure
-Etiquette
-Code of behavior
-Set of rules
-Modus Operandi (What the hell? I'm assuming this means "Mode (or Method) of operation")

That's basically... what a protocol is. It's basically a set of rules for how our data transfer will behave.

So we've already decided on TCP, since we're only sending out simple String messages that aren't going to be sent every millisecond, and every message counts. I remember a few years ago, MSN Messenger would act all weird saying "Your message: <Message> was not sent", 5 minutes after I sent the message - this of course, pissed me off really badly (as well as a multitude of others).

They were probably using something similar to the UDP protocol back then, now it doesn't do that anymore. Or it could have just been my computer. In either case, we need that data to arrive there at all costs.

Here's a quick introduction to what we're going to do:
(1) We're going to create 2 projects:
      (a) The Server
      (b) A Client
(2) This project will be local, meaning it won't work on the internet - this is for the next tutorial.
(3) The client will send the server a message, and the server will MessageBox it.

That's pretty much it. So this is basic client server stuff. However it's easier said than done, so I'll try to make this as easy as possible on you.

The Server
We'll begin by setting up the server.

Create a project called Server, now create a class called clsServer.

'This will make it so that you don't have to type the full name of a variable, like System.Net.Sockets.TCPListener
Imports System.Net
Imports System.Net.Sockets

Public Class clsServer
   Private Listener As TcpListener
   Private t As System.Threading.Thread
End Class

In a normal, real life conversation: Person A talks to Person B. Person B listens to Person A. Person B may or may not respond to Person A, but keeps listening to person A.

Our server is our Person B, it keeps on listening to the messages that the client sends, whether it responds back or not is up to you and your program execution. Our client is Person A, it does the talking initially. So this is why our server has a TCPListener, to listen to the messages that the client sends.

The reason I dimmed t as thread was because we'll use it later.

Next, we're going to create a Listen sub:

Public Sub StartListening()
    'We'll use the local IP (127.0.0.1) and port 6580
    Listener = New TcpListener(IPAddress.Parse("127.0.0.1"), 6580)
    Listener.Start()
    t = New System.Threading.Thread(AddressOf ListenContinuously)
    t.Start()
End Sub

Just ignore the error where you instantiate t, we'll get to that next.

We'll create a sub called ListenContinuously, which.. keeps on listening for messages. It's time to do some explaining here.

When you instantiate the Listener, you provide 2 arguments: The IP Address where to listen, and the port number. Obviously, you want to listen on your own computer - duh. However, the IPAddress.Parse() might be a bit confusing. See the thing is, we can't pass in the IP as a String, when we do IPAddress.Parse("myIP"), it will convert it to a special format.

The port is a simple concept. It's just a number on where to listen. For example, MSN Messenger listens on a specific port (I don't know which one), and accepts incoming connections only from that port. If, for example, Yahoo Messenger listened on the same port, and you were running both at the same time... you would get some conflicts. Don't worry - the port number cam go very high (I'm not sure how high), and if you ever run it to some conflicts you can change the port number. Just a tip:
Port 80, 88, and 8000 are usually used for the internet (HTML). So don't use this port number. I'd suggest you use a random port number, like 6580, and if you ever run into conflicts you can easily change the port number.

The next line basically tells the listener to start listening.

If you read the MultiThreading tutorial, you would know what the rest does. Also, if you read that tutorial, you would know that you need to abort a thread when the program ends:

Public Sub StopListening()
    t.Abort()
End Sub


Basically, what our ListenContinuously() sub will do, is keep checking for a TCPClient, and accept one in. When the server finds out that a client is trying to connect to it, its .Pending property will be set to True.

Private Sub ListenContinuously()
    While True = True

        If Listener.Pending = True Then
            AcceptClient()
        End If

        'PollForMessages() <This is for a later tutorial. That's why this line is commented out>
    End While
End Sub

Notice how it's a private sub. We don't want the user of this class to be able to call this sub directly, after all, it needs to be in a thread - so we'll use the StartListening and StopListening to control this sub basically.

Again, ignore the errors in AcceptClient(), we're going to get to that next.

To complete the rest of the tutorial, you will need to have a good knowledge of Collections: Please read the "Alternative To Arrays" tutorial for more information on this topic.

What we're going to do is, whenever a client connects, we'll add him to a Collection of clients. Let's first create that collection. In clsServer's globals:
Public Clients As New Collection


Now create a new sub:

Private Sub AcceptClient()
    Dim pendingClient As TcpClient
    pendingClient = Listener.AcceptTcpClient()

    Clients.Add(pendingClient)
End Sub

As I said before, when a client is trying to connect, the server's Pending property would be set to true, and we'd be taken to this sub. Basically all this does is establishes a connection between the client and the server.

We're going to play with this sub a bit, so that the client can give the server its name. But first I need to go explain what a stream is.

A stream is basically a connection between the client and the server. When a client connects to a server, a stream is established between the two (only one stream). That stream is the pathway for data to be sent.

At the top of your code:
Private reader As System.IO.StreamReader

Wait a minute! You've seen this before... somewhere..... yeah now you remember - the "Reading and Writing Text Files" tutorial. We used a StreamReader and a StreamWriter for this - the "Stream" was basically the text file.

In our case, for the server, we'll be receiving information from the Client (although we can send information too, but that's not the purpose of this tutorial), so the server will use a StreamReader and the Client will use a StreamWriter.

There's something else called a NetworkStream (we'll get to that in another tutorial), which relies on sockets - it's much more advanced than StreamReader and StreamWriter.

Anyways, back to the AcceptClient sub:

Private Sub AcceptClient()
     Dim pendingClient As TcpClient
     Dim nameOfClient As String
     pendingClient = Listener.AcceptTcpClient()
     reader = New System.IO.StreamReader(pendingClient.GetStream)
     nameOfClient = reader.ReadLine()

     Clients.Add(pendingClient, nameOfClient)
     MessageBox.Show(nameOfClient & " has just signed in.")
End Sub


There's only one major line here:

reader = New System.IO.StreamReader(pendingClient.GetStream)


The pendingClient.GetStream() method basically returns the stream which the Client and Server share, and the reader will read from it.

When the client connects (we'll make the client later in this tutorial), the first thing he'll send is his name.

Here's the thing: reader.ReadLine will wait until it receives a message before continuing.
This is a good thing because, let's say the client's PC lagged out, the server would still be waiting for him to send his name.
However this is a bad thing, because what if he never sent his name? These are the types of problems we'll be looking at in later tutorials.

Now for the good stuff. Go to form1's Form designer. Add 2 buttons: btnStartServer and btnStopServer.
Set btnStopServer's Enabled property to False (Because, how can you stop a server if it hasn't been started?).

In form1's globals:
 Dim server As New clsServer

In btnStartServer.Click:
server.StartListening()
btnStartServer.Enabled = False
btnStopServer.Enabled = True

In btnStopServer.Click:
server.StopListening()
btnStopServer.Enabled = False
btnStartServer.Enabled = True

In form1_Closing:
server.StopListening()

This tutorial won't go into the big specifics (since it's only the second tutorial in the Networking section), but please note that problems will arise if you stop the server when a client is connected.

The Client
Create a new project called Client. (Pretty basic name, I know).
I'll sort of breeze through this section, since you know most of the basics.

Create a new class called clsClient.

Imports System.Net
Imports System.Net.Sockets

Public Class clsClient
     Public Client As TcpClient
     Private writer As System.IO.StreamWriter
     Private name As String


     Public Sub Connect(ByVal IP As String, ByVal Port As Integer, ByVal yourName As String)
          Client = New TcpClient
          Client.Connect(IPAddress.Parse(IP), Port)
          name = yourName
          Me.SendMessage(yourName)
     End Sub

     Public Sub SendMessage(ByVal Message As String)
          Writer = New System.IO.StreamWriter(Client.GetStream)
          Writer.WriteLine(Message)
          Writer.Flush()
     End Sub

     Public Sub Die()
          Client.Close()
     End Sub
End Class

It's pretty basic actually  When you connect, the first thing you send to the server is your name. If you're not sure why, go take a look in clsServer.AddClient - the reader reads the name (and waits for the name). If you payed attention to the Reading and Writing Text Files tutorial, you'll know that Writer.Flush basically adds the text and saves changes.

NOTE: In the Reading and Writing Text Files tutorial, I clearly mentioned that you always do Writer.Close() when you're done with the file, but do NOT do this for networking! When you write to a text file, the Writer.Close method closes the file. Similarly, when you do Writer.Close for streams, it closes the Stream! It closes the connection between the client and the server.

It's pretty basic actually, look at the class as a whole and you'll understand it.

Now go to form1. Create 3 textboxes:
-Username     Name = txtUser ; Text = "vbProgrammer"
-IP Address    Name = txtIP     ; Text = "127.0.0.1"
-Port Number Name = txtPort  ; Text = "6580"

Create 2 buttons:
btnConnect
btnDisconnect ; Enabled = False

btnConnect.Click
client.Connect(txtIP.Text, txtPort.Text, txtUser.Text)

btnDisconnect.Click:
client.Die()

Now run the Server, press StartServer.
Run the Client, press Connect

Your firewall should act up, my ZoneAlarm said "Server.exe is trying to act as a server", and "Client.exe is trying to access the internet" (even though it's not). Just hit Accept.

If you're using windows firewall, I strongly urge you to get rid of that garbage, it does more harm than good. It might block the application from connecting, so just disable it.

Yay! You should get the message "vbProgrammer has signed in". However, press Disconnect and Connect again in the Client, you'll get an error in the server:
An unhandled exception of type 'System.ArgumentException' occurred in microsoft.visualbasic.dll

Additional information: Add failed. Duplicate key value supplied.

 Clients.Add(pendingClient, nameOfClient)

It's obviously because nameOfClient already exists in the collection Clients. We need to find out how to make it so that the client can Log Off when he disconnects. We'll take a look at that in later tutorials.

Oh one more thing - copy your Client project folder and paste it in a new folder called Client2.
Start the server.
Connect Client as "vbProgrammer"
Connect Client2 as "vbProgrammer2"

It should show you 2 messages:
"vbProgrammer has signed in"
"vbProgrammer2 has signed in"

For now, I hope this has been a good introductory tutorial.

That's pretty much it for this tutorial, the source code is in a RAR file containing 2 folders: Client and Server.

In the next tutorial, we'll do the same thing - except on the internet!
 

The Source Code for this tutorial is located here:

You can also locate this by logging in to vbProgramming Forums and going to:
Tutorials > Tutorial Source Code > Source Code