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 ...
随机推荐
- Java内存区域和对象的创建
文章绝大部分内存摘抄自<深入理解Java虚拟机>,结合了小部分个人理解如果有什么错误,还望指出,如果涉及到侵权,联系博主,立马删除,再次感谢<深入理解Java虚拟机>的作者-周 ...
- csharp: using OleDb Getting the identity of the most recently added record
/// <summary> /// 执行SQL语句,返回影响的记录数 /// </summary> /// <param name="SQLString&quo ...
- js小数乘法精确率问题
研究拓扑图百分比乘法计算,带小数位计算会出现值溢出的问题 JS里做小数的乘法运算时会出现浮点错误: 结果是251.89999999999998 而不是251.9 这个问题想必有很多人为之头痛. 那 ...
- <Android 基础(十九)> CoordinatorLayout
介绍 CoordinatorLayout,中文翻译,协调布局,顾名思义,此布局中的子View之间,子View与父布局之间应该是可以协调工作的,如何协调,Behavior. 今天看下Android St ...
- Git学习-Git时光机之版本回退(二)
Git,是Linus花了两周时间用C写的一个分布式版本控制系统.牛人该怎么定义? 零.结论先行 倒叙总结一下: HEAD指向的版本就是当前版本,因此,Git允许我们在版本的历史之间穿梭,使用命令git ...
- 【Android】Android studio 编译问题:finished with non-zero exit value 2
1.Android studio 编译问题:finished with non-zero exit value 2 问题: Error:Execution failed for task ':andr ...
- switch case 忘记 break
昨天纠结了很久的问题,一直找不到原因,早上发现是一个低级错误: private void selectButton(int id) { switch (id) { case 0: recommend_ ...
- DELPHI 小结
//十六进制(S)-->>十进制(I) [重写:Jey]function hextoint(s: string): Integer; begin //$代表16进制 ...
- mongodb远程连接
1.关闭防火墙 firewall-cmd --state 查看防火墙是否运行中 systemctl stop firewalld.service 关闭防火墙服务 2.使用bind_ip指定 ...
- 从尾到头打印链表(C++和Python 实现)
(说明:本博客中的题目.题目详细说明及参考代码均摘自 “何海涛<剑指Offer:名企面试官精讲典型编程题>2012年”) 题目 输入一个链表的头结点, 从尾到头反过来打印出每个结点的值. ...