简体   繁体   中英

Process TCP Socket data read in different thread

I are developing a program to integrate with a device which sends data over TCP channel every 70 ms.

I am using Socket.BeginReceive and Socket.EndReceive methods to read the data. The logic is depicted in following pseudo code

private void OnReceived(IAsyncResult ar)
{
    var rcvdDataLength = m_tcpSocket.EndReceive(ar);
    Array.Copy(m_tempRecvBuffer, 0, m_mainBuffer, m_mainBufferDataIndex, rcvdDataLength);
    if (CheckIfValidHeaderAndBodyReceived())
    {
        var actualData = new byte[headerLen + BodyLen];
        Array.Copy(m_mainBuffer, m_dataIndex, actualData, 0, headerLen + BodyLen);
        Process(actualData);
    }
    m_tcpSocket.BeginReceive(m_tempRecvBuffer, 0, m_tempRecvBuffer.Length, SocketFlags.None,
        OnReceived, null);
}

Process function depicted in the above code is responsible for implementing the business logic. Process function currently takes around 300 ms.

So the consumer (which takes 300 ms) is slower than producer (which publishes data every 70 ms). Do I need to run this Process function asynchronously to avoid the delay? Or flow control aspect of TCP layer take care of this?

Do I need to run this Process function asynchronously to avoid the delay?

This depends on your application and ultimately your own decision of priorities. Strictly speaking, no you don't need to do anything asynchronously, but it can be a good thing to do.

The approach I usually use and recommend is a thread dedicated to the interface that interacts with the rest of the application through a queue. As the communication thread receives messages, it locks a queue and pushes them in. When the main application is ready to consume that data, it locks that queue and dequeues as much as it needs to. It's a simple, robust, and reliable mechanism. Going to your pseudocode:

private void OnReceived(IAsyncResult ar)
{
    var rcvdDataLength = m_tcpSocket.EndReceive(ar);
    Array.Copy(m_tempRecvBuffer, 0, m_mainBuffer, m_mainBufferDataIndex, rcvdDataLength);
    if (CheckIfValidHeaderAndBodyReceived())
    {
        var actualData = new byte[headerLen + BodyLen];
        Array.Copy(m_mainBuffer, m_dataIndex, actualData, 0, headerLen + BodyLen);
        lock(messageQueue)
        {
           messageQueue.Enqueue(actualData);
        }
    }
    m_tcpSocket.BeginReceive(m_tempRecvBuffer, 0, m_tempRecvBuffer.Length, SocketFlags.None,
        OnReceived, null);
}

And then somewhere in your application:

void ProcessQueue()
{
   Queue<byte[]> tempQueue = new Queue<byte[]>();
   lock(messageQueue)
   {
      // Drain the queue so we can release the lock ASAP
      while(messageQueue.Count > 0)
      {
         tempQueue.Enqueue(messageQueue.Dequeue());
      }
   }
   while(tempQueue.Count > 0)
   {
      Process(tempQueue.Dequeue());
   }
}

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