# VBForums CodeBank > CodeBank - Visual Basic .NET >  Client/Server Socket classes for file transfer

## moeur

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 clientsBroadcast(msgTag) - Sends a 1-byte message
Broadcast(msgTag, strX) - Sends a message string
Broadcast(msgTag, byteData()) - Sends array of Byte dataEvents: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 thisMethods: MsgTag is a 1-byte message identifier defined by end userSend(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 FilePathEvents: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 memoryStreamTransferProgress(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.

----------


## moeur

If you try out this code and find a problem then let me know.
Also any suggestions for additions to the code?

----------


## aditya12c

can u please upload whole project of transferring file... i need it to learn

----------


## moeur

OK, I've uploaded a client and Server app.

----------


## aditya12c

> 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

----------


## moeur

Are you getting the error when you try to load the two classes into a 2003 project that you build also?

----------


## aditya12c

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

----------


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

----------


## aditya12c

> 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

----------


## Inuyasha1782

Is it possible to actually send data with the client side? Like not a request, just raw data, like sending an HTTP Request to a webserver.

----------


## moeur

I don't understand the question.

If you have a connection with a server then the client can send data.

----------


## Inuyasha1782

You show code like this:



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

----------


## moeur

These two classes are for building your own client/server programs.

I think what you are saying is that you want to send data to a server that you have not written.

If that is the case then I would not use either of these classes, but instead use the tcpClient class that comes with .NET.

----------


## seanwill2

Okay, I'm having a major foobar here.  Everything works great but how do I make the server disconnect the client when I want it to? Or Vice Versa.

----------


## Chris2k

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.

Thanks Chris

----------


## haae

Hi,
Thanks for the great work.
But i need to know how to disconnect programtically the client from the server.

----------


## tiger03

Correct me if I am wrong, but there is a method on the client side. Method is called "client_Disconnect" which handles "client.disconnect"

you can either call the method above or create a method or a button which can handle client.disconnect event.

Hope that helps.

----------


## mityVB2005

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.

----------


## mityVB2005

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
                    Me.client.GetStream.BeginRead(readByte, 0, 1, AddressOf ReceiveOneByte, Nothing)
                End SyncLock
                'once all data has arrived, pass it on to the end user as a stream
                RaiseEvent DataReceived(Me, passThroughByte, mStream)
                mStream.Dispose()
It solved My Issue. Any ideas if this code may raise any other issues i missed.

----------


## mityVB2005

Another Issue is that u get error if you are Broadcasting and at that moment one of the clients get closed. You get collection modified exception.

----------


## sachavdk

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?

Thanx,

Sacha

----------


## moeur

see post #1 for cross-thread answer

----------


## sachavdk

Must have overlooked it  :Blush:  .
I've looked at the sub to set the image of the picturebox,
but I can't get it to work some way with my datagrid.

The delegate sub and setpicture sub using invokerequired etc is all new to me.
What I actually want, is adding a row to a datagrid.

I have a sub:


VB Code:
Private Sub writeOutput()
         Dim row As New DataGridViewRow
        row.Height = 16
         ' all code for adding cells to the row
        ' after that, it should add the row to the datagrid
         dgOutput.Rows.Add(row) ' dgOutput is the datagrid I can`t access
        row.Dispose()
        row = Nothing
                
End Sub

this sub writeOutput() is called in the listener_ConnectionRequest sub.
Any help would be appreciated  :Smilie:  .

Thank you.

----------


## mityVB2005

This block of code gives errors!
selected string raises errors when socket is not connected.

VB Code:
[U][I][B] SyncLock client.GetStream[/B][/I][/U]
            'if error occurs here then socket has closed
            Try
                client.GetStream.EndRead(ar)
            Catch
                RaiseEvent Disconnect(Me)
                Exit Sub
            End Try
        End SyncLock

I guess u need to change this block to:


VB Code:
Try
            SyncLock client.GetStream
                'if error occurs here then socket has closed
                client.GetStream.EndRead(ar)
            End SyncLock
        Catch
            RaiseEvent Disconnect(Me)
            Exit Sub
        End Try

----------


## mityVB2005

To sachavdk


VB Code:
Private Delegate Sub DGwriteOutput()
 Private Sub listener_ConnectionRequest(...) Handles ...
....
dgOutput.Invoke(new DGwriteOutput(AddressOf writeOutput))
.....
End Sub
 Private Sub writeOutput()
         Dim row As New DataGridViewRow
        row.Height = 16
         ' all code for adding cells to the row
        ' after that, it should add the row to the datagrid
         dgOutput.Rows.Add(row) ' dgOutput is the datagrid I can`t access
        row.Dispose()
        row = Nothing
                
End Sub

----------


## ctbny

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.

----------


## moeur

I'm sorry, but I don't have much time to look into this problem for you. Did you try making the change suggested in post #24?

----------


## kpryor@carti.com

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?

----------


## Zapper

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.

----------


## moeur

In the code for the tcpConnection.SendFile method,  Add the following line



```
            Loop While byteArray.Length = PACKET_SIZE
            'make sure all data is sent
            w.Flush()
            w.Close() '<=== Add this line
        End SyncLock
    End Sub
#End Region
```

----------


## Zapper

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,

So:
fs.close()
r.close()

----------


## Zapper

nvm (delete this post)?

----------


## mik@

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?

----------


## Zapper

Hi Mik! Welcome to the forums!

Well first, can you either tell us what you mean by receiving a file with loop or show post up some code you have written?

----------


## mik@

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?

            ' While action finnished

            ' End While
        Next

    End Sub

----------


## Zapper

(edit) wait it was asynchronous,
I think there is a Check for "Progress" Routine in his class?

What was the error by the way?

----------


## mik@

How can I chech "Progress" Routine?

No errors, the server program only crash and Client jam and
when I Debug all is OK because step by step debug still program run time.

I write two seconds "pause" routine before send routine and all work OK, but I don't know what happen when used very slow network connection.

that's why I want use the check routine

----------


## moeur

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


```
    Private FileNumber As Integer = 1
    Private Const LastFile As Integer = 5
```

Then, to start the transfer begin with the first file


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


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

----------


## Zapper

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.

----------


## milesh2160

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.

----------


## moeur

Thanks Milesh,

I'm sure this will help many.

----------


## i am bob

:Thumb:  Elegant coding. I even can modified it into integrated chat apps.
But can you tell me how can I retrieve sender ip address when
a request coming in the server side.

"Case Requests.PictureFile
                Sender.SendFile(msgTag, picDir & message)"

I've debugging almost every parts of the code, but still can find the
"sender" ip.  :Ehh:  
Can anyone help?
Thx in advance

----------


## milesh2160

Re #42 the IP address and port can be obtained from the listener_ConnectionRequest event. The sender is objet type of System.Net.Sockets.TcpClient this means the IP address and Port can be retrieved using the following syntax:


vb Code:
Requestor.Client.RemoteEndPoint.ToString.Substring


I use the following to remove the port from the value from the returned from the above statement.


vb Code:
ClientIP= Requestor.Client.RemoteEndPoint.ToString.Substring(0, Requestor.Client.RemoteEndPoint.ToString.IndexOf(":"))

It would appear that the server would have to forward the sender's IP.

----------


## i am bob

Thanks for the quick response, Milesh.
I've already got it if it comes in the "listener_ConnectionRequest" event.
But if you had several clients connecting in the same time, how would you know which client(s) requesting data or image? 
(back to the "listener_StringReceived" event)

I'm still working on it right now and testing any possibilities.
I should back to you later.

----------


## i am bob

Resolved!!

Using the client port(s) and ip(s) retrieved from the "listener_ConnectionRequest" event and sent its values to a public array.
And when the client disconnected, call the array with indexes from "client.tag" in the "listener_MessageReceived" event.

Cheers

----------


## prashantRawal

To Moeur

Hi ....I M Trying to implement Remote Desktop Viewer for my academic project submission...
and I have used ur code for that and thanks alot for that.


But the thing i wanted to ask u that how can i send the images i captured and saved on one Pc to the viewer on other PC using ur code...

i've tried sending files on request repeatedly but i've failed to co-ordinate the request and the response...
i've modified code as below for requesting


```
Private Sub cmdGetPicture_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
        Handles cmdGetPicture.Click
        'request a picture file from server
        For i As Integer = 0 To 30 Step 1
            client.Send(Requests.PictureFile, i & ".jpg")
            If i = 30 Then
                i = 0
            End If
        Next

    End Sub
```

and created the files at other side as below:



```
 
Private Sub frmServer_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        'start listening on our port as soon as the form loads
        listener = New clsListener(PORT_NUM, PACKET_SIZE)
        thrd1 = New Thread(AddressOf listener.createFile)
        thrd1.Start()
    End Sub
```


ur immidiate help would be grateful sir....

----------


## softwareguy74

Is there a way to make this multithreaded in that the server can handle processing more than one request at a time?  For example, I'm using the included client app to get a very large file.  As the file is being received by the client, the client is not yet locked up. But if I attempt to click the "GetImage" button, it locks up and waits until the large file is downloaded, and then proceeds.  I'm not sure if this is a client or server issue.

----------


## mwibowo88@gmail.com

:Frown: 
I'm trying to put this code around. But what i get is an error. Object references is not set to an instance of object. Can anybody help me fixing the code?

    Private Declare Sub keybd_event Lib "user32" (ByVal bVk As Byte, ByVal bScan As Byte, ByVal dwFlags As Integer, ByVal dwExtraInfo As Integer)

    Private Const VK_SNAPSHOT As Short = &H2CS

    dim bmap as bitmap

    Public Sub testing()
        Call keybd_event(System.Windows.Forms.Keys.Snapshot, 0, 0, 0)
        Dim data As IDataObject

        data = Clipboard.GetDataObject()

        If data.GetDataPresent(GetType(System.Drawing.Bitmap)) Then
            bmap = CType(data.GetData(GetType(System.Drawing.Bitmap)), Bitmap)
        End If
                Catch e As Exception
            MsgBox(e.ToString())
        End Try
    End Sub

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
                testing()
                sender.SendImage(msgTag, bmap)
        End Select
    End Sub

Please help me fix the code. Thanks in advance  :Smilie:

----------


## tomasoft

Hello, i just wanted to ask is it possible to be able to transfer a file from client to server, not just from server to client as it is now?

e.g i have a button now on client form that when i press it gets a file from the server. i also want to have a button that when i press will send a file from the client side to the server.

Thank you in advance,
Tom

----------


## solid2005

How to kick all connection on the server? not closing the application and restart the connection?

----------


## Niya

It doesn't appear that he has provided a means to do that through his class. In such a case you must access the underlying Socket object which has a Disconnect method.

----------


## Mogge

Hi there

Simple question... the origional thread was from 2004 - now we are in 2014 and talking vb in Visual Studio 2013.

Is there any of your bright heads that could help in refreshing this to work in VS.net 2013, please?

I'm to new to do this... have tried but in the client part are several parts not handled corretly be the normal upgrade function in VS.net...

Thx.

Best Regards
/Mogens

----------


## solid2005

How to send file client to server? 
i saw a code but IDK how to declared for client.SendFile(IDK what to do here., "D:\Ads").

----------


## Niya

Boo!!

----------

