Delphi中UDP协议通讯
先在type域中定义Record(未压缩)或Packed Rcord(压缩包)结构体,再用Indy的idUDPclient和idUDPServer分别负责发送和接收
如:注意每定义一节都接一个End;表示定义完其中一个,末尾不再加其他end;
{------------------------------------------------------}
type
tcGetUserBuffer = record
ID: Integer;
Size: Integer;
nType: DWORD; //Dword是无符号32位长整型,直接赋十进制数就可以了。
UserID: Dword;
IMEI: array [0..23] of char;
end;
tcGetUserNextBuffer = record
ID: integer;
size: integer;
nTtype: Dword;
IP: Dword;
Port: Dword;
info:array[0..9] of char; //这是定义一个十位的Char类型,在VC++中用Char name[10][定义
end;
{------------------------------------------------------}
上面只是定义了结构体,在使用时,需要注意的是:这只是一个结构,也就是一个类似于骨架的东西,没有实际意义,在给结构体赋值(一般称为填包)时,发出去和接收到的只是一堆数组,所以发送和接收时都需要用到定义的结构体。另外有些结构体为了方便,也可以像下面这样定义包头和包体,在接收处理时就会更方便、灵活一些。
type
Head = record
ID:integer;
Command:Dword;
end;
tGetInfo = record
userID: Dword;
end;
tGetInfoBuffer = record;
tHead: Head;
tBody:tGetInfo;
end;
像上面这样就定义了一个多维的结构体,其实到最后还是一样的数组发送和接收。
现在看看怎么发送:
Procedure Button1_click();
var
Buffer: tcGetUserBuffer;
begin
Buffer.ID=1234;
Buffer.nType=4;
... //结构一般要填满,这里省略
IDudpClient.SendBuffer(Buffer,Sizeof(tcGetUserBuffer)) //Sizeof一定要获得结构体的长度才行。
end;
以上是发送一个包,现在看看接收包和处理包。
procedure TForm1.IdUS1UDPRead(Sender: TObject; AData: TBytes;
ABinding: TIdSocketHandle); //注意,D7中要手动uses[IdSocketHandle]这个类,自己加在上面。
Var
Buffer1: tcGetUserBuffer;
Buffer2: tcGetUserNextBuffer ;
//依此类推,把要用到的变量名Buffer[n]和结构体都定义好,以区分比较复杂的包类型。
begin
//下面是根据包长度判断不同的包,来分别处理它们。
if length(AData)=sizeof(tcGetUserBuffer) then
begin
Adata.read(Buffer1,Adata.size);
showmessage(inttostr(Buffer1.ID));
Abinding.sendto(Abinding.peerip,Abinding.peerport,data,sizeof(dataRecord)) //这句的意思是向发数据的IP和端口号回复数据,这个data和dataRecord没有填包和定义,实际应用时,要注意。
end;
if length(AData)=sizeof(tcGetUserNextBuffer) then
begin
Adata.read(Buffer2,Adata.size);
showmessage(inttostr(Buffer1.ID));
end;
end;
**指针的用法也很关键的
比如UDPserver收到数据包也可以用一个字节数组来接收
Var
ArrByte: Array [0..64000] of byte;
begin
Adata.readBuffer(ArrByte,Adata.size);
end;
在使用时,则要用到各种指针操作命令了。
Arrbyte[0]就是从数组的第一个字节。
读取字符串时,要用到Pchar(@ArrByte[0]),注意只用了一个@,后面不接^。
读取数字时,用Pinteger(@ArrByte[0])^,这里用了两个符号,要注意它们的 位置。
注意:上面两例都是读数组的所有字节,所以,在实际用时,可能要用到这个命令
Move(ArrByte1,ArrByte2,tSize)
两个数组没有定义,后面的大小要看实际情况。
Move是一个很好用的东东,有时可能需要从结构Record复制到数组,也是一样的:
Move(Buffer1,ArrByte,tSize)
这样就可以了。
其实Delphi在实际处理中还有很多东西,以后慢慢写,比如用线程发包、收包处理,包频繁发送,量大的还要做发送队列用到很多控件和类,以后再写啦。