日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > C# >内容正文

C#

C#和C++结构体Socket通信

發布時間:2023/12/9 C# 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C#和C++结构体Socket通信 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

From:?http://hi.baidu.com/yangliangwang/blog/item/1a0116138ff098d6f6039ea9.html

最近在用C#做一個項目的時候,Socket發送消息的時候遇到了服務端需要接收C++結構體的二進制數據流,這個時候就需要用C#仿照C++的結構體做出一個結構來,然后將其轉換成二進制流進行發送,之后將響應消息的二進制數據流轉換成C#結構。

1、仿照C++結構體寫出C#的結構來

??? using System.Runtime.InteropServices;

??? [Serializable] // 指示可序列化
??? [StructLayout(LayoutKind.Sequential, Pack = 1)] // 按1字節對齊
??? public struct Operator

??? {
???????? public ushort id;
??????? [MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)] // 聲明一個字符數組,大小為11
??????? public char[] name;
??????? [MarshalAs(UnmanagedType.ByValArray, SizeConst = 9)]
??????? public char[] pass;

???????? public Operator(string user, string pass) // 初始化
??????? {
??????????? this.id = 10000;
??????????? this.name = user.PadRight(11, '\0').ToCharArray();
??????????? this.pass = pass.PadRight(9, '\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[11];
??? CHAR password[9];
}Operator;

3、發送的時候先要把結構轉換成字節數組

??????? using System.Runtime.InteropServices;?????

???????? /// <summary>
??????? /// 將結構轉換為字節數組
??????? /// </summary>
??????? /// <param name="obj">結構對象</param>
??????? /// <returns>字節數組</returns>
??????? public 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, 0, size);
??????????? //釋放內存空間
??????????? Marshal.FreeHGlobal(structPtr);
??????????? //返回byte數組
??????????? return bytes;

?????? }

接收的時候需要把字節數組轉換成結構

??????? /// <summary>
??????? /// byte數組轉結構
??????? /// </summary>
??????? /// <param name="bytes">byte數組</param>
??????? /// <param name="type">結構類型</param>
??????? /// <returns>轉換后的結構</returns>
??????? public object BytesToStruct(byte[] bytes, Type type)
??????? {
??????????? //得到結構的大小
??????????? int size = Marshal.SizeOf(type);
??????????? Log(size.ToString(), 1);
??????????? //byte數組長度小于結構的大小
??????????? if (size > bytes.Length)
??????????? {
??????????????? //返回空
??????????????? return null;
??????????? }
??????????? //分配結構大小的內存空間
??????????? IntPtr structPtr = Marshal.AllocHGlobal(size);
??????????? //將byte數組拷到分配好的內存空間
??????????? Marshal.Copy(bytes, 0, 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,0,Message.Length); // 發送

byte[] Recv = new byte[1024]; // 緩沖

int NumberOfRecv = 0;

IList<byte> newRecv = new List<byte>();
ns.ReadTimeout = 3000;
try
{
do
{
// 接收響應
NumberOfRecv = ns.Read(Recv, 0, Recv.Length);
for (int i = 0; i < NumberOfRecv; i++)
newRecv.Add(Recv[i]);
}
while (ns.DataAvailable);
byte[] resultRecv = new byte[newRecv.Count];
newRecv.CopyTo(resultRecv, 0);

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通信的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。