C#服务器套接字数据未正确接收

时间:2018-12-13 13:38:57

标签: c#

我已经开发了一个应用程序,它将使用TCP服务器套接字程序与PLC进行交互。 每个循环plc都会以character('R')的形式向我的应用程序发送一个信号。
但有时我没有收到任何字符。这表示事件未触发。 但是下一次当plc发送“ R”时,我将收到它作为“ RR”。 我的代码是`

private void _tcpServerFortest_OnRead(Socket soc)
    {
      //  rec = new byte[1];
        byte[] rec = _tcpServerFortest.ReceivedBytes;

        string str = System.Text.ASCIIEncoding.ASCII.GetString(rec);`
}

我启动TCP服务器的代码是

   _tcpServerFortest = new CServerSocket(2005);
                _tcpServerFortest .OnConnect += _tcpServerFortest _OnConnect;
                _tcpServerFortest .OnDisconnect += _tcpServerFortest _OnDisconnect;
               _tcpServerFortest .OnRead += _tcpServerFortest _OnRead;
               _tcpServerFortest .Active();

在我的类cServerSocket中,数据接收方法如下

 private void OnDataReceived(IAsyncResult asyn)
    {
        SocketPacket socketData = (SocketPacket)asyn.AsyncState;
        try
        {
            int iRx = socketData.m_currentSocket.EndReceive(asyn);
            if (iRx < 1)
            {
                socketData.m_currentSocket.Close();
                if (!socketData.m_currentSocket.Connected)
                {
                    if (OnDisconnect != null)
                        OnDisconnect(socketData.m_currentSocket);
                    Clients.Remove(socketData.m_currentSocket);
                    socketData.m_currentSocket = null;
                }
            }
            else
            {

                mBytesReceived = socketData.dataBuffer;
                char[] chars = new char[iRx + 1];
                Decoder d = Encoding.UTF8.GetDecoder();
                d.GetChars(socketData.dataBuffer, 0, iRx, chars, 0);
                mTextReceived = new String(chars);
                if (OnRead != null)
                    OnRead(socketData.m_currentSocket);
                WaitForData(socketData.m_currentSocket);
            }
        }
        catch (InvalidOperationException ex)
        {
            if (socketData.m_currentSocket.Connected)
                socketData.m_currentSocket.Close();
            if (!socketData.m_currentSocket.Connected)
            {
                if (OnDisconnect != null)
                    OnDisconnect(socketData.m_currentSocket);
                Clients.Remove(socketData.m_currentSocket);
                socketData.m_currentSocket = null;
            }
            else
                if (OnError != null)
                    OnError(ex.Message, null, 0);
        }
        catch (SocketException se)
        {
            if (OnError != null)
                OnError(se.Message, socketData.m_currentSocket, se.ErrorCode);
            if (!socketData.m_currentSocket.Connected)
            {
                if (OnDisconnect != null)
                    OnDisconnect(socketData.m_currentSocket);
                Clients.Remove(socketData.m_currentSocket);
                socketData.m_currentSocket = null;
            }
        }
    }

有人可以帮我解决这个问题吗?

1 个答案:

答案 0 :(得分:1)

TCP适用于流,而不适用于消息。看来您确实想发送消息,因此UDP可能是一个更好的选择。

在TCP上发送数据时,不能保证这将导致另一侧的单次接收。单个发送可以导致多个接收,并且可以将多个发送批处理为单个接收(如您所知)。您应该连续读取数据,并根据通信协议的要求对其进行解释。就您而言,这很简单,就像“一次读取一个字节”一样-但只有您知道您到底想要什么。

此外,我建议不要使用基于Delphi的通信包装器;编程模型是不同的,似乎创建此库的唯一原因是让熟悉Delphi的人不了解.NET的工作方式。级别太低而无用,而在处理数据时并没有给您太多选择。

不管选择哪种解决方案,您都可以在Stack Overflow上找到数百个类似的问题。例如Handling messages on top of TCP。基本解决方案是:

  • 实施某种形式的消息框架。可以很简单,例如“每条消息的长度为一个字节”,或者“每条消息的前缀为4个字节,指示消息的长度”或“每条消息都以定界符结尾”。
  • 切换到UDP,这是基于消息的协议。由于似乎您关心的是设备的当前状态,而不是单个消息流,因此,这可能是一个更好的选择-获得较低的延迟和消息,以换取失去顺序和可靠性的好处。您需要确定这对您是否有益。

如果保留TCP,则需要学习如何使用TCP。这意味着处理正常关机(receive返回0个字节),正确读取数据(继续调用receive直到获得完整的消息,将其余的消息保存在缓冲区中以备后用……),错误处理。这意味着了解延迟在TCP上的工作方式(发送并非总是立即发送,除非您明确要求发送)。这意味着要理解,由于某些无关的消息需要重新传输,因此接收到的数据可能会延迟。 TCP并不简单,而且棘手的部分是,它很容易在大多数时间都能正常工作-然后所有假设都被打破了。