c# - c#服务器套接字数据没有正确接收
问题描述
我开发了一个应用程序,它将使用 TCP 服务器套接字程序与 plc 交互。每个循环 plc 都以字符('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;
}
}
}
谁能帮我解决这个问题?
解决方案
TCP 适用于流,而不是消息。看来您真的想发送消息,所以 UDP 可能是更好的选择。
当您在 TCP 上发送数据时,您不能保证这会导致另一端的单次接收。一次发送可能会导致多次接收,并且多次发送可以批处理为一次接收(如您所见)。您应该连续读取数据,并根据通信协议的要求对其进行解释。在您的情况下,这可以像“一次读取一个字节”一样简单 - 但只有您知道您到底想要什么。
另外,我建议不要使用基于 Delphi 的通信包装器;编程模型不同,似乎创建这个库的唯一原因是让熟悉 Delphi 的人不了解在 .NET 中是如何完成的。它的级别太低而无用,同时在处理数据时并没有给您太多选择。
无论您选择哪种解决方案,Stack Overflow 上已经有数百个类似的问题可供您查看;例如在 TCP 之上处理消息。基本解决方案是:
- 实现某种形式的消息框架。这可以像“每条消息都是一个字节长”一样简单,或者“每条消息都以 4 个字节为前缀,表示消息的长度”或“每条消息都以分隔符结尾”。
- 切换到 UDP,这是一种基于消息的协议。由于您似乎关心设备的当前状态而不是单个消息流,因此无论如何这可能是一个更好的选择 - 您可以获得更低的延迟和消息,以换取失去排序和可靠性。你需要决定这是否对你有好处。
如果保留 TCP,则需要学习如何使用 TCP。这意味着处理正常关闭(receive 返回 0 字节)、正确读取数据(继续调用接收直到获得整个消息,将其余部分保存在缓冲区中以备后用,...),错误处理。这意味着了解延迟如何在 TCP 上工作(发送并不总是立即发送,除非您明确要求他们这样做)。这意味着了解您收到的数据可能会延迟,因为您不关心的某些消息需要重新传输。TCP 并不简单,而棘手的部分是它很容易在大多数情况下工作——然后你的所有假设都会失效。