您好,欢迎访问三七文档
当前位置:首页 > 电子/通信 > 综合/其它 > C#和C++结构体Socket通信
C#和C++结构体Socket通信最近在用C#做一个项目的时候,Socket发送消息的时候遇到了服务端需要接收C++结构体的二进制数据流,这个时候就需要用C#仿照C++的结构体做出一个结构来,然后将其转换成二进制流进行发送,之后将响应消息的二进制数据流转换成C#结构。1、仿照C++结构体写出C#的结构来usingSystem.Runtime.InteropServices;[Serializable]//指示可序列化[StructLayout(LayoutKind.Sequential,Pack=1)]//按1字节对齐publicstructOperator{publicushortid;//声明一个字符数组,大小为11[MarshalAs(UnmanagedType.ByValArray,SizeConst=11)]publicchar[]name;[MarshalAs(UnmanagedType.ByValArray,SizeConst=9)]publicchar[]pass;publicOperator(stringuser,stringpass)//初始化{this.id=10000;this.name=user.PadRight(11,'\0').ToCharArray();this.pass=pass.PadRight(9,'\0').ToCharArray();}}2、注意C#与C++数据类型的对应关系C++与C#的数据类型对应关系表API数据类型类型描述C#类型WORD16位无符号整数ushortCHAR字符charLONG32位无符号整数intDWORDLONG64位长整数longDWORD32位无符号整数uintHDC设备描述表句柄intHANDLE句柄,32位整数intHGDIOBJGDI对象句柄intUINT32位无符号整数uintHINSTANCE实例句柄intBOOL32位布尔型整数boolHWM窗口句柄intLPSTR指向字符的32位指针stringHPARAM32位消息参数intLPCSTR指向常字符的32位指针StringLPARAM32位消息参数intBYTE字节byteWPARAM32位消息参数int整个结构的字节数是22bytes。对应的C++结构体是:typedefstruct{WORDid;CHARname[11];CHARpassword[9];}Operator;3、发送的时候先要把结构转换成字节数组usingSystem.Runtime.InteropServices;///summary///将结构转换为字节数组////summary///paramname=obj结构对象/param///returns字节数组/returnspublicbyte[]StructToBytes(objectobj){//得到结构体的大小intsize=Marshal.SizeOf(obj);//创建byte数组byte[]bytes=newbyte[size];//分配结构体大小的内存空间IntPtrstructPtr=Marshal.AllocHGlobal(size);//将结构体拷到分配好的内存空间Marshal.StructureToPtr(obj,structPtr,false);//从内存空间拷到byte数组Marshal.Copy(structPtr,bytes,0,size);//释放内存空间Marshal.FreeHGlobal(structPtr);//返回byte数组returnbytes;}接收的时候需要把字节数组转换成结构///summary///byte数组转结构////summary///paramname=bytesbyte数组/param///paramname=type结构类型/param//returns转换后的结构/returnspublicobjectBytesToStruct(byte[]bytes,Typetype){//得到结构的大小intsize=Marshal.SizeOf(type);Log(size.ToString(),1);//byte数组长度小于结构的大小if(sizebytes.Length){//返回空returnnull;}//分配结构大小的内存空间IntPtrstructPtr=Marshal.AllocHGlobal(size);//将byte数组拷到分配好的内存空间Marshal.Copy(bytes,0,structPtr,size);//将内存空间转换为目标结构objectobj=Marshal.PtrToStructure(structPtr,type);//释放内存空间Marshal.FreeHGlobal(structPtr);//返回结构returnobj;}4、实际操作:usingSystem.Collections;usingSystem.Collections.Generic;usingSystem.Net;usingSystem.Net.Sockets;byte[]Message=StructToBytes(newOperator(user,pass));//将结构转换成字节数组TcpClientsocket=newTcpClient();socket.Connect(ip,port);NetworkStreamns=Socket.GetStream();ns.Write(Message,0,Message.Length);//发送byte[]Recv=newbyte[1024];//缓冲intNumberOfRecv=0;IListbytenewRecv=newListbyte();ns.ReadTimeout=3000;try{do{//接收响应NumberOfRecv=ns.Read(Recv,0,Recv.Length);for(inti=0;iNumberOfRecv;i++)newRecv.Add(Recv[i]);}while(ns.DataAvailable);byte[]resultRecv=newbyte[newRecv.Count];newRecv.CopyTo(resultRecv,0);OperatorMyOper=newOperator();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#代码来实现,我贴个例子给你,我也想知道有没有办法不用unsafecode来得到结构的字节数组。usingSystem;usingSystem.Collections.Generic;usingSystem.Text;namespaceConsoleApplication1{structTest{publicintx,y;}classProgram{unsafestaticbyte[]GetStructBytes(Testt){intn=sizeof(Test);byte*p=(byte*)&t;byte[]r=newbyte[n];for(inti=0;in;i++)r[i]=p[i];returnr;}staticvoidPrintByteArray(byte[]arr){Console.Write(Bytes:);for(inti=0;iarr.Length;i++)Console.Write({0:X},arr[i]);}staticvoidMain(string[]args){Testt=newTest();t.x=0x11223344;t.y=0x22334455;byte[]arr=GetStructBytes(t);PrintByteArray(arr);Console.ReadKey();}}}
本文标题:C#和C++结构体Socket通信
链接地址:https://www.777doc.com/doc-309278 .html