C#网络编程数据传输中封装数据帧头的方法

在C#的网络编程中,自定义数据帧头不同于C/C++,需要借助Marshal等非托管方法。本文介绍了如何使用StructLayout和FieldOffsetAttribute来定义帧头结构,并展示了如何进行数据的封装和解析,包括发送端和接收端的代码示例。此外,还提及了C++端(使用Qt)的相应操作。

  在C/S端编程的时候,经常要在C端和S端之间传数据时自定义一下报文的帧头,如果是在C/C++,封装帧头是一件很简单的事情,直接把unsigned char *强转为struct就行,但是在C#中,并没有提供直接从struct到byte[]的转换,这个时候就需要用到Marshal等非托管的方法了。

自定义帧


我们可以在C#中写出如下代码:

 1 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1,Size = 12)]
 2 [Serializable()]
 3  public struct DatagramHeaderFrame
 4 {
 5             // MessageType类型:
 6             public MessageType MsgType;
 7 
 8             //一个四个字节的特征码
 9             public uint FeatureCode;
10 
11             //用于标识报文的长度,用于校验
12             public int MessageLength;
13   }

  首先我们说明一下,StructLayout是一个用于管理struct的布局特性,

CharSet指示在默认情况下是否应将类中的字符串数据字段作为 LPWSTR 或 LPSTR 进行封送处理;

Pack控制类或结构的数据字段在内存中的对齐方式。

Size指示类或结构的绝对大小。

  LayoutKind是布局的类型,这个枚举有三个值:

Auto运行库自动为非托管内存中的对象的成员选择适当的布局。 使用此枚举成员定义的对象不能在托管代码的外部公开。 尝试这样做将引发异常。

Explicit在未管理内存中的每一个对象成员的精确位置是被显式控制的,服从于 StructLayoutAttribute. Pack 字段的设置。每个成员必须使用 FieldOffsetAttribute 指示该字段在类型中的位置。在MSDN文档中为我们展示了下面的一个例子:

1 [StructLayout(LayoutKind.Explicit)]
2 public struct Rect 
3 {
4    [FieldOffset(0)] public int left;
5    [FieldOffset(4)] public int top;
6    [FieldOffset(8)] public int right;
7    [FieldOffset(12)] public int bottom;
8 }   

Sequential对象的成员按照它们在被导

(注意使用前先将IP改为自己的IP或127.0.0.1) 本软件是使用套接字、ReceiveCallBack(IAsyncResult AR)函数为例的客服实例,修正了关闭客户端会导致异常的Bug;并且还是一个RichTextBox颜色使用的范例,不同的事件使用不同的颜色:如用户登录用红色、用户名用绿色、聊天内容用黑色^_^! 代码附赠全套注释,帮助初学者学习使用。 下面是核心代码 private void ReceiveCallBack(IAsyncResult AR) { try { DateTime dt = DateTime.Now; //如果服务器突然关闭后,客户端还坚持与之连接就会弹出异常; //检查是否套接字还连接上就可以避免这一问题。 if (!ClientSocket.Connected) { return; } //挂起AR,独占的使用AR来接收传过来的内容 int REnd = ClientSocket.EndReceive(AR); string StrOfREnd=Encoding.Unicode.GetString(MsgBuffer, 0, REnd); //截断的传输过来的字符串,"\n"前的是用户名 "\n"后的是聊天的内容 string UsersName = StrOfREnd.Substring(0, StrOfREnd.LastIndexOf("\n")); string Content = StrOfREnd.Substring(StrOfREnd.LastIndexOf("\n")+1); string Login=StrOfREnd.Substring(0,2); //MessageBox.Show("缓存中的内容:" + StrOfREnd + "\n" + "截断的用户名:" + UsersName + "\n" + "截断的内容:" + Content); if (Login != "登录") { //第一个字符不为“登陆” int oldlenth = tb_RecieveMsg.TextLength; this.tb_RecieveMsg.Select(oldlenth, 0); this.tb_RecieveMsg.SelectionColor = Color.Green; string str = Encoding.Unicode.GetString(MsgBuffer, 0, REnd); str = str.Substring(1, str.Length - 1); //用户使用绿色字体 this.tb_RecieveMsg.AppendText(" " + string.Format("{0:T}", dt) + " " + "用户:" + UsersName + "说:" + "\r\n"); this.tb_RecieveMsg.SelectionColor = Color.Black; this.tb_RecieveMsg.AppendText(" " + Content + "\r\n"); this.tb_RecieveMsg.AppendText("\r\n"); } else {
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值