Click here to Skip to main content
15,882,329 members
Please Sign up or sign in to vote.
1.50/5 (2 votes)
Hi, I have a connection to the server, I get data info from the server. Everything working fine if the server sends small data, a few hundred bytes, the problem occurs when the server sends large data, about a few thousands bytes, then I only receive first part, very little of the data, 256 first bytes. I want to get enough large data and write it to log textbox, how can I adjust in my code. This is my code.

 private async void _connect()
 {
 try
            {
                socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
                socket.SendTimeout = 180000;
                socket.ReceiveTimeout = 180000;
                socket.Connect(IPAddress.Parse("10.10.10.120"), 12345);			
                byte[] myReadBuffer = new byte[1024 * 10];
                int numberOfBytesRead = 0;
                bool _flag = false;
                bool _flagnextreceive = false;
                int _recleng = 0;
                stream = new NetworkStream(socket);
                while (true)
                {
                    if (_flag)
                    {
                        numberOfBytesRead = 0;
                        goto receiveskip;
                    }
					////after connect to host, send ack dummy from client to host
                    if (numberOfBytesRead == 0)
                    {	
                        byte[] data = Encoding.ASCII.GetBytes("ACKDUMMY");
                        stream.Write(data, 0, data.Length);
                        stream.Flush();
                        _flag = true;
                    }
                receiveskip:
				
                    numberOfBytesRead = stream.Read(myReadBuffer, 0, myReadBuffer.Length);
                    if (!_flagnextreceive)
                    {
                        byte[] _4byteleng = new byte[4];
                        Buffer.BlockCopy(myReadBuffer, 0, _4byteleng, 0, 4);
                        Array.Reverse(_4byteleng);
                        _recleng = BitConverter.ToInt32(_4byteleng, 0);
                    }
                    byte[] bytes_real = new byte[numberOfBytesRead];
                    Buffer.BlockCopy(myReadBuffer, 0, bytes_real, 0, numberOfBytesRead);
                    if (numberOfBytesRead < _recleng)
                    {
                        _flagnextreceive = true;
                        goto receiveskip;
                    }
                    if (numberOfBytesRead == _recleng)
                    {
                        _flagnextreceive = false;
                        goto _next;
                    }
                _next:
				
                    ////if received from host after send ack dummy from client to host, dont' do anything
                    if (bytes_real.Length == 14 && Encoding.ASCII.GetString(bytes_real) == "ACCEPTACK")
                    {
                        _flag = true;
                        goto receiveskip;
                    }
                    ////if received linked test data from host, reply with dummy data
                    if (bytes_real.Length == 14 && Encoding.ASCII.GetString(bytes_real) == "LINKTEST")
                    {
						byte[] data1 = Encoding.ASCII.GetBytes("ACCEPTLINKTEST");
                        stream.Write(data1, 0, data1.Length);
                        stream.Flush();
                        _flag = true;
                        goto receiveskip;
                    }
                    ////receive data from host, write to log
                    if (bytes_real.Length > 14)
                    {
                        txt_log.Invoke((Action)(() =>
                        {
                            txt_log.AppendText(Encoding.ASCII.GetString(bytes_real) + "\r\n");
                        }));
                        _flag = true;
                        goto receiveskip;
                    }
					////if can not receive from host, break while, it will disconnect with host
                    if (bytes_real.Length == 0)
                    {
                        break;
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("Warning: You are disconnected with host " + ex.Message);
            }
}


What I have tried:

When debug, if server send small data, everything is ok, can write to log textbox. But when server send large data, about thousands bytes (~10k bytes), my code loop and just get one first part 256 bytes and write to log textbox.
Posted
Updated 2-Aug-23 23:09pm

The problem you are facing is likely related to the way you are handling the data reception. Reading data from the stream using 'stream.Read' may not guarantee that you receive all the data at once, you should modify your code to read from the stream in a loop. Personally I will make use of asynchronous methods (await and async) to handle the socket operations, as this will improve your app's efficiency.

You can read up more on the methods and their usage from - MS Learn | Asynchronous programming[^]

Your code will look similar to -
C#
private async Task _connect()
{
    try
    {
        socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
        socket.SendTimeout = 180000;
        socket.ReceiveTimeout = 180000;
        await socket.ConnectAsync(IPAddress.Parse("10.10.10.120"), 12345);
        byte[] myReadBuffer = new byte[1024 * 10];
        int numberOfBytesRead = 0;
        bool _flag = false;
        bool _flagnextreceive = false;
        int _recleng = 0;
        stream = new NetworkStream(socket);
        while (true)
        {
            if (_flag)
            {
                numberOfBytesRead = 0;
                goto receiveskip;
            }

            //After connecting to the host, send an ack dummy from the client to your host...
            if (numberOfBytesRead == 0)
            {
                byte[] data = Encoding.ASCII.GetBytes("ACKDUMMY");
                await stream.WriteAsync(data, 0, data.Length);
                await stream.FlushAsync();
                _flag = true;
            }

        receiveskip:

            //Read the data from the stream in a loop until you have the complete data set...
            while (!_flagnextreceive && numberOfBytesRead < myReadBuffer.Length)
            {
                int bytesRead = await stream.ReadAsync(myReadBuffer, numberOfBytesRead, myReadBuffer.Length - numberOfBytesRead);
                if (bytesRead == 0)
                {
                    break; //Your connection has been closed by the server...
                }
                numberOfBytesRead += bytesRead;

                if (!_flagnextreceive && numberOfBytesRead >= 4) //Check if you received the length...
                {
                    byte[] _4byteleng = new byte[4];
                    Buffer.BlockCopy(myReadBuffer, 0, _4byteleng, 0, 4);
                    Array.Reverse(_4byteleng);
                    _recleng = BitConverter.ToInt32(_4byteleng, 0);
                    _flagnextreceive = true;
                }
            }

            if (numberOfBytesRead < _recleng)
            {
                _flagnextreceive = true;
                goto receiveskip;
            }

            if (numberOfBytesRead == _recleng)
            {
                _flagnextreceive = false;
                goto _next;
            }

        _next:

            //If data received from the host after sending an ack dummy from the client to your host, don't do anything here...
            if (numberOfBytesRead == 14 && Encoding.ASCII.GetString(myReadBuffer, 0, numberOfBytesRead) == "ACCEPTACK")
            {
                _flag = true;
                goto receiveskip;
            }

            //If received linked test data from your host, reply with dummy data...
            if (numberOfBytesRead == 14 && Encoding.ASCII.GetString(myReadBuffer, 0, numberOfBytesRead) == "LINKTEST")
            {
                byte[] data1 = Encoding.ASCII.GetBytes("ACCEPTLINKTEST");
                await stream.WriteAsync(data1, 0, data1.Length);
                await stream.FlushAsync();
                _flag = true;
                goto receiveskip;
            }

            //Receive data from the host and write it to your log file...
            if (numberOfBytesRead > 14)
            {
                txt_log.Invoke((Action)(() =>
                {
                    txt_log.AppendText(Encoding.ASCII.GetString(myReadBuffer, 0, numberOfBytesRead) + "\r\n");
                }));
                _flag = true;
                goto receiveskip;
            }

            //If you cannot receive data from your host, break the while loop, and it will disconnect from your host...
            if (numberOfBytesRead == 0)
            {
                break;
            }
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show("Warning: You are disconnected from the host " + ex.Message);
    }
}
 
Share this answer
 
Comments
headshot9x 3-Aug-23 5:49am    
Hi, I see difference from your code. It's mean we need one loop inside and get enough all byte data, which sent from server.
Andre Oosthuizen 3-Aug-23 5:58am    
Correct
headshot9x 5-Aug-23 6:59am    
Hi, I have tested and see it can be working until now. So, I'm not sure if anything abnormal in the future or not. But this way can be accept for other people looking for it. Thank for your idea.
For starters, get rid of the goto crap, and learn about if ... else if ... else can do to make your code readable. You should also look at a using block to ensure the server socket connection is released ...

THen use the debugger to find out what exactly your code is doing: what happens in your code when you do receive a "large" buffer. Single step through, and look at what is actually going on.

That is what I'd have to do in order to tray and fix it, and I'm not prepared to run code that badly written on my machine.
 
Share this answer
 
Comments
headshot9x 5-Aug-23 7:02am    
By the way, I have learn something about in this case also. It's good your touch point.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900