SHUDPSocket.pas
上传用户:hylc_2004
上传日期:2014-01-23
资源大小:46800k
文件大小:13k
源码类别:

Delphi控件源码

开发平台:

Delphi

  1. unit SHUDPSocket;
  2. interface
  3. uses
  4.   SysUtils, Windows, Winsock2, Classes;
  5. const
  6.   DEFAULT_SENDBUF_SIZE = 8192; //系统默认的缓冲区大小
  7.   DEFAULT_RECVBUF_SIZE = 8192; //系统默认的缓冲区大小
  8. type
  9.   TUDPRecvThread = class;
  10.   TSHUDPSocket = class;
  11.   TUDPException = class(Exception);
  12.   //usInit包括设置缓冲区长度
  13.   //usSend是发送数据的时候
  14.   //usRecv是接受数据的时候
  15.   //usClose是关闭套接字的时候
  16.   TPeerInfo = record
  17.     PeerIP: string; //接受到的数据包的IP
  18.     PeerPort: integer;
  19.   end;
  20.   TUDPErrorClass = (usInit, usSend, usRecv, usClose);
  21.   TUDPErrorEvent = procedure(UDPSocket: TSHUDPSocket; ErrorClass:
  22.     TUdpErrorClass; var ErrorCode: integer) of object;
  23.   TUDPReadEvent = procedure(UDPSocket: TSHUDPSocket; const PeerInf: TPeerInfo)
  24.     of object;
  25.   //主要的UDP类
  26.   TSHUDPSocket = class(TComponent)
  27.   private
  28.     //套接字
  29.     FSocket: TSocket;
  30.     //绑定端口号
  31.     FPort: integer;
  32.     //错误处理事件
  33.     FOnSocketError: TUDPErrorEvent;
  34.     //读数据事件
  35.     FOnDataRead: TUDPReadEvent;
  36.     //发送和接受缓冲大小
  37.     FSendBufSize: integer;
  38.     FRecvBufSize: integer;
  39.     //记录接受到数据的远程机器的信息
  40.     FPeerInfo: TPeerInfo;
  41.     //发送数据的套接字
  42.     FAddrOut: TSockAddrIn;
  43.     //可以在这段时间进行一些客户清理工作
  44.     //得到数据到达时间
  45.     FWaitForTime: Longword;
  46.     FOnTimeOut: TThreadMethod;
  47.     //判断是否打开了套接字
  48.     FActive: boolean;
  49.     //是否广播
  50.     FBroadcast: boolean;
  51.     //得到和设置缓冲大小的函数
  52.     function GetSendBufSize: integer;
  53.     function GetRecvBufSize: integer;
  54.     procedure SetSendBufSize(Value: integer);
  55.     procedure SetRecvBufSize(value: integer);
  56.     procedure SetActive(value: boolean);
  57.     procedure SetWaitForTime(Value: Longword);
  58.     procedure DoActive(Active: boolean);
  59.     procedure SetBroadcast(const Value: boolean);
  60.     function GetVer: string;
  61.   protected
  62.     FUDPRecvThread: TUDPRecvThread;
  63.     procedure Loaded; override;
  64.     procedure ReadData; virtual; //供后代继承重新覆盖该事件
  65.   public
  66.     constructor Create(AOwner: TComponent); override;
  67.     destructor Destroy; override;
  68.     //两个普通的发送函数
  69.     function SendBuf(var buf; Size: integer; IP: string; Port: integer):
  70.       boolean;
  71.     function SendText(Text: string; IP: string; Port: integer): boolean;
  72.     //两个发送广播的函数
  73.     function SendBroadBuf(var buf; Size: integer; Port: integer): boolean;
  74.     function SendBroadText(Text: string; Port: integer): boolean;
  75.     //接受函数
  76.     function RecvBuf(var buf; Size: integer): Integer;
  77.     //接受到远程数据的Client信息
  78.     property RecvInf: TPeerInfo read FPeerInfo;
  79.   published
  80.     //发送和接受缓冲区大小
  81.     property SendBufSize: integer read GetSendBufSize write SetSendBufSize
  82.       default DEFAULT_SENDBUF_SIZE;
  83.     property RecvBufSize: integer read GetRecvBufSize write SetRecvBufSize
  84.       default DEFAULT_RECVBUF_SIZE;
  85.     //监听端口
  86.     property Port: integer read FPort write FPort default 0;
  87.     //等待数据超时间 默认是$FFFFFFFF;
  88.     property WaitForTime: DWORD read FWaitForTime write SetWaitForTime default
  89.       $FFFFFFFF;
  90.     //打开套接字
  91.     property Active: boolean read FActive write SetActive default false;
  92.     //
  93.     //5种事件类型
  94.     //
  95.     //有数据到达的事件
  96.     property OnDataRead: TUDPReadEvent read FOnDataRead write FOnDataRead;
  97.     //套接字发生错误事件
  98.     property OnSocketError: TUDPErrorEvent read FOnSocketError write
  99.       FOnSocketError;
  100.     //接受数据发生超时
  101.     property OnTimeOut: TThreadMethod read FOnTimeOut write FOnTimeOut;
  102.     //是否广播数据
  103.     property Broadcast: boolean read FBroadcast write SetBroadcast default
  104.       False;
  105.     property Ver: string read GetVer;
  106.   end;
  107.   TUDPRecvThread = class(TThread)
  108.   private
  109.     FSocket: TSHUDPSocket;
  110.     FEvent: WSAEvent;
  111.     //接受到数据的事件
  112.     FOnDataRecv: TThreadMethod;
  113.     procedure InitEvent;
  114.     procedure FreeEvent;
  115.   protected
  116.     procedure Execute; override;
  117.   public
  118.     property OnDataRecv: TThreadMethod read FOnDataRecv write FOnDataRecv;
  119.     constructor Create(AUdpSocket: TSHUDPSocket);
  120.     destructor Destroy; override;
  121.     procedure Stop;
  122.   end;
  123. procedure Register;
  124. implementation
  125. { TUdpSocket }
  126. uses
  127.   SHSocket;
  128. procedure Register;
  129. begin
  130.   RegisterComponents('SHNetTool', [TSHUDPSocket]);
  131. end;
  132. constructor TSHUDPSocket.Create(AOwner: TComponent);
  133. begin
  134.   //初始化所有的参数
  135.   inherited Create(AOwner);
  136.   FActive := False;
  137.   FPort := 0;
  138.   FillChar(FPeerInfo, SizeOf(FPeerInfo), 0);
  139.   FSendBufSize := DEFAULT_SENDBUF_SIZE;
  140.   FRecvBufSize := DEFAULT_RECVBUF_SIZE;
  141.   FSocket := INVALID_SOCKET;
  142.   FUdpRecvThread := nil;
  143.   FWaitForTime := $FFFFFFFF;
  144.   FBroadcast := False;
  145. end;
  146. destructor TSHUDPSocket.Destroy;
  147. begin
  148.   if FActive then
  149.     DoActive(False);
  150.   inherited Destroy;
  151. end;
  152. procedure TSHUDPSocket.DoActive(Active: boolean);
  153. var
  154.   iError: Integer;
  155. begin
  156.   if Active and (FSocket = INVALID_SOCKET) then //开始初始化套接字
  157.   begin
  158.     FSocket := SHSocket.InitUDPSocket(FPort);
  159.     if FSocket <> INVALID_SOCKET then
  160.     begin
  161.       FActive := True;
  162.       try
  163.         SetBroadcast(FBroadCast);
  164.         SetSendBufSize(FSendBufSize);
  165.         SetRecvBufSize(FRecvBufSize);
  166.         FUDPRecvThread := TUdpRecvThread.Create(Self);
  167.         FUDPRecvThread.FOnDataRecv := ReadData;
  168.         FUDPRecvThread.Resume;
  169.       except
  170.         DoActive(False);
  171.         raise TUDPException.Create('建立监听线程发生错误...');
  172.       end;
  173.     end
  174.     else
  175.     begin
  176.       iError := WSAGetLastError();
  177.       if Assigned(FOnSocketError) then
  178.         FOnSocketError(Self, usInit, iError);
  179.       if iError <> 0 then
  180.         raise TUDPException.CreateFmt('初始化套接字发生错误,错误代码是%d',
  181.           [iError]);
  182.     end;
  183.   end
  184.   else //关闭套接字
  185.   begin
  186.     if Assigned(FUdpRecvThread) then
  187.     begin
  188.       FUdpRecvThread.Stop;
  189.       FreeAndNil(FUdpRecvThread);
  190.     end;
  191.     FreeSocket(FSocket);
  192.     FActive := False;
  193.   end;
  194. end;
  195. function TSHUDPSocket.GetRecvBufSize: integer;
  196. begin
  197.   if FActive then
  198.   begin
  199.     Result := SHSocket.GetRecvBufSize(FSocket);
  200.     FRecvBufSize := Result;
  201.   end
  202.   else
  203.     Result := FRecvBufSize;
  204. end;
  205. function TSHUDPSocket.GetSendBufSize: integer;
  206. begin
  207.   if FActive then
  208.   begin
  209.     Result := SHSocket.GetSendBufSize(FSocket);
  210.     FSendBufSize := Result;
  211.   end
  212.   else
  213.     Result := FSendBufSize;
  214. end;
  215. function TSHUDPSocket.GetVer: string;
  216. const
  217.   TAB = #13#10;
  218. begin
  219.   MessageBox(0,
  220.     PChar('SHUDPSocket 2.0A' + TAB + '作者:孙辉 EMAIL:sunhuiNO1@hotmail.com'),
  221.     '版本',
  222.     MB_ICONINFORMATION);
  223.   Result := 'SHUDPSocket 2.0A';
  224. end;
  225. procedure TSHUDPSocket.Loaded;
  226. begin
  227.   inherited Loaded;
  228.   SetActive(FActive);
  229. end;
  230. procedure TSHUDPSocket.ReadData;
  231. begin
  232.   if Assigned(FOnDataRead) then
  233.     FOnDataRead(Self, FPeerInfo);
  234. end;
  235. function TSHUDPSocket.RecvBuf(var buf; Size: integer): Integer;
  236. var
  237.   AddrIn: TSockAddrIn;
  238.   iRc, iAddr: integer;
  239.   iError: Integer;
  240. begin
  241.   iAddr := SizeOf(AddrIn);
  242.   iRc := RecvFrom(FSocket, buf, Size, 0, AddrIn, iAddr);
  243.   with FPeerInfo do
  244.   begin
  245.     PeerPort := ntohs(AddrIn.sin_port);
  246.     PeerIP := inet_ntoa(AddrIn.sin_addr);
  247.   end;
  248.   Result := iRc;
  249.   if iRc = SOCKET_ERROR then
  250.   begin
  251.     iError := WSAGetLastError();
  252.     if iError <> WSAEWOULDBLOCK then //缓冲区满的错误代码
  253.     begin
  254.       if Assigned(FOnSocketError) then
  255.         FOnSocketError(Self, usRecv, iError);
  256.       if iError <> 0 then
  257.         raise TUDPException.CreateFmt('接受数据发生错误,错误代码是%d',
  258.           [iError]);
  259.     end;
  260.   end;
  261. end;
  262. function TSHUDPSocket.SendBroadBuf(var buf; Size, Port: integer): boolean;
  263. begin
  264.   if not FBroadcast then
  265.     SetBroadcast(True);
  266.   Result := SendBuf(buf, size, '255,255,255,255', Port);
  267. end;
  268. function TSHUDPSocket.SendBroadText(Text: string; Port: integer): boolean;
  269. begin
  270.   Result := SendText(Text, '255,255,255,255', Port);
  271. end;
  272. function TSHUDPSocket.SendBuf(var buf; Size: integer; IP: string;
  273.   Port: integer): boolean;
  274. var
  275.   iRc, iError: integer;
  276. begin
  277.   Result := False;
  278.   FAddrOut.sin_family := AF_INET;
  279.   FAddrOut.sin_port := htons(Port);
  280.   FAddrOut.sin_addr.S_addr := inet_addr(pchar(IP));
  281.   if (not FBroadcast) and (FAddrOut.sin_addr.S_addr = INADDR_NONE) then
  282.     raise TUDPException.Create('无效的远程IP地址...');
  283.   iRc := SendTo(FSocket, buf, Size, 0, FAddrOut, SizeOf(FAddrOut));
  284.   if iRc = SOCKET_ERROR then
  285.   begin
  286.     iError := WSAGetLastError();
  287.     if iError <> WSAEWOULDBLOCK then
  288.     begin
  289.       if Assigned(FOnSocketError) then
  290.         FOnSocketError(Self, usSend, iError);
  291.       if iError <> 0 then
  292.         raise TUDPException.CreateFmt('发送数据发生错误,错误代码是%d',
  293.           [iError]);
  294.     end;
  295.   end
  296.   else
  297.     Result := True;
  298. end;
  299. function TSHUDPSocket.SendText(Text: string; IP: string; Port: integer):
  300.   boolean;
  301. begin
  302.   Result := SendBuf(Pointer(Text)^, Length(Text), IP, Port);
  303. end;
  304. procedure TSHUDPSocket.SetActive(value: boolean);
  305. begin
  306.   if (csDesigning in ComponentState)
  307.     or (csLoading in ComponentState) then
  308.   begin
  309.     if (FActive <> Value) then
  310.       FActive := Value
  311.   end
  312.   else
  313.   begin
  314.     DoActive(Value);
  315.   end;
  316. end;
  317. procedure TSHUDPSocket.SetBroadcast(const Value: boolean);
  318. var
  319.   iError: integer;
  320. begin
  321.   if (Value <> FBroadcast)
  322.     or (csDesigning in ComponentState)
  323.     or (csLoading in ComponentState) then
  324.   begin
  325.     FBroadcast := Value;
  326.     Exit;
  327.   end;
  328.   if (FSocket <> INVALID_SOCKET) and (not SHSocket.SetBroadCasst(FSocket, Value))
  329.     then
  330.   begin
  331.     iError := WSAGetLastError();
  332.     if Assigned(FOnSocketError) then
  333.       FOnSocketError(Self, usInit, iError);
  334.     if iError <> 0 then
  335.       raise TUDPException.CreateFmt(
  336.         '设置广播出错,错误代码是%d',
  337.         [iError]);
  338.   end
  339.   else
  340.     FBroadCast := Value;
  341. end;
  342. procedure TSHUDPSocket.SetRecvBufSize(value: integer);
  343. begin
  344.   if (csDesigning in ComponentState) or (csLoading in ComponentState) then
  345.   begin
  346.     if (Value <> FRecvBufSize) and (Value >= 0) then
  347.       FRecvBufSize := Value;
  348.     Exit;
  349.   end
  350.   else if SHSocket.SetRecvBufSize(FSocket, Value) then
  351.   begin
  352.     FRecvBufSize := Value;
  353.   end
  354.   else
  355.     raise TUDPException.CreateFmt('设置接受缓冲区出错,错误代码是%d',
  356.       [WSAGetLastError()]);
  357. end;
  358. procedure TSHUDPSocket.SetSendBufSize(Value: integer);
  359. begin
  360.   if (csDesigning in ComponentState) or (csLoading in ComponentState) then
  361.   begin
  362.     if (Value <> FSendBufSize) and (Value >= 0) then
  363.       FSendBufSize := Value;
  364.     Exit;
  365.   end
  366.   else
  367.   begin
  368.     if SHSocket.SetSendBufSize(FSocket, Value) then
  369.     begin
  370.       FSendBufSize := Value;
  371.     end
  372.     else
  373.       raise TUDPException.CreateFmt('设置发送缓冲区出错,错误代码是%d',
  374.         [WSAGetLastError()]);
  375.   end;
  376. end;
  377. procedure TSHUDPSocket.SetWaitForTime(Value: Longword);
  378. begin
  379.   if Value <> FWaitForTime then
  380.   begin
  381.     FWaitForTime := Value;
  382.   end;
  383. end;
  384. { TUdpRecvThread }
  385. constructor TUDPRecvThread.Create(AUdpSocket: TSHUDPSocket);
  386. begin
  387.   inherited Create(true);
  388.   FSocket := AUdpSocket;
  389.   FEvent := WSA_INVALID_EVENT;
  390.   InitEvent;
  391. end;
  392. destructor TUDPRecvThread.Destroy;
  393. begin
  394.   if not Terminated then
  395.     Stop;
  396.   FreeEvent;
  397.   inherited Destroy;
  398. end;
  399. procedure TUDPRecvThread.Execute;
  400. var
  401.   dwRc: DWORD;
  402. begin
  403.   while not Terminated do
  404.   begin
  405.     dwRc := WSAWaitForMultipleEvents(
  406.       1,
  407.       @FEvent,
  408.       False,
  409.       FSocket.FWaitForTime,
  410.       False);
  411.     if Terminated then
  412.       Break;
  413.     if (dwRc = WAIT_IO_COMPLETION) or (dwRc = WSA_WAIT_FAILED) then
  414.       Break
  415.     else
  416.     begin
  417.       WSAResetEvent(FEvent);
  418.       if dwRc = WSA_WAIT_TIMEOUT then
  419.       begin
  420.         if Assigned(FSocket.FOnTimeOut) then //设置处理多长时间没有收到数据
  421.           Synchronize(FSocket.FOnTimeOut);
  422.       end
  423.       else if Assigned(FOnDataRecv) then
  424.         Synchronize(FOnDataRecv);
  425.     end;
  426.   end;
  427. end;
  428. procedure TUDPRecvThread.FreeEvent;
  429. begin
  430.   if FEvent <> WSA_INVALID_EVENT then
  431.   begin
  432.     WSACloseEvent(FEvent);
  433.     FEvent := WSA_INVALID_EVENT;
  434.   end;
  435. end;
  436. procedure TUDPRecvThread.InitEvent;
  437. var
  438.   iRc: integer;
  439. begin
  440.   FEvent := WSACreateEvent();
  441.   if FEvent = WSA_INVALID_EVENT then
  442.     raise TUDPException.CreateFmt('创建套接字事件句柄出错..,错误代码是%d',
  443.       [WSAGetLastError()]);
  444.   iRc := WSAEventSelect(FSocket.FSocket, FEvent, FD_READ);
  445.   if iRc = SOCKET_ERROR then
  446.     raise TUDPException.CreateFmt('设置套接字事件句柄出错..,错误代码是%d',
  447.       [WSAGetLastError()]);
  448. end;
  449. procedure TUDPRecvThread.Stop;
  450. begin
  451.   Terminate;
  452.   SetEvent(FEvent);
  453.   WaitFor;
  454. end;
  455. end.