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.
clsListener
Constructor:
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
tcpConnection
Constructor:
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)
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.
Re: Client/Server Socket classes for file transfer
Originally Posted by moeur
OK, I've uploaded a client and Server app.
hey man thanks but still having poblem i am using vb.net 2003 while i think u made it in upper version so i am getting error message that this form is made on higher version of visual studio... any suggestion which will help me to run this program or is it i have to install 2005
Re: Client/Server Socket classes for file transfer
Originally Posted by moeur
Are you getting the error when you try to load the two classes into a 2003 project that you build also?
dude i dint get u what u asking ........... but if u mean that do i get error when i load any of other project in 2003.... than no i dont get error but when i am loading ur project i am getting error as i had mentioned above.
can u please tell me which version of .net u had used.
Re: Client/Server Socket classes for file transfer
The project was developed in 2005, but you should be able to load the clsListener.vb and tcpConnection.vb files into a new project in 2003. Then in your form just enter the code I show above.
Re: Client/Server Socket classes for file transfer
Originally Posted by moeur
The project was developed in 2005, but you should be able to load the clsListener.vb and tcpConnection.vb files into a new project in 2003. Then in your form just enter the code I show above.
Does that not work?
will try and let u know thanks dude....... or atlast will find for 2005 cd and install it and work ur program der
Re: Client/Server Socket classes for file transfer
You show code like this:
Code:
client.Send(Requests.DataFile, "wg_cs_1.mpg")
That requests a data file from the server, and tells it the file it wants. Well, I don't want to request a file, I just want to send a command to the server, how do I do that?
Age - 15 ::: Level - Advanced
If you find my post useful please ::Rate It::
Re: Client/Server Socket classes for file transfer
Hey,
Thanks for all your effect in this moeur, Impressive easy to use bit off code.
What i am interested in is adding a user/password authentication between the client and server do you have any idea how this could be done. I have looked everywhere but cant find anything unless i am looking in the wrong places.
Re: Client/Server Socket classes for file transfer
Error! Messages get joined. To use Zero length EndReceive Reply to devide one message from another is wrong because if you send one message after another in multi-thread app and if client and server on the same PC you don't have Zero length EndReceive Reply betwin messages. So some messages get lost.
Solution! You need to implement message length field and parse In Buffer which will be appended when new data received.
Re: Client/Server Socket classes for file transfer
oops! it IS implemented, but doesn't work in described conditions.
I replaced original "Case RequestTags.DataTransfer" in "tcpConnection.ReadOneByte" with following:
VB Code:
Case RequestTags.DataTransfer
'a block of data is coming
'Format of this transaction is
' DataTransfer identifier byte
' Pass-Through Byte contains user defined data
' Length of data block (max size = 2,147,483,647 bytes)
SyncLock client.GetStream
r = New BinaryReader(client.GetStream)
'next we expect a pass-through byte
passThroughByte = r.ReadByte
'next expect length of data (Int32)
lenData = r.ReadInt32
'now comes the data, save it in a memory stream
mStream = New MemoryStream()
mStream.Write(r.ReadBytes(lenData), 0, lenData)
mStream.Capacity = lenData
'Continue the asynchronous read from the NetworkStream
Re: Client/Server Socket classes for file transfer
Hi all,
I have a related question, but not an issue or so.
I tried the code and it seems to work fine.
But I added some kind of log datagrid.
But when I try to access the datagrid in the listener_ConnectionRequest sub of the server form, I get a cross-thread exception.
Is there any way I can access that control from that sub?
Re: Client/Server Socket classes for file transfer
Thank you to Moeur for a great bit of code, but I am still confused on one aspect of it. When either the server or a client loses connection, I am not sure how to handle it. As it is, my program instantly crashes on the client end if I exit the program on the server end, for example.
Re: Client/Server Socket classes for file transfer
After I run the SaveFile routine, I am getting a Permissions Denied error when trying to update the original file and when I rename and move the original file. Is there any code to run to disconnect from the original file once it has been saved in it's new spot?
Re: Client/Server Socket classes for file transfer
Excuse me, I'm very Dependant on and thankful for this class noeur.
And though I'm still amaturish, i think i found a BUG.(edit: wait, the guy above already noticed it ><)
It has something to do with file transfer. After the class reads from a certain file and writes it into the stream, the class/process is still attached to the file in someway. (i don't think the reader is closed properly) so when i try to modify/delete/open THAT file after the 'reading' a exception is thrown.
Re: Client/Server Socket classes for file transfer
Thanks for the reply. But yes i have tried that before, and theres another problem with that. If you close it there, then when u try to send the file next time, the writer would still be closed, hence another exception.
A friend gave me the advice to close the readers or whatever in instead, so for future reference add,
Re: Client/Server Socket classes for file transfer
Hi, I send and received data, all work OK when I send / received file alone. But when I tried to sent / received file with loop, program stopped. Question, how can I check when latest event (send or received) is done?
Re: Client/Server Socket classes for file transfer
Hi
I mean loop, if I have 10 picture names in listbox and I send all pictures of the list with loop.
same is possible for...next statement, example:
Private Sub cmdGetFile_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles cmdGetFile.Click
Dim x As Integer
'request a file from server
' Example getting pictures
RecPathFile = "C:\Users\Dan\Pictures\"
For x = 1 To 5
client.Send(Requests.DataFile, RecPathFile & x & ".jpg")
' How can I test when last action is finnish?
Re: Client/Server Socket classes for file transfer
This class can really only handle one file at a time. Therefore this is how I would handle transferring your five files. Add these two line at the form level
Code:
Private FileNumber As Integer = 1
Private Const LastFile As Integer = 5
Then, to start the transfer begin with the first file
Code:
Private Sub cmdGetFile_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles cmdGetFile.Click
'request 1st file from server
client.Send(Requests.DataFile, String.Format("RecPathFile{0}.jpg", FileNumber))
End Sub
Finally, when the file has finished transferring automatically begin transfer of the next. Keep doing this until all files have been transferred.
Code:
Private Sub client_DataReceived(ByVal Sender As tcpConnection, ByVal msgTag As Byte, _
ByVal mstream As System.IO.MemoryStream) Handles client.DataReceived
Select Case msgTag
Case Requests.DataFile
'save file data to a local file
SaveFile(String.Format("RecPathFile{0}.jpg", FileNumber), mstream)
'increment file number
FileNumber += 1
'request next file
If FileNumber <= LastFile Then
client.Send(Requests.DataFile, String.Format("RecPathFile{0}.jpg", FileNumber))
Else
MsgBox("All files have been transferred")
End If
End Select
End Sub
I haven't tested this so you might have to debug a step or two, but I think it should work.
Re: Client/Server Socket classes for file transfer
I struggled to modify the sendfile() to a sendimage() function in the tcpConnectionClass. But i managed somehow, tested and working:
vb Code:
Public Sub SendImage(ByVal msgTag As Byte, ByVal Image As Bitmap)
'max filesize is 2GB
Dim ms As New MemoryStream
'Converts the image into a memory stream
Image.Save(ms, Imaging.ImageFormat.Jpeg)
SyncLock client.GetStream
Dim w As New BinaryWriter(client.GetStream)
'notify that image data is coming
w.Write(RequestTags.DataTransfer)
'send user-define message byte
w.Write(msgTag)
'send size of image
w.Write(CInt(ms.Length))
'Converts memory stream into an array of bytes to be sent
Dim byteArray() As Byte = ms.GetBuffer()
'Send the image data
For i As Long = 0 To ms.Length Step PACKET_SIZE
If ms.Length - i >= PACKET_SIZE Then
w.Write(byteArray, CInt(i), PACKET_SIZE)
Else
w.Write(byteArray, CInt(i), CInt(ms.Length - i))
End If
Next
'make sure all data is sent
w.Flush()
End SyncLock
ms.Close()
End Sub
Upon the image being Received, the DataReceived Event event will be raised.
Hope you enjoy it and find it useful. As i am an amateur, suggestions of how I can improve the code is appreciated.
Last edited by Zapper; Sep 20th, 2008 at 03:16 AM.
Re: Client/Server Socket classes for file transfer
Thanks to Mr Moeur for this flexible piece of code. I believe I have discovered why the application crashes when a connection is lost. It is due to System.Net.Sockets.SocketError.ConnectionAborted() error. I have not figured out how to capture this error and raise the error to other class files.
I stumbled upon this condition when toggling the AllowConnection from true to false during code execution.
I resolved this issue by adding the following "Requestor.Client.Disconnect(True)" to the Listener_ConnectionRequest method
vb Code:
Private Sub Listener_ConnectionRequest(ByVal Requestor As System.Net.Sockets.TcpClient, ByRef AllowConnection As Boolean) Handles Listener.ConnectionRequest
AllowConnection = CheckBox1.Checked
If AllowConnection = False Then
Requestor.Client.Disconnect(True)
End If
End Sub
As I can best understand it the Requestor.Client.Disconnect(True) allows for a graceful disconnection to the Socket that the TCPClient that has initiated the connection. I hope that this helps some one else.
You will have to stop and start the listener again in order to accept connections if you stop allowing connections.