通过TCP套接字创建通信协议?

时间:2011-10-02 16:57:59

标签: c# .net sockets tcp arduino

我有一个带Sparkfun WiFly shield的Arduino微控制器。

我在C#/ .NET中构建了一个简单的程序,使用System.Net.Sockets连接到Arduino:

Socket Soc = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

public void SendMsg(string msg)
{
    try
    {
        byte[] buffer = StrToByteArray(msg);
        if (Soc.Connected)
            Soc.Send(buffer);
        else
        {
            Soc.Connect(this.remoteIP);
            Soc.Send(buffer);
        }
    }
    catch (Exception e){}
}

关于我的arduino:

while(SpiSerial.available() > 0) {
    byte b = SpiSerial.read();
    Serial.println(b);
}

当套接字连接进行握手时,我得到:“ * OPEN * ”,当我关闭时,我得到:“ * CLOS * ”。

问题在于我将消息逐个字节地获取,有时我在一个while循环中没有得到完整的消息。

因此,如果我使用上面在Arduino上显示的代码,我的串行终端看起来像:

*
O
P
E
N
*
T
E
S
T
*
C
L
O
S
*

那么如何找出PC试图发送的消息呢?

我知道我需要以某种方式使用一个特殊字节来表示我的消息结束。 (我不会在我的消息中使用的特殊字节,仅用于表示消息的结尾)

但是我该怎么办呢?要使用哪个字节?

2 个答案:

答案 0 :(得分:2)

您需要在此设计自己的协议。您应该定义一个字节(最好是数据中不会出现的字节)来表示“开始”,然后您有三个选择:

  • 跟随起始字节,其中“length”字节表示数据量 阅读
  • 定义标记数据结尾的“结束”字节
  • 读取数据,直到您有完整的消息与其中一个匹配 你期待的那些

第三个选项是最不可扩展和灵活的,当然,好像你已经有一个消息“OPEN”,你不能再添加一条新消息“OPENED”。

如果你选择第二个选项并定义一个“结束”字节,那么你需要担心如果它出现在你的数据中那么转义该字节(或者使用另一个保证不在你数据中的字节)。

答案 1 :(得分:0)

查看您当前的示例,一个很好的起点是简单地为每条消息添加长度前缀。

如果要支持长消息,可以使用2字节长度的前缀,然后读取前2个字节以获取长度,然后继续从套接字读取,直到读取长度指示的字节数为止前缀。

一旦你读完了一条完整的信息,你就会回来期待读取下一条信息的长度前缀,依此类推,直到其中一方终止通信为止。

当然,在所有这些之间,您需要检查错误情况,例如一端的套接字过早关闭等,以及如何处理可能导致套接字过早关闭的潜在部分消息。