C#中通过TCP进行面向对象的通信

时间:2012-08-25 10:53:07

标签: c# oop design-patterns tcp

我正在开发一个简单的应用程序,它将通过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)
}

这是每分钟发送一次。 没有开销。它只是发出所有变量的值而不再是

修改 我对服务器没有任何控制权。

2 个答案:

答案 0 :(得分: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
    }
}

答案 1 :(得分:1)

通常步骤相同:

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

2)连续检查缓冲区(每次更新缓冲区)以确定是否到达完整的数据包。

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

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

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

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

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

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

相关问题