Server Client Communication - File Sending
Hi, I'm looking to create a program which will allow the server and my client computers to communicate. I've been looking at this tutorial:
http://msdn2.microsoft.com/en-us/library/aa478452.aspx
Which has been useful for the most part (apart from a few mistakes the writer made, which I've managed to correct), but, when I try to send a message from the client, the server errors with a cross threading error.
What I want to be able to do is, send and receive from the client, as well as the server, I will have multiple clients sending and receiving data from the server application, but I would like the server to be able to send messages to any / all clients.
This is pretty basic operation, and I'm a bit miffed that I can't get it to work :o
so any help would be muchly appreciated
Cheers :thumb:
Re: Server Client Communication
Post the exact error messages and the lines on which they occur and we'll help you fix it :)
Re: Server Client Communication
Legend;
Quote:
Cross-thread operation not valid: Control 'lstStatus' accessed from a thread other than the thread it was created on.
Line 2;
VB Code:
Private Sub UpdateStatus(ByVal t As String)
lstStatus.Items.Add(t)
lstStatus.SetSelected(lstStatus.Items.Count - 1, True)
End Sub
All code is the same as on the tutorial, apart from a couple of fixes:
Dim mobjThread =...
Re: Server Client Communication
Quote:
Originally Posted by Dayjo
Legend;
Line 2;
VB Code:
Private Sub UpdateStatus(ByVal t As String)
lstStatus.Items.Add(t)
lstStatus.SetSelected(lstStatus.Items.Count - 1, True)
End Sub
You have to use delegates to access controls with safe cross-thread calls.
VB.NET Code:
Private Delegate Sub UpdateStatusCallBack(ByVal t As String)
Private Sub UpdateStatus(ByVal t As String)
If lstStatus.InvokeRequired Then
lstStatus.Invoke(New UpdateStatusCallBack(AddressOf UpdateStatus), t)
Else
lstStatus.Items.Add(t)
lstStatus.SetSelected(lstStatus.Items.Count - 1, True)
End If
End Sub
This is the general structure for making safe cross-thread calls. If you take a look at jmcillhinney's signature, you'll find a link to his thread dedicated to this topic.
Quote:
Originally Posted by Dayjo
All code is the same as on the tutorial, apart from a couple of fixes:
Dim mobjThread =...
The reason why there was no 'Dim' there is because that statement was not a declaration, but an instantiation. The thread should be declared at class level.
Re: Server Client Communication
Duh :), Thanks dude, sometimes I listen but don't hear... well.. read.. but don't .. think :P (it was 7am and my coffee hasn't hit yet )
So how would I go about communicating back to the client (Depending on their IP)
Re: Server Client Communication
I haven't looked closely on that code (mainly because the page is big, and i hate scrolling around like crazy to find stuff;)), but if I havent missed something essential, I believe each incoming connection is encapsulated in a 'Client' class and stored in a Hashtable. If you want to send something back to the client when something was received, use the 'sender' parameter:
VB.NET Code:
Private Sub OnLineReceived(ByVal sender As Client, ByVal Data As String)
Select Case Data
Case "something"
sender.Send("Reply" & vbCrLf)
End Select
End Sub
Normally you shouldnt need to worry about the clients IP's, but if you do need to retrieve it, you can get it from the TcpClients Client.RemoteEndPoint member. The TcpClient is encapsulated in the Client class, so you'd need to create a new public property to return this EndPoint.
Re: Server Client Communication
Yeah, that's how I thought, however I'm a little confused about the clients 'listening' ability.
Here is the Client's code:
vb Code:
Imports System.Net.Sockets
Imports System.Text
Public Class Form1
Private mobjClient As TcpClient
Private marData(1024) As Byte
Private mobjText As New StringBuilder()
Public Delegate Sub DisplayInvoker(ByVal t As String)
Private Sub DisplayText(ByVal t As String)
txtDisplay.AppendText(t)
End Sub
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
mobjClient = New TcpClient("192.168.1.162", 3900)
DisplayText("Connected to server" & vbCrLf)
End Sub
Private Sub Send(ByVal Data As String)
Dim w As New IO.StreamWriter(mobjClient.GetStream)
w.Write(Data & vbCr)
w.Flush()
End Sub
Private Sub btnSend_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSend.Click
Send(txtSend.Text)
txtSend.Text = ""
End Sub
Private Sub MarkAsDisconnected()
DisplayText("Connection failed!")
End Sub
Private Sub DoRead(ByVal ar As IAsyncResult)
Dim intCount As Integer
Try
intCount = mobjClient.GetStream.EndRead(ar)
If intCount < 1 Then
MarkAsDisconnected()
Exit Sub
End If
BuildString(marData, 0, intCount)
mobjClient.GetStream.BeginRead(marData, 0, 1024, _
AddressOf DoRead, Nothing)
Catch e As Exception
MarkAsDisconnected()
End Try
End Sub
Private Sub BuildString(ByVal Bytes() As Byte, _
ByVal offset As Integer, ByVal count As Integer)
Dim intIndex As Integer
For intIndex = offset To offset + count - 1
If Bytes(intIndex) = 10 Then
mobjText.Append(vbLf)
Dim params() As Object = {mobjText.ToString}
Me.Invoke(New DisplayInvoker(AddressOf Me.DisplayText), params)
mobjText = New StringBuilder()
Else
mobjText.Append(ChrW(Bytes(intIndex)))
End If
Next
End Sub
End Class
Thanks for your help by the way :) Nice to get decent response here after so long!
Re: Server Client Communication
You never begin reading fom the networkstream. This line will start reading asynchronously from the stream:
VB.NET Code:
mobjClient.GetStream.BeginRead(marData, 0, 1024, AddressOf DoRead, Nothing)
Re: Server Client Communication
Yeah I figured. I wasn't entirely sure of the parameters for the beginread function :).
Well, thanks a bunch, I'll mark this as resolved and if I have any other problems I can create a new topic. :thumb:
Thanks!
Dayjo
Re: [RESOLVED] Server Client Communication
Great:) I enjoy discussing networking so dont hesitate post away! :D
Re: Server Client Communication - File Sending
Well, because I figured if anyone was to help they'd want to know what code I'm using (which is above), and so I don't have to explain it all again.
But I'm trying to send a file across the network from the server to the client, but I'm having trouble with how I go about doing it.
I can obviously turn the file into a byte array, and send that, but the Client.Send method only supports string, do I have to convert the byte array to string? or can I just modify the Send method to send arrays too?
BTW, this IS my first time programming across networks so don't get upset :D.
Thankies
Re: Server Client Communication - File Sending
Alright, first tell me more about your application. Will you only be sending files? Will you be sending other data aswell? Will you be needing to send/receive several files at once?
The reason I'm asking is because this can be done in several ways, depending on your applications needs/design.
Re: Server Client Communication - File Sending
Ok, well, I would like to be able to send / receive files between the client and server, however it would be preferable if the other communication between the two applications could continue.
I'm not bothered about being able to send multiple files, but maybe, seeing as I want the opportunity to send images from video sources, like webcams, video cameras and the screen display device. :)
Re: Server Client Communication - File Sending
Ah alright. We'll I would take the same approach as the FTP protocoll does. That is:
- Have 1 "main" TCP connection, in which all "generic" stuff would be sent.
- Create one new TCP connection for each file transfer.
You'd need to create a separate class for the file transfer. Both on the server and the client.
When host A requests a file from host B (and host B accepts the request), host A would create an instance of this class which then starts to listen on a specific port, this portnumber is sent to Host B on the main connection, when Host B receives the port number, it creates an instance of the file transfer class, that connects to Host A on the specified port number, and starts reading bytes from the file and writing into the networkstream, in blocks of say..1024 bytes.
Give it a shot, dont hesitate to ask if something is unclear.
Re: Server Client Communication - File Sending
Ok, I've had a few goes and haven't managed to come up with anything that works yet, but a quick question... Say the client asks the server for a file, right then the server creates a new tcp connection, but the client doesn't have the ip of the server, do I need to send the client the ip so it knows what to connect to?
Re: Server Client Communication - File Sending
Wouldnt the client already have the IP, seeing as it just made a request to the server?
Re: Server Client Communication - File Sending
Ah, haha I meant the server doesn't have the client's ip :P.. I'm confusing myself.. because the 'server' is my client.. lol, because the client is what I run on my computer, and the server is run on the other computers..
So the client asks the server for a file, and the server sends the client that file. But because the server is connected to by the server, it doesn't have it's IP.
God this is confusing lol.
Re: Server Client Communication - File Sending
Ah well you see. When the client has connected to the server, there is a connection between the two hosts, in the form of a stream. So whenever the client sends something to the server, the server just sends its reply back on the same stream that it got the message from.
So the server should actually never need to bother about IP's. However the client must have the servers IP in order to connect to it.
Thats (one of) the advantage(s) of using the TCP protocoll, being a connection-based protocoll, there will always be a connection between the two hosts until one host decides to disconnect.