研究了几天,还是两眼一抹黑,求指点
不是伸手党,需要个demo学习下
下面是发送的结构体
协议ID:BACKE_M_ASKTA = 4000
struct
{
CM_TYPE_DLG m_dlgType; //操作类型 EM_TYPE_DLG_NOTICE
X_INT m_GroupID; //服务器大区
X_INT m_Date; //操作时间
X_CHAR m_Contex[256] ; //内容
};
其中 CM_TYPE_DLG 是enum
不是伸手党,需要个demo学习下
下面是发送的结构体
协议ID:BACKE_M_ASKTA = 4000
struct
{
CM_TYPE_DLG m_dlgType; //操作类型 EM_TYPE_DLG_NOTICE
X_INT m_GroupID; //服务器大区
X_INT m_Date; //操作时间
X_CHAR m_Contex[256] ; //内容
};
其中 CM_TYPE_DLG 是enum
解决方案
5
发送类,可以把 这个类序列化到网络流(NetStream)中发送,接收的时候反序列化网络流中的这个对象就是了
10
先将结构体转成byte[]. 参考: //// <summary> /// 结构体转byte数组 /// </summary> /// <param name="structObj">要转换的结构体</param> /// <returns>转换后的byte数组</returns> public static byte[] StructToBytes(object structObj) { //得到结构体的大小 int size = Marshal.SizeOf(structObj); //创建byte数组 byte[] bytes = new byte[size]; //分配结构体大小的内存空间 IntPtr structPtr = Marshal.AllocHGlobal(size); //将结构体拷到分配好的内存空间 Marshal.StructureToPtr(structObj, structPtr, false); //从内存空间拷到byte数组 Marshal.Copy(structPtr, bytes, 0, size); //释放内存空间 Marshal.FreeHGlobal(structPtr); //返回byte数组 return bytes; } /// <summary> /// byte数组转结构体 /// </summary> /// <param name="bytes">byte数组</param> /// <param name="type">结构体类型</param> /// <returns>转换后的结构体</returns> public static object BytesToStuct(byte[] bytes, Type type) { //得到结构体的大小 int size = Marshal.SizeOf(type); //byte数组长度小于结构体的大小 if (size > bytes.Length) { //返回空 return null; } //分配结构体大小的内存空间 IntPtr structPtr = Marshal.AllocHGlobal(size); //将byte数组拷到分配好的内存空间 Marshal.Copy(bytes, 0, structPtr, size); //将内存空间转换为目标结构体 object obj = Marshal.PtrToStructure(structPtr, type); //释放内存空间 Marshal.FreeHGlobal(structPtr); //返回结构体 return obj; }
5
结构
头 ABCD
内容 FFAABB
尾 SDDD
头 + 内容 + 尾 组合
发送即可
收到 ABCD 表示准确数据,收到SDDD表示 内部数据完整
解析 FFAABB即可
FF = 1111111111111111 表示 16个 回路。1表示 回路开,0表示关 显示在界面上。
下位机一般那样定的,不知道你这个是啥意思。
头 ABCD
内容 FFAABB
尾 SDDD
头 + 内容 + 尾 组合
发送即可
收到 ABCD 表示准确数据,收到SDDD表示 内部数据完整
解析 FFAABB即可
FF = 1111111111111111 表示 16个 回路。1表示 回路开,0表示关 显示在界面上。
下位机一般那样定的,不知道你这个是啥意思。
5
可以像二楼说的那样,先序列化成一个string,然后string转byte【】发送出去,第二种根据这个结构体弄一个通讯协议,然后发送的时候吧结构体弄成报文,接收的时候收到报文再把报文转为结构体;两种方式差不多,第一种会简单点,但是个人还是习惯用第二种
5
假如你只是做实验的话。完全可以不管包头
直接重载一个tostring方法,再转byte【】发送
直接重载一个tostring方法,再转byte【】发送
10
先要将结构体序列化为byte[]
然后只需要把发送的bKick用序列化好的数据替换:myS.Send(bytes);
序列化的方式有很多,2楼的算一个,不过不推荐
BinaryFormatter,这个必须是c#才能用
常见的还有json,protobuf,都可以从nuget下载
使用哪种序列化方式,通常是由服务器程序定义好的
然后只需要把发送的bKick用序列化好的数据替换:myS.Send(bytes);
序列化的方式有很多,2楼的算一个,不过不推荐
BinaryFormatter,这个必须是c#才能用
常见的还有json,protobuf,都可以从nuget下载
使用哪种序列化方式,通常是由服务器程序定义好的
20
这方面一旦就接到“越是低级的越高效”就会出问题。
本人只是告诉你几个基本事实。在15~10年以前,编程世界流行使用基于xml的通讯机制来取代rpc;后来过渡到轻量级的基于 json 等等。当然使用纯二进制形式的系统一直存在,c开发平台可以直接支持对struct的收发,但是用熟悉用底层的开发工具的人跟开发应用系统的人不在同一个层面上看问题。
例如一个大型开发团队,15年前,随便一个高级程序员都会发现 xml 的好处。例如它有(仅仅才有)上千个客户端,当服务器更新时并不能保证每一个客户端都更新。此时其要传送的数据多了几个字段、少了一个字段、字段的排列次序调整了,甚至个别字段的数据类型都有了一点改变,使用 xml 方式就能保证这种版本兼容性。使用json 当然也还是如此灵活的,而且 web 富客户端直接就是 json 形式(json 本来就是来自于 javsscript 对象的直接映射,方便于用 js 对象的知识来调试 json 对象)。
假如站在这个角度,你就会发现扔掉 struct 而用应用层“对象”的角度来设计通讯,会更可靠。
反之,假如你非要说“越是底层的做法效率越高”,那么这也是对的,用汇编语言编程还比c#的执行效率高呢——关键是你写出没有什么瑕疵的汇编语言需要30年经验才能做到。
本人只是告诉你几个基本事实。在15~10年以前,编程世界流行使用基于xml的通讯机制来取代rpc;后来过渡到轻量级的基于 json 等等。当然使用纯二进制形式的系统一直存在,c开发平台可以直接支持对struct的收发,但是用熟悉用底层的开发工具的人跟开发应用系统的人不在同一个层面上看问题。
例如一个大型开发团队,15年前,随便一个高级程序员都会发现 xml 的好处。例如它有(仅仅才有)上千个客户端,当服务器更新时并不能保证每一个客户端都更新。此时其要传送的数据多了几个字段、少了一个字段、字段的排列次序调整了,甚至个别字段的数据类型都有了一点改变,使用 xml 方式就能保证这种版本兼容性。使用json 当然也还是如此灵活的,而且 web 富客户端直接就是 json 形式(json 本来就是来自于 javsscript 对象的直接映射,方便于用 js 对象的知识来调试 json 对象)。
假如站在这个角度,你就会发现扔掉 struct 而用应用层“对象”的角度来设计通讯,会更可靠。
反之,假如你非要说“越是底层的做法效率越高”,那么这也是对的,用汇编语言编程还比c#的执行效率高呢——关键是你写出没有什么瑕疵的汇编语言需要30年经验才能做到。
10
例如说每一个 struct 之前,你用4个字节的一个int编号来表示命令类型,那么你接收数据的那一端根据前4个字节就知道该对应哪一类的struct,然后用c语言编程方式将从第5个字节开始的部分直接读为此确定类型的 struct。
在c++开发工具中(例如微软的c++工具),针对 Stream 而写和读struct 都是一条简单的语句的事情(就好像你在c#写 stream.Read(buffer, index)、stream.write(buffer) 一样简单,根本不像有些人想象的那样值得花哨地去考虑。
并没有什么技术含量。这里“4个字节”相对你的struct收发,就是忽悠人的包头了。
但是本人还是要告诉你,除非你是跑到 c# 论坛来问一个 c/c++ 底层的问题,否则从应用架构设计上看,使用 xml/json(或其它的可以随时增加减少字段都兼容的序列化方案)来传送“通用对象”,是比考虑 struct 更好的。
5
例如说,以前的 msn 使用这样的信令协议(仅仅举例):
购买装备 | 服务大区 | 时间| 用户sessionid | 装备类型 | 装备数量 | 交易号
它用“回车换行”作为每一个信令的结束符号,用竖线“|”作为字段的分隔符。用这种简单的相似 csv 数据行的形式为通讯信令,也有好几十年历史。
表现力越高,就越不需要一些比较底层的术语。而是用高级的目标领域的术语来说信令。
假如你硬说“传struct二进制字节形式”要比传字符型式高效,本人也没有什么可说的。但是要知道应用系统通常都从比较自然、岁是千变万化、容易调试的角度去设计,而不是仅仅抠底层效率。
购买装备 | 服务大区 | 时间| 用户sessionid | 装备类型 | 装备数量 | 交易号
它用“回车换行”作为每一个信令的结束符号,用竖线“|”作为字段的分隔符。用这种简单的相似 csv 数据行的形式为通讯信令,也有好几十年历史。
表现力越高,就越不需要一些比较底层的术语。而是用高级的目标领域的术语来说信令。
假如你硬说“传struct二进制字节形式”要比传字符型式高效,本人也没有什么可说的。但是要知道应用系统通常都从比较自然、岁是千变万化、容易调试的角度去设计,而不是仅仅抠底层效率。
5
方向专为流行的应用层设计方式,那么你的路就很宽,灵活性高很多。可以重点在到处去扩展应用。
假如只是为了底层“效率”,那么你就一直死抠一小段简单的代码,一直抠技术。
假如只是为了底层“效率”,那么你就一直死抠一小段简单的代码,一直抠技术。
5
实在不行就PInvoke吧..
15
C#里面的struct和C/C++的是不一样的。C/C++里面可以通过#pragma pack(n)配合,精确的控制struct在内存、硬盘和网络上的精确布局,通过memcpy之类函数可以直接操作struct对应的内存,而C#不保证struct的内存布局,一个struct想对应到一个byte[],只能通过序列化技术。
常见的几种序列化技术:
1、笨办法:本人用BitConverter/BinaryWriter/BinaryReader,逐个字段的读写
2、用StructLayoutAttribute和Marshal的工具自动转换
3、用json工具自动转换,例如newtonsoft.json,但是要注意json转换成的是一个string,需要继续在某个指定的encoding下(例如UTF8)再转换成二进制的byte[]
4、google的protobuf
等你调研完这几种办法,你就成了序列化的专家了
常见的几种序列化技术:
1、笨办法:本人用BitConverter/BinaryWriter/BinaryReader,逐个字段的读写
2、用StructLayoutAttribute和Marshal的工具自动转换
3、用json工具自动转换,例如newtonsoft.json,但是要注意json转换成的是一个string,需要继续在某个指定的encoding下(例如UTF8)再转换成二进制的byte[]
4、google的protobuf
等你调研完这几种办法,你就成了序列化的专家了