Search code examples
c#tcp

TCP Receive does not return expected number of bytes


I using TCPIP to get data from a controller. When using TCPIP to receive data, i only can get the first line on data which mean the data length is 1514, but the another line of data which is length 174 are unable to get from TCPIP Client protocol at C#. May need you guys to advise on this.

Picture Below is used Wireshark to trace the TCPIP data.

enter image description here

Below picture is the method used to receive data from TCPIP Client Protocol.

enter image description here

Thanks.

Here is how I approach to connect and get data from TCPIP. Please correct me if that was a mistake.

public void Connect(string ipAddress, int port)
    {
        lock (this)
        {
            try
            {
                IPAdddress = ipAddress;
                Port = port;
                IPAddress ip = IPAddress.Parse(ipAddress);
                IPEndPoint endPoint = new IPEndPoint(ip, port);

                Client.BeginConnect(endPoint, new AsyncCallback(OnClientConnected), null);
            }
            catch (Exception ex)
            {
                ExceptionThrownEventArgs args = new ExceptionThrownEventArgs();
                args.Exception = ex;
                
                if (m_ExceptionThrown != null)
                {
                    foreach (Delegate del in m_ExceptionThrown.GetInvocationList())
                    {
                        ISynchronizeInvoke syncer = del.Target as ISynchronizeInvoke;
                        if (syncer == null)
                        {
                            del.DynamicInvoke(this, args);
                        }
                        else
                        {
                            syncer.BeginInvoke(del, new object[] { this, args });
                        }
                    }
                    #endregion
                }

                // SupportMethod.ShowExceptionMessage(ex, Output.EventLog);
            }
        }
    }

private void OnMessageReceived(IAsyncResult result)
    {
        try
        {           
            Metadata metadata = (Metadata)result.AsyncState;

            if (metadata.ReceiveBuf[0] == 0)
            {
                Disconnect();
            }
            else
            {
                Client.EndReceive(result);
 
                
                var e = Encoding.GetEncoding("iso-8859-1");
                LastMessageReceived = e.GetString(metadata.ReceiveBuf).Trim('\0');
                Debug.Print("TCPRaw: " + LastMessageReceived);
                
                if (m_EchoOnReceived)
                {                        
                    Echo(LastMessageReceived);
                }
               
                MessageReceivedEventArgs args = new MessageReceivedEventArgs();
                if (m_MessageReceived != null)
                {
                    #region Fire the MessageReceived event (bound during instantiation of ClientSocket).
                    
                    foreach (Delegate del in m_MessageReceived.GetInvocationList())
                    {
                        ISynchronizeInvoke syncer = del.Target as ISynchronizeInvoke;
                        if (syncer == null)
                        {
                            del.DynamicInvoke(this, args);
                        }
                        else
                        {
                            syncer.BeginInvoke(del, new object[] { this, args });
                        }
                    }
                    #endregion
                }

                // Provide additional data for the socket operation. Re-instantiate a new Metadata object.
                metadata = new Metadata();
                metadata.ReceiveBuf = new byte[m_ReceiveBufSize];

                // Continue to prepare receive data from the connected Server.
                Client.BeginReceive(
                    metadata.ReceiveBuf,
                    0,
                    metadata.ReceiveBuf.Length,
                    SocketFlags.None,
                    new AsyncCallback(OnMessageReceived),
                    metadata);
            }
        }
        catch (Exception ex)
        {
            ExceptionThrownEventArgs args = new ExceptionThrownEventArgs();
            args.Exception = ex;

            
            // ExceptionThrown Event.
            if (m_ExceptionThrown != null)
            {
                #region Fire the ExceptionThrown event (bound during instantiation of ClientSocket).
                // Check the Target of each delegate in the event's invocation list, and marshal the call
                // to the target thread if that target is ISynchronizeInvoke
                // ref: http://stackoverflow.com/questions/1698889/raise-events-in-net-on-the-main-ui-thread

                foreach (Delegate del in m_ExceptionThrown.GetInvocationList())
                {
                    ISynchronizeInvoke syncer = del.Target as ISynchronizeInvoke;
                    if (syncer == null)
                    {
                        del.DynamicInvoke(this, args);
                    }
                    else
                    {
                        syncer.BeginInvoke(del, new object[] { this, args });
                    }
                }
                #endregion
            }

            //  SupportMethod.ShowExceptionMessage(ex, Output.EventLog);
        }
    }

Solution

  • For TCP/IP, when you specify the number of bytes to receive in a Receive method, it is an upper limit, not an absolute number of bytes. If you receive less than the requested number of bytes, you need to do another read and combine the results together into the data you want. This is why the Receive method allows you to specify the index into the array to put the received data. For example:

    var message = new byte[myMessageSize];
    var totalBytesReceived = 0;
    while (totalBytesReceived < myMessageSize)
    {
        var bytesReceived = socket.Receive(message, 
                                           totalBytesReceived, 
                                           myMessageSize - totalBytesReceived,
                                           SocketFlags.None);
        
        totalBytesReceived += bytesReceived;
    }
    

    I recommend against using BeginReceive, the callbacks are difficult to manage and most people do it wrong. Use the synchronous methods or ReceiveAsync().