C#和C++结构体Socket通信
最近在用C#做一个项目的时候,Socket发送消息的时候遇到了服务端需要接收C++结构体的二进制数据流,这个时候就需要用C#仿照C++的结构体做出一个结构来,然后将其转换成二进制流进行发送,之后将响应消息的二进制数据流转换成C#结构。
1、仿照C++结构体写出C#的结构来
1using System.Runtime.InteropServices;
2
3 [Serializable] // 指示可序列化
4 [StructLayout(LayoutKind.Sequential, Pack =1)] // 按1字节对齐
5public struct Operator
6
7 {
8public ushort id;
9 [MarshalAs(UnmanagedType.ByValArray, SizeConst =11)] // 声明一个字符数组,大小为11
10public char[] name;
11 [MarshalAs(UnmanagedType.ByValArray, SizeConst =9)]
12public char[] pass;
13
14public Operator(string user, string pass) // 初始化
15 {
16this.id = 10000;
https://www.doczj.com/doc/8213437867.html, = user.PadRight(11, '\0').ToCharArray();
18this.pass = pass.PadRight(9, '\0').ToCharArray();
19 }
20 }
21
22
2、注意C#与C++数据类型的对应关系
1typedef
2{
3 WORD id;
4 CHAR name[
5 CHAR password[
6}Operator;
7
8
1
2
3
4
5
6
7
8
9 {
10
11
12
13
14
15 IntPtr structPtr =
16
17 Marshal.StructureToPtr(obj, structPtr, 18
19 Marshal.Copy(structPtr, bytes, 0, size);
20//释放内存空间
21 Marshal.FreeHGlobal(structPtr);
22//返回byte数组
23return bytes;
24
25 }
26
27
接收的时候需要把字节数组转换成结构
1///
2/// byte数组转结构
3///
4///byte数组
5///结构类型
6///
7public object BytesToStruct(byte[] bytes, Type type)
8 {
9//得到结构的大小
10int size = Marshal.SizeOf(type);
11 Log(size.ToString(), 1);
12//byte数组长度小于结构的大小
13if (size > bytes.Length)
14 {
15//返回空
16return null;
17 }
18//分配结构大小的内存空间
19 IntPtr structPtr = Marshal.AllocHGlobal(size);
20//将byte数组拷到分配好的内存空间
21 Marshal.Copy(bytes, 0, structPtr, size);
22//将内存空间转换为目标结构
23object obj = Marshal.PtrToStructure(structPtr, type);
24//释放内存空间
25 Marshal.FreeHGlobal(structPtr);
26//返回结构
27return obj;
28 }
29
4、实际操作:
1using System.Collections;
2using System.Collections.Generic;
3using https://www.doczj.com/doc/8213437867.html,;
4using https://www.doczj.com/doc/8213437867.html,.Sockets;
5
6byte[] Message = StructToBytes(new Operator("user","pass")); // 将结构转换成字节数组
7
8TcpClient socket =new TcpClient();
9
10socket.Connect(ip,port);
11
12NetworkStream ns = Socket.GetStream();
13
14ns.Write(Message,0,Message.Length); // 发送
15
16byte[] Recv =new byte[1024]; // 缓冲
17
18int NumberOfRecv =0;
19
20IList
21ns.ReadTimeout =3000;
22try
23{
24do
25{
26// 接收响应
27NumberOfRecv = ns.Read(Recv, 0, Recv.Length);
28for (int i =0; i < NumberOfRecv; i++)
29newRecv.Add(Recv[i]);
30}
31while (ns.DataAvailable);
32byte[] resultRecv =new byte[newRecv.Count];
33newRecv.CopyTo(resultRecv, 0);
34
35Operator MyOper =new Operator();
36
37MyOper = (Operator)BytesToStruct(resultRecv, MyOper.GetType()); // 将字节数组转换成结构
38
在这里取值的时候可能会出现只能取到一个字段,剩余的取不到的问题,怎么回事我也搞不懂,反正我的解决办法就是按照字节的顺序从resultRecv里分别取出对应的字段的字节数组,然后解码,例如:
https://www.doczj.com/doc/8213437867.html,是11个字节,最后一位是0,Operator.id是2个字节,那么从第3位到第12位的字节就是https://www.doczj.com/doc/8213437867.html,的内容,取出另存为一个数组MyOperName,Encoding.Default.GetString(MyOperName)就是
https://www.doczj.com/doc/8213437867.html,的内容。
1socket.Close();
2
3ns.Close();
4