C#和C++的Socket通信
最近在用C#做一个项目的时候,Socket发送消息的时候遇到了服务端需要接收C++结构体的二进制数据流,这个时候就需要用C#仿照C++的结构体做出一个结构来,然后将其转换成二进制流进行发送,之后将响应消息的二进制数据流转换成C#结构。
1、仿照C++结构体写出C#的结构
[Serializable] // 指示可序列化
[StructLayout(LayoutKind.Sequential, Pack = )] // 按1字节对齐
public struct Operator
{
public ushort id;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = )] // 声明一个字符数组,大小为11
public char[] name;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = )]
public char[] pass; public Operator(string user, string pass) // 初始化
{
this.id = ;
this.name = user.PadRight(, '\0').ToCharArray();
this.pass = pass.PadRight(, '\0').ToCharArray();
}
}
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++结构体是:
typedef struct
{
WORD id;
CHAR name[];
CHAR password[];
}Operator;
3、发送的时候先要把结构转换成字节数组
/// <summary>
/// 将结构转换为字节数组
/// </summary>
/// <param name="obj">结构对象</param>
/// <returns>字节数组</returns>
public static byte[] StructToBytes(object obj)
{
//得到结构体的大小
int size = Marshal.SizeOf(obj);
//创建byte数组
byte[] bytes = new byte[size];
//分配结构体大小的内存空间
IntPtr structPtr = Marshal.AllocHGlobal(size);
//将结构体拷到分配好的内存空间
Marshal.StructureToPtr(obj, structPtr, false);
//从内存空间拷到byte数组
Marshal.Copy(structPtr, bytes, , size);
//释放内存空间
Marshal.FreeHGlobal(structPtr);
//返回byte数组
return bytes;
}
//接收的时候需要把字节数组转换成结构
/// <summary>
/// byte数组转结构
/// </summary>
/// <param name="bytes">byte数组</param>
/// <param name="type">结构类型</param>
/// <returns>转换后的结构</returns>
public static object BytesToStruct(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, , structPtr, size);
//将内存空间转换为目标结构
object obj = Marshal.PtrToStructure(structPtr, type);
//释放内存空间
Marshal.FreeHGlobal(structPtr);
//返回结构
return obj;
}
4、实际操作:
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
byte[] Message = StructToBytes(new Operator("user","pass")); // 将结构转换成字节数组
TcpClient socket = new TcpClient();
socket.Connect(ip,port);
NetworkStream ns = Socket.GetStream();
ns.Write(Message,,Message.Length); // 发送
byte[] Recv = new byte[]; // 缓冲
int NumberOfRecv = ;
IList<byte> newRecv = new List<byte>();
ns.ReadTimeout = ;
try
{
do
{
// 接收响应
NumberOfRecv = ns.Read(Recv, , Recv.Length);
for (int i = ; i < NumberOfRecv; i++)
newRecv.Add(Recv[i]);
}
while (ns.DataAvailable);
byte[] resultRecv = new byte[newRecv.Count];
newRecv.CopyTo(resultRecv, );
Operator MyOper = new Operator();
MyOper = (Operator)BytesToStruct(resultRecv, MyOper.GetType()); // 将字节数组转换成结构
在这里取值的时候可能会出现只能取到一个字段,剩余的取不到的问题,怎么回事我也搞不懂,反正我的解决办法就是按照字节的顺序从resultRecv里分别取出对应的字段的字节数组,然后解码,例如:
Operator.name是11个字节,最后一位是0,Operator.id是2个字节,那么从第3位到第12位的字节就是Operator.name的内容,取出另存为一个数组MyOperName,Encoding.Default.GetString(MyOperName)就是MyOper.name的内容。
socket.Close();
ns.Close();
C#和C++的Socket通信的更多相关文章
- 我看不下去鸟。。。。Java和C#的socket通信真的简单吗?
这几天在博客园上看到好几个写Java和C#的socket通信的帖子.但是都为指出其中关键点. C# socket通信组件有很多,在vs 使用nuget搜索socket组件有很多类似的.本人使用的是自己 ...
- php简单实现socket通信
socket通信的原理在这里就不说了,它的用途还是比较广泛的,我们可以使用socket来做一个API接口出来,也可以使用socket来实现两个程序之间的通信,我们来研究一下在php里面如何实现sock ...
- Socket通信类
package com.imooc; import java.io.BufferedReader; import java.io.IOException; import java.io.InputSt ...
- AgileEAS.NET SOA 中间件平台.Net Socket通信框架-介绍
一.前言 AgileEAS.NET SOA 中间件平台是一款基于基于敏捷并行开发思想和Microsoft .Net构件(组件)开发技术而构建的一个快速开发应用平台.用于帮助中小型软件企业建立一条适合市 ...
- socket通信
socket通信 一:socket基于Tcp连接,数据传输有保证 二:socket连接的建立过程: 1:服务器监听 2:客户端发出请求 3:建立连接 4:通信 三:一个简单的例子:服务器端每隔一段时间 ...
- Android之Socket通信、List加载更多、Spinner下拉列表
Android与服务器的通信方式主要有两种,一是Http通信,一是Socket通信.两者的最大差异在于,http连接使用的是“请求—响应方式”,即在请求时建立连接通道,当客户端向服务器发送请求后,服务 ...
- .NET开源高性能Socket通信中间件Helios介绍及演示
一:Helios是什么 Helios是一套高性能的Socket通信中间件,使用C#编写.Helios的开发受到Netty的启发,使用非阻塞的事件驱动模型架构来实现高并发高吞吐量.Helios为我们大大 ...
- iOS开发之Socket通信实战--Request请求数据包编码模块
实际上在iOS很多应用开发中,大部分用的网络通信都是http/https协议,除非有特殊的需求会用到Socket网络协议进行网络数 据传输,这时候在iOS客户端就需要很好的第三方CocoaAsyncS ...
- AgileEAS.NET SOA 中间件平台.Net Socket通信框架-简单例子-实现简单的服务端客户端消息应答
一.AgileEAS.NET SOA中间件Socket/Tcp框架介绍 在文章AgileEAS.NET SOA 中间件平台Socket/Tcp通信框架介绍一文之中我们对AgileEAS.NET SOA ...
- AgileEAS.NET SOA 中间件平台.Net Socket通信框架-完整应用例子-在线聊天室系统-下载配置
一.AgileEAS.NET SOA中间件Socket/Tcp框架介绍 在文章AgileEAS.NET SOA 中间件平台Socket/Tcp通信框架介绍一文之中我们对AgileEAS.NET SOA ...
随机推荐
- golang学习之闭包
匿名函数不能够独立存在,但可以被赋值于某个变量,即保存函数的地址到变量中:fplus := func(x, y int) int { return x + y },然后通过变量名对函数进行调用:fpl ...
- Spring相关概念的理解理解
spring 框架的优点是一个轻量级比较简单易学的框架,实际使用中的有点优点有哪些呢!1.降低了组件之间的耦合性 ,实现了软件各层之间的解耦 2.可以使用容易提供的众多服务,如事务管理,消息服务等 3 ...
- hdu 1011 Starship Troopers 经典的树形DP ****
Starship Troopers Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Other ...
- Ascii码 unicode码 utf-8编码 gbk编码的区别
ASCII码: 只包含英文,数字,特殊符号的编码,一个字符用8位(bit)1字节(byte)表示 Unicode码: 又称万国码,包含全世界所有的文字,符号,一个字符用32位(bit)4字节(byte ...
- HTML5特效~3D立方体旋转
先欣赏一下该特效的最终效果 本文源码参考自http://www.cnblogs.com/ECJTUACM-873284962/进行一点点优化,下面是对此特效原理上的的剖析. 该特效是基于Css3的一些 ...
- Tjoi2016&Heoi2016 字符串
传送门 另一个传送门 终于把心头大恨切掉了……后缀自动机大法好,从此抛弃后缀数组哈哈……(说的跟你会写后缀数组似的 好像网上的题解大多都是后缀数组?看了看表示理解不能,那我这份后缀自动机的题解就写详细 ...
- 配合sublime使用flexible.js实现微信开发页面自适应
什么是flexible.js 是一个终端设备适配的解决方案.也就是说它可以让你在不同的终端设备中实现页面适配. 是一个用来适配移动端的javascript框架.根据宽度的不同设置不同的字体大小,样式间 ...
- easyui汉化啊!
<script type="text/javascript" src="__PUBLIC__/jquery-easyui-1.4.4/locale/easyui-l ...
- FiddLer模拟post不成功的解决办法
开始用fiddler抓app包,后来想模拟一下post请求,发现一直接受不到,wtf? 默认的header是类似这样的 User-Agent: Fiddler Host: localhost Cont ...
- sqlserver根据条件生成插入语句--单表
ALTER proc [dbo].[proc_insert] (@tablename varchar(256),@where varchar(max))asbeginset nocount ondec ...