简体   繁体   中英

sending a large amount of data throught TCP socket

This is my first question posted on this forum, and I'm a beginner in c# world , so this is kind of exciting for me, but I'm facing some issues with sending a large amount of data through sockets so this is more details about my problem:

I'm sending a binary image of 5 Mo through a TCP socket, at the receiving part I'm saving the result(data received ) and getting only 1.5 Mo ==> data has been lost (I compared the original and the resulting file and it showed me the missed parts) this is the code I use:

private void senduimage_Click(object sender, EventArgs e)
{
    if (!user.clientSocket_NewSocket.Connected)
    {
        Socket clientSocket_NewSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        user.clientSocket_NewSocket = clientSocket_NewSocket;
        System.IAsyncResult _NewSocket = user.clientSocket_NewSocket.BeginConnect(ip_address, NewSocket.Transceiver_TCP_Port, null, null);
        bool successNewSocket = _NewSocket.AsyncWaitHandle.WaitOne(2000, true);
     }
     byte[] outStream = System.Text.Encoding.ASCII.GetBytes(Uimage_Data);
     user.clientSocket_NewSocket.Send(outStream);
 }

In forums they say to divide data into chunks, is this a solution, if so how can I do this, I've tried but it didn't work!

There are lots of different solutions but chunking is usually a good solution, you can either do this blindly where you keep filling your temporary buffer and then putting it into some stateful buffer until you hit some arbitrary token or the buffer is not completely full, or you can adhere to some sort of contract per tcp message (a message being the overall data to recieve).

If you were to look at doing some sort of contract then do something like the first N bytes of a message is the descriptor, which you could make as big or as small as you want, but your temp buffer will ONLY read this size up front from the stream.

A typical header could be something like:

public struct StreamHeader // 5 bytes
{
   public byte MessageType {get;set;} // 1 byte
   public int MessageSize {get;set;}  // 4 bytes
}

So you would read that in then if its small enough allocate the full message size to the temp buffer and read it all in, or if you deem it too big chunk it into sections and keep reading until the total bytes you have received match the MessageSize portion of your header structure.

Probably you haven't read the documentation on socket usage in C#. ( http://msdn.microsoft.com/en-us/library/ms145160.aspx )

The internal buffer can not store all the data you provided to send methode. A possible solution to your problem can be is like you said to divide your data into chunks.

int totalBytesToSend = outstream.length;     int bytesSend = 0;
while(bytesSend < totalBytesToSend )
    bytesSend+= user.clientSocket_NewSocket.Send(outStream, bytesSend, totalBytesToSend - bytesSend,...);

I suspect that one of your problems is that you are not calling EndConnect . From the MSDN documentation:

The asynchronous BeginConnect operation must be completed by calling the EndConnect method.

Also, the wait:-

bool successNewSocket = _NewSocket.AsyncWaitHandle.WaitOne(2000, true);

is probably always false as there is nothing setting the event to the signaled state. Usually, you would specify a callback function to the BeginConnect function and in the callback you'd call EndConnect and set the state of the event to signaled. See the example code on this MSDN page .

UPDATE

I think I see another problem:-

byte[] outStream = System.Text.Encoding.ASCII.GetBytes(Uimage_Data);

I don't know what type Uimage_Data but I really don't think you want to convert it to ASCII. A zero in the data may signal an end of data byte (or maybe a 26 or someother ASCII code). The point is, the encoding process is likely to be changing the data.

Can you provide the type for the Uimage_Data object?

Most likely the problem is that you are closing the client-side socket before all the data has been transmitted to the server, and it is therefore getting discarded.

By default when you close a socket, all untransmitted data (sitting in the operating system buffers) is discarded. There are a few solutions:

[1] Set SO_LINGER (see http://developerweb.net/viewtopic.php?id=2982 ) [2] Get the server to send an acknowledgement to the client, and don't close the client-side socket until you receive it. [3] Wait until the output buffer is empty on the client side before closing the socket (test using getsocketopt SO_SND_BUF - I'm not sure of the syntax on c#).

Also you really should be testing the return value of Send(). Although in theory it should block until it sends all the data, I would want to actually verify that and at least print an error message if there is a mismatch.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM