Here are two classes that can be used for client server applications:
a listener class for the server and a tcpConnection class for the client which the listener also creates dynamically as connection requests arrive.
These classes do most operations asnychronously in seperate threads, so in VB 2005 you have to either
VB Code:
CheckForIllegalCrossThreadCalls = False
or handle cross-thread calls properly.
Included are some nice methods for transferring files and large data blocks.
clsListenerConstructor:
Private WithEvents listener As clsListener
listener = New clsListener(PORT_NUM, optional DataBlockSize))
Methods: Send messages to all connected clients
Broadcast(msgTag) - Sends a 1-byte message
Broadcast(msgTag, strX) - Sends a message string
Broadcast(msgTag, byteData()) - Sends array of Byte data
Events:
ConnectionRequest(Requestor, AllowConnection) - Raised when a new connection request is made.
Set AllowConnection to True to accept connection, otherwise connection is denied.
Disconnect(Client) - A client has disconnected.
MessageReceived(Client, msgTag)
StringReceived(Client, msgTag, StrMessage) - Data is in a String
DataReceived(Client, msgTag, memStream) - Data is in a memoryStream
MsgTag is a 1-byte message identifier defined by end user
tcpConnectionConstructor:
From Client:
Private WithEvents client As tcpConnection
client = New tcpConnection("localhost", PORT_NUM)
From Server:
clsListener handles this
Methods: MsgTag is a 1-byte message identifier defined by end user
Send(msgTag) - sends only the user-defined message tag
Send(msgTag, strX) - sends a string
Send(msgTag, byteData()) - sends an array of bytes
SendFile(msgTag, FilePath) - Sends the contents of the file located at FilePath
Events:
Connect(ByVal sender As tcpConnection)
Disconnect(ByVal Sender As tcpConnection)
Data Reception: MsgTag is a 1-byte message identifier defined by end user
MessageReceived(Sender, msgTag)
StringReceived(Sender, msgTag, StrMessage) - Data is in a String
DataReceived(Sender, msgTag, memStream) - Data is in a memoryStream
TransferProgress(Sender, msgTag, Percentage) - Periodically notifies end user of what percentage of data
has been transfered for bytedata and file transfers
Examples of Use:
Server Side
The Listener starts to listen when the class is instantiated
VB Code:
Private WithEvents listener As clsListener
listener = New clsListener(PORT_NUM, PACKET_SIZE)
When a connection request comes in we have to decided whether to accept it or not.
VB Code:
Private Sub listener_ConnectionRequest(ByVal requestor As System.Net.Sockets.TcpClient, _
ByRef AllowConnection As Boolean) Handles listener.ConnectionRequest
'Here you can examine the requestor to determine whether to accept the connection or not
Debug.Print("Connection Request")
AllowConnection = True
End Sub
Now we have to decide how we want to respond to client requests. Here is an example of responding to a string sent from the client by sending back the file identified in the string.
VB Code:
Private Sub listener_StringReceived(ByVal Sender As tcpConnection, ByVal msgTag As Byte, _
ByVal message As String) Handles listener.StringReceived
'This is where the client will send us requests for file data using our
' predefined message tags
Debug.Print("String Received from Client: " & message)
Select Case msgTag
Case Requests.PictureFile
Sender.SendFile(msgTag, picDir & message)
Case Requests.DataFile
Sender.SendFile(msgTag, fileDir & message)
End Select
End Sub
Client Side
Connect to our server
VB Code:
Private WithEvents client As tcpConnection
Private Sub cmdConnect_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles cmdConnect.Click
Try
client = New tcpConnection(txtServer.Text, PORT_NUM)
Catch ex As Exception
MessageBox.Show(Me, ex.Message, "Network Error", MessageBoxButtons.OK, _
MessageBoxIcon.Error)
Me.Dispose()
End Try
End Sub
Our server is set up to accept requests for picture and data files. Request a Picture vbcode]client.Send(Requests.PictureFile, "bliss.bmp")[/Highlight]Request a file
VB Code:
client.Send(Requests.DataFile, "wg_cs_1.mpg")
The responses will come here. When they come in put the picture into our local picturebox control and save the file to the local disk.
VB Code:
Private Sub client_DataReceived(ByVal Sender As tcpConnection, ByVal msgTag As Byte, _
ByVal mstream As System.IO.MemoryStream) Handles client.DataReceived
'This code is run in a seperate thread from the thread that started the form
'so we must either handle any control access in a special thread-safe way
'or ignore illegal cross thread calls
Select Case msgTag
Case Requests.PictureFile
'picture data, put into our local picturebox control
'use a thread-safe manner for this action
SetPicture(mstream)
Case Requests.DataFile
'file data, save to a local file
SaveFile("C:\new.mpg", mstream)
End Select
End Sub
#Region "How to properly handle cross thread calls instead of ignoring them"
Delegate Sub SetPictureCallback(ByVal mstream As System.IO.MemoryStream)
Private Sub SetPicture(ByVal mstream As System.IO.MemoryStream)
' Thread-safe way to access the picturebox
' This isn't really needed because we are ignoring illegal cross thread calls.
If Me.PictureBox1.InvokeRequired Then
Dim d As New SetPictureCallback(AddressOf SetPicture)
Me.Invoke(d, New Object() {mstream})
Else
PictureBox1.Image = Image.FromStream(mstream)
End If
End Sub
#End Region
Private Sub SaveFile(ByVal FilePath As String, ByVal mstream As System.IO.MemoryStream)
'save file to path specified
Dim FS As New FileStream(FilePath, IO.FileMode.Create, IO.FileAccess.Write)
mstream.WriteTo(FS)
mstream.Flush()
FS.Close()
End Sub
Attached are the full projects
Changes:Fixed bug that prevented more than one client from connecting to server.
Fixed problem with percent data transferred number.
Added data block size parameter to Listener class constructor.