摘要:
Delphi與C#通過SOCKET通信,互傳結構體。好處是可以把協議及要傳送的內容封裝成一個結構體,一次性發送,不需要再做過多的封包的拆包。封包過程通過的做法是把要發送的內容組成字符串,每個子項內容之間用分隔符隔開,以便客戶端收到內容後知道如何拆包。拆包過程就把接收到的字符串再按分隔符分解成多項,並按封包時對應的子項賦值給對應的接收者。整個過程很繁瑣,並且不同的開發語言對封包拆包操作的實現的支持也不一樣,有的語言方便,有些不方便。
那麼採用結構體的好處就顯而易見了。其一隻需要雙方都定義好結構體,發送方轉成字節發送,接收方按字節接收,再賦值給結構體變量,就完成了通常意義上封包和拆包過程。其二就是容易控制各項的默認值,各種高級語言對結構體的支持越來越到位、方便了。
正文:
1、C#
[StructLayout(LayoutKind.Sequential)]//注意此處一定要有此語句
public struct Body
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]//設置字符的長度,當實際長度不足時,會自動填充0
public string password;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 24)]//
public string Tel;
public int accid;
}
//轉換方法:
public byte[] StructToBytes<T>(T obj)
{
int size = Marshal.SizeOf(obj);
byte[] bytes = new byte[size];
IntPtr arrPtr = Marshal.UnsafeAddrOfPinnedArrayElement(bytes, 0);
Marshal.StructureToPtr(obj, arrPtr, true);
return bytes;
}
//發送
Body body;
body.accid = 123412345;
body.password = "567890123456";
body.Tel = "13526396605abcdefg";
data = StructToBytes<Body>(body);
ClientSocket.Send(Data, 0, Data.Length, SocketFlags.None);
2、接收Delphi
procedure TMain_Frm.btn14Click(Sender: TObject);
type
TBody=Packed Record //包體定義
password: array[0..15] of char; //密碼
Tel :array[0..23] of char; //手機號
accid: integer; //編號
end;
var
data, recbuff: TIdBytes;
Body: TBody;
begin
IdTCPClient1.Connect('192.163.1.132', 5632);
SetLength(data, 1)
data[0] := $F0;
idtcpclnt1.Socket.Write(data);//服務端接收到後返回一個整數
IdTCPClient1.Socket.ReadBytes(recbuff, SizeOf(Body));
Move( recbuff[0], Body, Length(recbuff) - 1);
ShowMessage('密碼:' + Body.password + #13 + 'tel:' + Body.Tel + #13 + '數字:' + FloatToStr(Body.accid));
end;
接收完成時,就是各項分解並賦值完成時,省去了拆包過程。
3、缺點
1、所有內容都必須是能夠提前知道長度的;
2、傳輸的內容相對簡單,太複雜的結構傳不了。
結束語:
1、本文重點在於介紹不同語言間如何傳遞結構體,並無強調結構體優越之意。
2、本文舉例的結構可傳遞協議,也是基於本人的刷卡交易模塊。由於格式固定、內容統一,才易於實現。
3、感謝網上資料的支持,由於大家的無私奉獻,才完成了此功能,在此統一謝過。