Udp
数据接收端实现
----Delphi实现
Lanno Ckeeke
LC2005052202
概要
此程序本想与上一篇实现的功能相同,代码是在delphi6编写。与C++程序相比,其发送端发送数据太快,在一个for循环中连续调用sendto20次,则此程序将不能完全接收到数据。若在for循环中每发送一次数据后 sleep(200),则此程序可以接收全部的数据。这就是UDP数据传输的不可靠性吗?而C++程序(LC2005052201)则不会出现此现象。进一步考虑中。。。。。。
说明
所用到的函数与LC2005052201相同,可以参见上一篇文章。
窗体中一个Button用于启动程序进行必要的socket设置,并开始接收数据(处于阻塞状态);一个EditBox用于显示接收数据的次数;一个ListBox用于显示已接收到的数据。
变量说明在代码中有详细的注释。
- unit Unit1;
- interface
- uses
- Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
- Dialogs, StdCtrls,Winsock;
- type
- TForm1 = class(TForm)
- Button2: TButton; //开始接收数据
- ListBox1: TListBox; //将接收到的数据显示到列表中
- Edit1: TEdit; //显示接收了多少次数据
- procedure Button2Click(Sender: TObject);
- private
- { Private declarations }
- public
- { Public declarations }
- end;
- procedure CheckRc(szErr : PChar);
- var
- Form1: TForm1;
- const
- DEFAULT_PORT = 5150; //接收端口号
- DEFAULT_COUNT = 20; //接收20次
- DEFAULT_BUFFER_LENGTH = 4096; //接收数据的最大缓冲区大小
- var
- nPort : Integer = DEFAULT_PORT;
- dwCount : DWORD = DEFAULT_COUNT;
- dwLength : DWORD = DEFAULT_BUFFER_LENGTH ;
- szInterface : array[0..31] of char;
- wsd : WSAData; //保存初始化信息
- soRecv : TSOCKET; //接收数据的socket
- pszRecv: PChar; //接收数据的缓冲区指针
- nRet : integer;
- i : integer;
- dwSenderSize : Integer;
- siSender,local : SOCKADDR_IN;
- nError : Integer;
- implementation
- {$R *.dfm}
- procedure CheckRc(szErr : PChar);
- begin
- MessageBox(0,szErr,'Error',MB_OK);
- end;
- procedure TForm1.Button2Click(Sender: TObject);
- var
- i: integer;
- nLastError : Integer;
- nNumOfRecv : Integer;
- begin
- nNumOfRecv := 0;
- //初始化socket
- nError := WSAStartup(MakeWord(2,2),wsd);
- if Boolean(nError) then
- MessageBox(0,'WSAStartup','Error',MB_OK);
- //建立socket
- soRecv := socket(AF_INET,SOCK_DGRAM,0);
- if soRecv = SOCKET_ERROR then
- begin
- CheckRc('socket');
- end;
- //设置端口与地址
- local.sin_family := AF_INET;
- local.sin_port := htons(5150);
- local.sin_addr.S_addr := inet_addr('127.0.0.1');
- //将socket绑定地址
- nError := bind(soRecv,local,sizeof(local));
- if nError = SOCKET_ERROR then
- CheckRc('bind');
- //分配内存
- pszRecv := AllocMem(4096);
- for i := 0 to dwCount -1 do
- begin
- dwSenderSize := SizeOf(siSender);
- //接收发送过来的数据,并保存到缓冲区中
- nRet := recvFrom(soRecv,pszRecv[0],4096,0,siSender,dwSenderSize);
- if nRet = SOCKET_ERROR then
- begin
- CheckRc('recvFrom');
- break;
- end else if nRet = 0 then
- break
- else
- begin
- pszRecv[nRet] := #0;
- //添加到列表中,仅用于显示
- self.ListBox1.Items.Add(pszRecv);
- end;
- Inc(nNumOfRecv);
- self.Edit1.Text := IntToStr(nNumOfRecv);
- end; //end of for
- //关闭 socket
- closesocket(soRecv);
- //释放分配的内存
- FreeMem(pszRecv);
- //清理winsocket
- WSACleanup();
- end;
- end.