C#.NET和C++结构体Socket通信与数据转换
最近在用C#做一个项目的时候,Socket发送消息的时候遇到了服务端需要接收C++结构体的二进制数据流,这个时候就需要用C#仿照C++的结 构体做出一个结构来,然后将其转换成二进制流进行发送,之后将响应消息的二进制数据流转换成C#结构。
1、仿照C++结构体写出C#的结构来
1 using System.Runtime.InteropServices;
2
3 [Serializable] // 指示可序列化
4 [StructLayout(LayoutKind.Sequential, Pack = 1 )] // 按1字节对齐
5 public struct Operator
6
7 {
8 public ushort id;
9 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 11 )] // 声明一个字符数组,大小为11
10 public char [] name;
11 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 9 )]
12 public char [] pass;
13
14 public Operator( string user, string pass) // 初始化
15 {
16 this .id = 10000 ;
17 this .name = user.PadRight( 11 , ' /0 ' ).ToCharArray();
18 this .pass = pass.PadRight( 9 , ' /0 ' ).ToCharArray();
19 }
20 }
21
22
2、注意C#与C++数据类型的对应关系
| 
 C++与C#的数据类型对应关系表 
 | 
|||||
| API数据类型 | 类型描述 | C#类型 | API数据类型 | 类型描述 | C#类型 | 
| WORD | 16位无符号整数 | ushort | CHAR | 字符 | char | 
| LONG | 32位无符号整数 | int | DWORDLONG | 64位长整数 | long | 
| DWORD | 32位无符号整数 | uint | HDC | 设备描述表句柄 | int | 
| HANDLE | 句柄,32位整数 | int | HGDIOBJ | GDI对象句柄 | int | 
| UINT | 32位无符号整数 | uint | HINSTANCE | 实例句柄 | int | 
| BOOL | 32位布尔型整数 | bool | HWM | 窗口句柄 | int | 
| LPSTR | 指向字符的32位指针 | string | HPARAM | 32位消息参数 | int | 
| LPCSTR | 指向常字符的32位指针 | String | LPARAM | 32位消息参数 | int | 
| BYTE | 字节 | byte | WPARAM | 32位消息参数 | int | 
整个结构的字节数是22bytes。
对应的C++结构体是:
1 typedef struct
2 {
3 WORD id;
4 CHAR name[ 11 ];
5 CHAR password[ 9 ];
6 } Operator;
7
8
3、发送的时候先要把结构转换成字节数组
1 using System.Runtime.InteropServices;
2
3 /// <summary>
4 /// 将结构转换为字节数组
5 /// </summary>
6 /// <param name="obj"> 结构对象 </param>
7 /// <returns> 字节数组 </returns>
8 public byte [] StructToBytes( object obj)
9 {
10 // 得到结构体的大小
11 int size = Marshal.SizeOf(obj);
12 // 创建byte数组
13 byte [] bytes = new byte [size];
14 // 分配结构体大小的内存空间
15 IntPtr structPtr = Marshal.AllocHGlobal(size);
16 // 将结构体拷到分配好的内存空间
17 Marshal.StructureToPtr(obj, structPtr, false );
18 // 从内存空间拷到byte数组
19 Marshal.Copy(structPtr, bytes, 0 , size);
20 // 释放内存空间
21 Marshal.FreeHGlobal(structPtr);
22 // 返回byte数组
23 return bytes;
24
25 }
26
27
接收的时候需要把字节数组转换成结构
1 /// <summary>
2 /// byte数组转结构
3 /// </summary>
4 /// <param name="bytes"> byte数组 </param>
5 /// <param name="type"> 结构类型 </param>
6 /// <returns> 转换后的结构 </returns>
7 public object BytesToStruct( byte [] bytes, Type type)
8 {
9 // 得到结构的大小
10 int size = Marshal.SizeOf(type);
11 Log(size.ToString(), 1 );
12 // byte数组长度小于结构的大小
13 if (size > bytes.Length)
14 {
15 // 返回空
16 return null ;
17 }
18 // 分配结构大小的内存空间
19 IntPtr structPtr = Marshal.AllocHGlobal(size);
20 // 将byte数组拷到分配好的内存空间
21 Marshal.Copy(bytes, 0 , structPtr, size);
22 // 将内存空间转换为目标结构
23 object obj = Marshal.PtrToStructure(structPtr, type);
24 // 释放内存空间
25 Marshal.FreeHGlobal(structPtr);
26 // 返回结构
27 return obj;
28 }
29
4、实际操作:
1 using System.Collections;
2 using System.Collections.Generic;
3 using System.Net;
4 using System.Net.Sockets;
5
6 byte [] Message = StructToBytes( new Operator( " user " , " pass " )); // 将结构转换成字节数组
7
8 TcpClient socket = new TcpClient();
9
10 socket.Connect(ip,port);
11
12 NetworkStream ns = Socket.GetStream();
13
14 ns.Write(Message, 0 ,Message.Length); // 发送
15
16 byte [] Recv = new byte [ 1024 ]; // 缓冲
17
18 int NumberOfRecv = 0 ;
19
20 IList < byte > newRecv = new List < byte > ();
21 ns.ReadTimeout = 3000 ;
22 try
23 {
24 do
25 {
26 // 接收响应
27 NumberOfRecv = ns.Read(Recv, 0 , Recv.Length);
28 for ( int i = 0 ; i < NumberOfRecv; i ++ )
29 newRecv.Add(Recv[i]);
30 }
31 while (ns.DataAvailable);
32 byte [] resultRecv = new byte [newRecv.Count];
33 newRecv.CopyTo(resultRecv, 0 );
34
35 Operator MyOper = new Operator();
36
37 MyOper = (Operator)BytesToStruct(resultRecv, MyOper.GetType()); // 将字节数组转换成结构
38
在这里取值的时候可能会出现只能取到一个字段,剩余的取不到的问题,怎么回事我也搞不懂,反正我的解决办法就是按照字节的顺序从 resultRecv里分别取出对应的字段的字节数组,然后解码,例如:
Operator.name是11个字节,最后一位是0,Operator.id是2个字节,那么从第3位到第12位的字节就是 Operator.name的内容,取出另存为一个数组 MyOperName,Encoding.Default.GetString(MyOperName)就是MyOper.name的内容。
1 socket.Close();
2
3 ns.Close();
4
C#.NET和C++结构体Socket通信与数据转换的更多相关文章
- C/C++编程笔记:C语言对齐问题【结构体、栈内存以及位域对齐】
		
引言 考虑下面的结构体定义: 假设这个结构体的成员在内存中是紧凑排列的,且c1的起始地址是0,则s的地址就是1,c2的地址是3,i的地址是4. 现在,我们编写一个简单的程序: 运行后输出: 为什么会这 ...
 - java socket传送一个结构体给用C++编写的服务器解析的问题
		
另一端是Java写客户端程序,两者之间需要通信.c++/c接收和发送的都是结构体,而Java是直接发送的字节流或者byte 数组.解决方法:c++/c socket 在发送结构体的时候其实发送的也是字 ...
 - C# Socket 入门4 UPD 发送结构体(转)
		
今天我们来学 socket 发送结构体 1. 先看要发送的结构体 using System; using System.Collections.Generic; using System.Text; ...
 - socket编程——sockaddr_in结构体操作
		
sockaddr结构体 sockaddr的缺陷: struct sockaddr 是一个通用地址结构,这是为了统一地址结构的表示方法,统一接口函数,使不同的地址结构可以被bind() , connec ...
 - socket编程相关的结构体和字节序转换、IP、PORT转换函数
		
注意:结构体之间不能直接进行强制转换, 必须先转换成指针类型才可以进行结构体间的类型转换, 这里需要明确的定义就是什么才叫强制转换. 强制转换是将内存中一段代码以另一种不同类型的方式进行解读, 因此转 ...
 - Linux C Socket编程发送结构体、文件详解及实例
		
利用Socket发送文件.结构体.数字等,是在Socket编程中经常需要用到的.由于Socket只能发送字符串,所以可以使用发送字符串的方式发送文件.结构体.数字等等. 本文:http://www.c ...
 - C#与C++通过socket传送结构体
		
C#服务端: using System; using System.Net.Sockets; using System.Net; using System.IO; using System.Diagn ...
 - 2. socket结构体——表示socket地址
		
一.两种通用socket结构体 1. sockaddr struct sockaddr { sa_family_t sa_family; // 地址族 char sa_data[14]; // 存放s ...
 - struct socket结构体详解
		
原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://weiguozhihui.blog.51cto.com/3060615/15852 ...
 
随机推荐
- 性能测试---CPU内存部分
			
CPU内存的测试可以通过top命令来测试 ,如下是我写的bat脚本,其中的测试进程可以替换为你自己需要测试的进程. @echo offecho============================= ...
 - 1.准备工作之Groovy
			
Groovy(读做:gu : ru : wei) Groovy是一种运行在jvm上的动态语言,它吸取了Python.Ruby和SmallTalk等语言的优点:在Java的基础之上增加了许多特色功能,相 ...
 - all about
			
1.三次握手和四次挥手?2.什么是OSI七层结构?3.http vs https?4.what is Ping?基于什么协议?使用方法?5.DNS?6.cookie vs session?7.LDAP ...
 - Python 每日随笔
			
使用python已经有3个月了,带总体来说,还是python菜鸟,今天发现了一个好玩的东西,记录下来,有时间深入研究一下. 关于Metaclass 不得不说python 的元类很有意思,可以做很多有趣 ...
 - 【webpack】-- 入门与解析
			
每次学新东西总感觉自己是不是变笨了,看了几个博客,试着试着就跑不下去,无奈只有去看官方文档. webpack是基于node的.先安装最新的node. 1.初始化 安装node后,新建一个目录,比如ht ...
 - ASP.NET MVC项目中App_Code目录在程序应用
			
学习ASP.NET MVC,如果你是开发ASP.NET MVC项目的,也许你去为项目添加前ASP.NET项目的APP_Code目录,在这里创建与添加的Class类,也许你无法在MVC项目所引用. 那这 ...
 - 全国计算机等级考试二级Python语言程序设计考试大纲
			
全国计算机等级考试二级Python语言程序设计考试大纲(2018年版) 基本要求 掌握Python语言的基本语法规则. 掌握不少于2个基本的Python标准库. 掌握不少于2个Python第三方库,掌 ...
 - Webview 浏览器开源项目总结
			
在Android开发中,我们不免会遇到使用WebView实现网页展示的需求,以下是本人之前star的开源项目,供大家参考: 一.CrosswalkWebview 项目地址:https://github ...
 - 几分钟几张图教你学会如何使用UML
			
很多初次接触UML的朋友们可能会感觉它各种各样的线条.关系.描述等晦涩难懂.本篇文章简单介绍了一下其中几个图,用最朴实的语言结合上图片来让你一眼就能理解他们,如果您在阅读的过程种发现错误之处恳请您在评 ...
 - Go语言map
			
map 是一种特殊的数据结构:一种元素对(pair)的无序集合,pair 的一个元素是 key,对应的另一个元素是 value,所以这个结构也称为关联数组或字典.这是一种快速寻找值的理想结构:给定 k ...