如何以二进制帧格式发送数据(TCP) [英] How send data (TCP) in binary frame format

查看:402
本文介绍了如何以二进制帧格式发送数据(TCP)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要将数据流传输到TCP服务器,并且之前已经完成了操作.数据应为二进制帧格式.我在Google上搜索后发现了本教程,该教程描述了我需要做的事情:

I need to stream data to a TCP-server and havnt done it before. The data should be in binary frame format. I googled and found this tutorial which I think describes what I need to do:

http://msdn.microsoft.com/zh-CN/library/system.net.sockets.tcpclient(v=vs.71).aspx

但是我不知道如何以所需的格式创建数据,因此我无法以正确的方式发送数据.格式应为:

But I dont know how to create the data in the format needed so I can send it in the correct way. It should be in this format:

Field|Offset|    Type  | size(octets)
id   |  0   |unsign int|      1
name |  1   |Byte Array|      40
grade|  41  |sign float|      8 

示例:

Field| Data | InBytes  |
id   |  133 | 133      |
name |  247 | 247 0    |
grade|  0   | 0        |

我应该存储int,字节数组,float in的数据类型是什么,我应该在哪里指定偏移量和大小,最后应如何将其发送到服务器(在示例中,它们仅发送字节数组).

Whats the data type I should store the int, byte array, float in and where do I specify offsets and size and finally how should it be sent to the server (in the example they only send a byte array).

一个C#示例,说明如何使用上面提供的链接中的代码发送这样的数据.

A C#-example of how to send data like this using the code in the link provided above would be appreciated.

推荐答案

要表示要序列化(和反序列化)的数据,可以使用结构并设置适当的元数据,因此CLR会为您完成其余工作.就像其他人在这里说的那样,您将需要在端点上处理数据包的接收.另外,由于数据中有一个字符串字段,因此您还必须考虑接收者期望的字符集.以下代码是一个示例,说明如何实现该结构以将托管数据转换为带注释的二进制格式.

To represent the data to be serialized (and deserialized) you can use a struct and set the proper metadata, so the CLR do the rest for you. Like others said here you will need to deal with the packet reception on the end point. Also you'll have to consider the charset expected by the receiver, since you have a string field in your data. The following code is an example on how you can implement the struct to convert your managed data to a binary format, with comments.

// setting the layout to sequential will prevent the compiler/JIT
// to reorder the struct fields
// NOTE: Observe here that the Charset used is Ansi. You may need to
// change this depending on the format expected by the receiver.
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
struct DataPacket
{

    [MarshalAs(UnmanagedType.U4)]
    public uint Id;

    // As I understood from your question, the Name field
    // has a prefixed size of 40 bytes. Attention here:
    // the SizeConst actually means '40 characters', not bytes
    // If you choose to use the Unicode charset, set SizeConst = 20
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 40)]
    public String Name;

    // This will be serialized in little endian format
    // in your question this field is 8 bytes long, which 
    // in c# corresponds to the double type. If you really mean
    // the float type (4 bytes), change here.
    public double Grade;

    // Calling this method will return a byte array with the contents
    // of the struct ready to be sent via the tcp socket.
    public byte[] Serialize()
    {
        // allocate a byte array for the struct data
        var buffer = new byte[Marshal.SizeOf(typeof(DataPacket))];

        // Allocate a GCHandle and get the array pointer
        var gch = GCHandle.Alloc(buffer, GCHandleType.Pinned);
        var pBuffer = gch.AddrOfPinnedObject();

        // copy data from struct to array and unpin the gc pointer
        Marshal.StructureToPtr(this, pBuffer, false);
        gch.Free();

        return buffer;
    }

    // this method will deserialize a byte array into the struct.
    public void Deserialize(ref byte[] data)
    {
        var gch = GCHandle.Alloc(data, GCHandleType.Pinned);
        this = (DataPacket)Marshal.PtrToStructure(gch.AddrOfPinnedObject(), typeof(DataPacket));
        gch.Free();
    }
}

用法:

DataPacket packet;
packet.Id = 1234;
packet.Name = "Marvin the paranoid robot";
packet.Grade = 9.2;

// serialize
var bytes = packet.Serialize();

// send via tcp
var tcp = new TcpClient(...); 
tcp.GetStream().Write(bytes, 0, bytes.Length);


// deserializing;
DataPacket receivedPacket;
receivedPacket.Deserialize(bytes);

您已经有了数据包,现在您需要在接收器上处理数据包的接收.那部分您不需要手工完成,可以使用一些工具,例如@jgauffin说.

You already have the packet, now you'll need to deal with the packet reception on the receiver. That part you don't need to do all by hand, you can use some tools, like @jgauffin said.

这篇关于如何以二进制帧格式发送数据(TCP)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆