1

我正在开发一个简单的应用程序,它将通过 TCP 从硬件接收数据。我在互联网上搜索了一下如何开发一个接收 TCP 数据的程序,但没有找到任何我满意的东西。它要么是对如何在 C# 中使用 TCP 的非常简化的描述,要么是对高级框架的描述。

我想要一个简单的最佳实践,说明如何以良好的面向对象的方式组织我的程序的通信部分。有什么建议么?

理想情况下,我希望通过 TCP 发送的不同结构存储在程序中的相应结构中

发送内容的结构:

Head
{
  Int16    Mode;
  Time     Start_time //(Unix time)
  Int16    Number of records
}
for each record if mode == 1
  char[20]    Name_of_record
for each record
  float    Value_of_record //(hardware-specific float)
  Int16    Flag_of_record
Foot
{
  Time     Stop_time //(Unix time)
}

这是每分钟发送一次。没有开销。它只是发送所有变量的值,仅此而已

编辑 我对服务器没有任何控制权。

4

2 回答 2

2

我们可以使用异步通信接收 TCP 消息。

初始化服务器套接字并尝试连接:

// Specify the size according to your need.
private byte[] bytData = new byte[1024 * 50000];
private Socket oServerSocket;

private void WindowLoaded(object sender, RoutedEventArgs e)
{
    try
    {
        // We are using TCP sockets
        this.oServerSocket = new Socket(
        addressFamily: AddressFamily.InterNetwork,
        socketType: SocketType.Stream,
        protocolType: ProtocolType.Tcp);

        // Assign the any IP of the hardware and listen on port number which the hardware is sending(here it's 5656)
        var oIPEndPoint = new IPEndPoint(address: IPAddress.Any, port: 5656);

        // Bind and listen on the given address
        this.oServerSocket.Bind(localEP: oIPEndPoint);
        this.oServerSocket.Listen(backlog: 4);

        // Accept the incoming clients
        this.oServerSocket.BeginAccept(this.OnAccept, null);
        this.oLogger.WriteLog("Server started");
    }
    catch (Exception ex)
    {
        // Handle Exception
    }
}

成功连接时:

private void OnAccept(IAsyncResult ar)
{
    try
    {
        var oClientSocket = this.oServerSocket.EndAccept(asyncResult: ar);

        // Start listening for more clients
        this.oServerSocket.BeginAccept(callback: this.OnAccept, state: null);

        // Once the client connects then start receiving the commands from her
        oClientSocket.BeginReceive(
        buffer: this.bytData,
        offset: 0,
        size: this.bytData.Length,
        socketFlags: SocketFlags.None,
        callback: this.OnReceive,
        state: oClientSocket);
    }
    catch (Exception ex)
    {
        // Handle Exception
    }
}

处理收到的消息:

private void OnReceive(IAsyncResult ar)
{
    try
    {
        var oClientSocket = (Socket)ar.AsyncState;
        oClientSocket.EndReceive(asyncResult: ar);

        /* Process the data here

        BitConverter.ToInt32(value: this.bytData, startIndex: 0);
        string SomeString= Encoding.ASCII.GetString(bytes: this.bytData, index: 8, count: 5);

        */

        // Specify the size according to your need.
        this.bytData = null;
        this.bytData = new byte[1024 * 50000];
        oClientSocket.BeginReceive(
            buffer: this.bytData,
            offset: 0,
            size: this.bytData.Length,
            socketFlags: SocketFlags.None,
            callback: this.OnReceive,
            state: oClientSocket);
    }

    catch (Exception ex)
    {
        // Handle Exception
    }
}
于 2012-08-25T12:45:03.553 回答
1

通常步骤是相同的​​:

1) 从 tcp 流中读取数据并将其存储在缓冲区(通常是字节数组)中。

2)不断检查缓冲区(每次更新它)以确定是否有一个完整的数据包到达。

3)解析缓冲区并将数据包提取到所需的OO对象

4) 将对象添加到队列中以进一步处理或调用后台线程来消费数据包对象。

通过输出流发送数据以相反的顺序几乎相同。

处理缓冲区时,事情会变得复杂/嘈杂/痛苦。您需要处理二进制数据以确定一个数据包何时结束而另一个数据包何时开始。当然,这与您正在通信的设备的协议有关,如果它发送固定长度的数据包或开始/停止字节等...此时没有标准解决方案,因为您将编写的代码取决于关于设备发送的数据。

编辑:您用示例代码更新了您的问题,但是记录的结构并不重要,该部分很简单且编写起来很冗长(如果您的结构有一个int字段,您从缓冲区读取 4 个字节并使用BitConverter例如,将字节转换为 int 的类)。您需要阅读硬件手册来检查它发送数据的格式(同样,开始/停止字节、固定长度等)。

这是非常抽象的,因为它特定于每种情况,没有“成熟的解决方案”。此外,您似乎不了解流/tcp 连接/二进制数据包的工作原理,是什么让您认为这是 tcp 连接的问题,但事实并非如此。Tcp 连接只是通过网络发送的字节流,您可以使用相同的模式从磁盘上的文件或串行端口中读取二进制数据。

于 2012-08-25T11:18:20.343 回答