|
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
|