简体   繁体   中英

Not the whole data received in a socket C# WP8

The code below is perfectly working when i receive "small" data. But when i try to receive a big data , it always cut. The data that i received isn't whole

static ManualResetEvent _clientDone = new ManualResetEvent(false);

        const int TIMEOUT_MILLISECONDS = 500000000;

        const int MAX_BUFFER_SIZE = 2048;

 public string Receive_msg()
        {
            string response = "Operation Timeout";

            if (_socket != null)
            {
                SocketAsyncEventArgs socketEventArg = new SocketAsyncEventArgs();
                socketEventArg.RemoteEndPoint = _socket.RemoteEndPoint;

                socketEventArg.SetBuffer(new Byte[MAX_BUFFER_SIZE], 0, MAX_BUFFER_SIZE);


                socketEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(delegate(object s, SocketAsyncEventArgs e)
                {
                    if (e.SocketError == SocketError.Success)
                    {
                        response = Encoding.UTF8.GetString(e.Buffer, e.Offset, e.BytesTransferred);
                        response = response.Trim('\0');
                        Debug.WriteLine(response);
                    }
                    else
                    {
                        response = e.SocketError.ToString();
                    }

                    _clientDone.Set();
                });

                _clientDone.Reset();

                _socket.ReceiveAsync(socketEventArg);

                _clientDone.WaitOne(TIMEOUT_MILLISECONDS);
            }
            else
            {
                response = "Socket is not initialized";
            }
            return response;
        }

I tried to increase the value of the TIMEOUT_MILLISECONDS and the size of my MAX_BUFFER_SIZE , but nothing change. I need to be able to get a bigger data. And i must use this way, i can't use WebClient or HttpWebRequest...

If you didn't receive all the data you want, just call your receive function again.

Also, and this very important, before you implement anything on top of TCP, document the protocol you're using unless you're implementing a protocol that's already documented. It may be helpful to read the protocol documentation for some protocol layered on top of TCP such as SMTP, IRC, HTTP, or the like.

You can't count on getting all your data in a single socket read. You have to put in a loop that will continue to receive data until there is no more data to receive.

How, then, do you tell when you have received all your data? You have a couple of options: you can send a delimiter byte that will only appear at the end of the message; if you see that as the last byte received you are done. Otherwise, you can send the length of the message at the start of the message (this is what HTTP does, btw). Or you can have the sender close the socket when the message is complete, and just keep reading until there is an EOF condition on the socket.

The thing is that the receive call will only read the minimum length between the receiving packet size and the buffer you use for reading. I suspect the data you send to be too large and getting split by the system into smaller packets (called fragmentation).

I would prefix anything you send with an integer (4 bytes, the size of the data to come), read it on the receiving side and read bytes from the socket as long as you haven't received the length you sent as a header.

Edit: Since you can use TcpClient, I would recommend using this and the .GetStream() . Tell me if i'm wrong, but this program should send and receive strings only (according to your code). Here's what I would do:

public async Task<string> ReceiveString()
{
    NetworkStream netStream = _client.GetStream(); //Using _client instead of _socket
    StreamReader streamReader = new StreamReader(netStream);
    string result = await streamReader.ReadLine(); //Reading the stream until we find a newline
    return result;
}

And you would use it like so:

void MyMethod()
{
    string message = await ReceiveString(); //This is the fully async way, the "MyMethod" signature should be "async void" too in order to use "await"

    string message = ReceiveString().Result; //This is a blocking call, waits for everything to be received before proceding
}

Note: This code works if you end all your messages with a newline character. It also only applies if you only want to transfer strings (as mentioned above, I assumed).

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