Question Connecting 2 Clients Through a Server - Fastest Transfer Method?

bigfoot3d

Well-known member
Joined
Mar 11, 2007
Messages
56
Location
New Orleans, LA
Programming Experience
3-5
The idea is in my head and so is the implementation, but not the syntax :(

This is what I am trying to do:
There are 3 Parts: Client A, Client B, and the Server

Client A and Client B are both connected to the Server.
Client A is trying to send a picture to Client B through the Server.

Client A and Client B are both behind separate firewalls, so there is no way to directly connect Client A to Client B except through the Server.

What would be the quickest way I would go about doing this.

I do not want to send the entire image to the Server and then the Server send it out. This is just wasting time, especially with larger images. I am trying to figure out how the Server would write the data from Client B as it is read from Client A.

I don't think there is a way to directly connect the sending stream from Client A to Client B in the Server, or is there?

If that is not possible, then how would I go about writing the data to Client B from the Server as it is being received from Client A?

Any thoughts, insights, or examples :confused:
 
You can't connect the streams, you have to read some from one and write it to the other.
 
I guess I am having trouble now figuring how to break it up and only read some and transfer some so as to know when I have finally transferred the whole thing. I was doing it asynchronously when I was directly connecting the two clients, but now I may have to do it just synchronously since I am using the Server as a middle man?

So how would I read some and write some to come out with a finished image at Client B?

How does Client B know when it has received the entire image since it is being received in sections?

I have done some playing around with the code, but it just simply doesn't complete the tasks and errors.
 
but now I may have to do it just synchronously since I am using the Server as a middle man?
no why?
how would I read some and write some
It is no different from before, I really don't see the problem.
How does Client B know when it has received the entire image
I don't know exactly how you are doing things, but this is also no different from sending from one party to another.
 
Hmm, but how would I send it in pieces to allow the Server to read and write at the same time. All I see that is happening here is that the Server completely receives it then sends it.

Is there a way for the server to send it as it receives it?

The code below works with no problems. Just I was hoping there was some way to increase the performance by allowing the Server to write the data as it is received from Client A to Client B. How would I make the server send the data as it is received rather than receive the entire block of data from Client A then send the entire block of data to Client B.

What I am trying to accomplish:

A: Send 1 S: Receive 1
S: Send 1 B: Receive 1 While A: Send 2 S: Receive 2
S: Send 2 B: Receive 2 While A: Send 3 S: Receive 3
S: Send 3 B: Receive 3

Instead what is happening here:

A: Send 123 S: Receive 123
S: Send 123 B: Receive 123


Client A:
VB.NET:
            HFHSendScreenTCP.GetStream.Write(compbytes, 0, compbytes.Length)
            'send(packet)
            HFHSendScreenTCP.GetStream.BeginWrite(mem.GetBuffer, 0, mem.Length, New AsyncCallback(AddressOf myWriteCallBack), _
HFHSendScreenTCP.GetStream)

Server:
VB.NET:
Public Sub myWriteCallBack(ByVal ar As IAsyncResult)
        Dim myNetworkStream As Net.Sockets.NetworkStream = CType(ar.AsyncState, Net.Sockets.NetworkStream)
        myNetworkStream.EndWrite(ar) 'blocks until finished sending
    End Sub 'myWriteCallBack

    Public Sub myReadCallBackHFHRecScreen(ByVal ar As IAsyncResult)
        Dim HFHSendScreen As Net.Sockets.NetworkStream = CType(ar.AsyncState, Net.Sockets.NetworkStream)
        Dim numberOfBytesReadHFHSendScreen As Integer = HFHSendScreen.EndRead(ar)
        If numberOfBytesReadHFHSendScreen > 0 Then
            If numberOfBytesReadHFHSendScreen = NumBytesInLengthHFHSendScreen Then
                'get packet length
                PacketLengthHFHSendScreen = BitConverter.ToInt32(bufferHFHSendScreen, 0)
            Else
                'write/get packet
                memHFHSendScreen.Write(bufferHFHSendScreen, 0, numberOfBytesReadHFHSendScreen)
                If memHFHSendScreen.Length = PacketLengthHFHSendScreen Then
                    getdataHFHSendScreen(memHFHSendScreen)
                    ReDim bufferHFHSendScreen(HFHTechSendScreenTCP.ReceiveBufferSize - 1)
                    memHFHSendScreen = New IO.MemoryStream(PacketLengthHFHSendScreen)
                End If
            End If
            'get next read buffer
            HFHSendScreen.BeginRead(bufferHFHSendScreen, 0, HFHSendScreenTCP.ReceiveBufferSize, _
New AsyncCallback(AddressOf myReadCallBackHFHRecScreen), HFHSendScreen)
        Else
            'socket disconnected
        End If
    End Sub 'myReadCallBack

    Sub getdataHFHSendScreen(ByVal mem As IO.MemoryStream)
        Dim compbytes() As Byte = BitConverter.GetBytes(CInt(mem.Length))
        Me.HFHTechSendScreenTCP.GetStream.Write(compbytes, 0, compbytes.Length)
        Me.HFHTechSendScreenTCP.GetStream.BeginWrite(mem.GetBuffer, 0, mem.Length, _
New AsyncCallback(AddressOf myWriteCallBack), Me.HFHTechSendScreenTCP.GetStream)
    End Sub

Client B:
VB.NET:
Public Sub myReadCallBackHFHRecScreen(ByVal ar As IAsyncResult)
        Dim HFHRecScreen As Net.Sockets.NetworkStream = CType(ar.AsyncState, Net.Sockets.NetworkStream)
        Dim numberOfBytesReadHFHRecScreen As Integer = HFHRecScreen.EndRead(ar)
        If numberOfBytesReadHFHRecScreen > 0 Then
            If numberOfBytesReadHFHRecScreen = NumBytesInLengthHFHRecScreen Then
                'get packet length
                PacketLengthHFHRecScreen = BitConverter.ToInt32(bufferHFHRecScreen, 0)
            Else
                'write/get packet
                memHFHRecScreen.Write(bufferHFHRecScreen, 0, numberOfBytesReadHFHRecScreen)
                If memHFHRecScreen.Length = PacketLengthHFHRecScreen Then
                   getdataHFHRecScreen(memHFHRecScreen)
                    ReDim bufferHFHRecScreen(HFHRecScreenTCP.ReceiveBufferSize - 1)
                    memHFHRecScreen = New IO.MemoryStream(PacketLengthHFHRecScreen)
                End If
            End If
            'get next read buffer
            HFHRecScreen.BeginRead(bufferHFHRecScreen, 0, HFHRecScreenTCP.ReceiveBufferSize, _
New AsyncCallback(AddressOf myReadCallBackHFHRecScreen), HFHRecScreen)
        Else
            'socket disconnected
        End If
    End Sub 'myReadCallBack


    Sub getdataHFHRecScreen(ByVal mem As IO.MemoryStream)
    'More Lovely Code Here
    End Sub
 
From what I gather your server deliberately waits until a full "packet" is received until it starts forwarding the data, why? It's only purpose is to read bytes from one and send bytes to another, unless you want to send messages to the server itself the server have no need to interpret the data, also in that case it would be better to use a dedicated control port. It could also look like you are targeting reading a specific number of bytes, if so you can't rely on specific bytes written to a networkstream is bundled together when transmitted.

Have a look at the attached sample CSC solution, it should be very similar to what you are doing. A much simpler communication interface is used by serializing packets between the clients, the server just forwards byte data continuosly. A request-response protocol is also implemented in order to prevent flooding of output buffers. Solution is multi-startup; server and both clients runs on debug. I don't have VS2005 installed for the time being, but you can install VB2008 Express or just review the source files, the code should be .Net 2.0 compatible.
 

Attachments

  • vbnet35-CSC.zip
    49.6 KB · Views: 35
JohnH,

Thanks once again for your must valuable insight.

You presented me with some code which showed me how to implement a asynchronous server just passing along the data which I have used to altered the way I am handling my reading to be the solution.

This is what I end up with in my server side code now which allows the code to be written as it is received.

VB.NET:
 Public Sub myReadCallBackHFHRecScreen(ByVal ar As IAsyncResult)
        Dim readbytes As Integer = Me.HFHSendScreenTCP.GetStream.EndRead(ar)
        Me.HFHTechSendScreenTCP.GetStream.BeginWrite(bufferHFHSendScreen, 0, readbytes, _
        New AsyncCallback(AddressOf Me.myWriteCallBack), Me.HFHTechSendScreenTCP.GetStream)
        'start next async read from client
        ReDim bufferHFHSendScreen(HFHSendScreenTCP.ReceiveBufferSize - 1)
        Me.HFHSendScreenTCP.GetStream.BeginRead(bufferHFHSendScreen, 0, HFHSendScreenTCP.ReceiveBufferSize, _
        New AsyncCallback(AddressOf Me.myReadCallBackHFHRecScreen), Me.HFHSendScreenTCP)
    End Sub
 
Back
Top