BufferUDP.pas
上传用户:juxian
上传日期:2013-04-01
资源大小:38k
文件大小:15k
源码类别:

驱动编程

开发平台:

Delphi

  1. unit BufferUDP;
  2. interface
  3. uses
  4.   Windows, SysUtils, Classes, WinSock, syncobjs;
  5. type // Main class
  6.   TUDPDataEvent = procedure(Sender: TObject; const Buffer: Pointer; const RecvSize:Integer; const Peer: string; const Port: Integer) of object;
  7.   TUDPSender = class(TComponent)
  8.   private
  9.     { Private declarations }
  10.     FHandle: TSocket;
  11.     FActive: Boolean;
  12.     FRemoteIP: String;
  13.     FRemoteHost: String;
  14.     FRemotePort: Word;
  15.     CS: TCriticalSection;
  16.     Procedure SetActive(const Value: Boolean);
  17.     Procedure SetRemoteIP(const Value: String);
  18.     Procedure SetRemoteHost(const Value: String);
  19.     Procedure SetRemotePort(const Value: Word);
  20.   protected
  21.     { Protected declarations }
  22.   public
  23.     { Public declarations }
  24.     Class function ResolveHost(const psHost: string; var psIP: string): u_long; virtual;
  25.     Class function ResolveIP(const psIP: string): string; virtual;
  26.     Constructor Create(AOwner: TComponent); override;
  27.     Destructor Destroy; override;
  28.     Procedure Connect;
  29.     Procedure Disconnect;
  30.     Function SendBuf(var Buffer; BufSize: Integer): Integer;
  31.     property Handle: TSocket read FHandle;
  32.   published
  33.     { Published declarations }
  34.     property Active: Boolean read FActive write SetActive default False;
  35.     property RemoteIP: String read FRemoteIP write SetRemoteIP;
  36.     property RemoteHost: String read FRemoteHost write SetRemoteHost;
  37.     property RemotePort: Word read FRemotePort write SetRemotePort;
  38.   end;
  39.   TUDPReceiver = class;
  40.   TUDPReceiverThread = class(TThread)
  41.   protected
  42.     FReceiver: TUDPReceiver;
  43.     FBuffer: Pointer;
  44.     FRecvSize: Integer;
  45.     FPeer: string;
  46.     FPort: Integer;
  47.     FBufSize: Integer;
  48.     procedure SetBufSize(const Value: Integer);
  49.   public
  50.     procedure Execute; override;
  51.     procedure UDPRead;
  52.   published
  53.     Property BufSize: Integer read FBufSize write SetBufSize;
  54.     Property Receiver: TUDPReceiver read FReceiver write FReceiver;
  55.   end;
  56.   TUDPReceiver = class(TComponent)
  57.   private
  58.     { Private declarations }
  59.     FHandle: TSocket;
  60.     FActive: Boolean;
  61.     FPort: Word;
  62.     FBufferSize: Integer;
  63.     FMulticastIP : String;
  64. //    FUDPBuffer: Pointer;
  65.     FOnUDPData: TUDPDataEvent;
  66.     FUDPReceiverThread: TUDPReceiverThread;
  67.     Procedure SetActive(const Value: Boolean);
  68.     Procedure SetPort(const Value: Word);
  69.     Procedure SetBufferSize(const Value: Integer);
  70.     procedure SetMulticastIP(const Value: String);
  71.   protected
  72.     { Protected declarations }
  73.   public
  74.     { Public declarations }
  75.     Class Function BindMulticast(const Socket: TSocket; const IP:String): LongInt; virtual;
  76.     Constructor Create(AOwner: TComponent); override;
  77.     Destructor Destroy; override;
  78.     Procedure Connect;
  79.     Procedure Disconnect;
  80.     procedure DoUDPRead(const Buffer: Pointer; const RecvSize:Integer; const Peer: string; const Port: Integer); virtual;
  81.     property Handle: TSocket read FHandle;
  82.   published
  83.     { Published declarations }
  84.     property Active: Boolean read FActive write SetActive default False;
  85.     property Port: Word read FPort write SetPort;
  86.     property BufferSize: Integer read FBufferSize write SetBufferSize default 65000;
  87.     property OnUDPData: TUDPDataEvent read FOnUDPData write FOnUDPData;
  88.     property MulticastIP: String read FMulticastIP write SetMulticastIP;
  89.   end;
  90. type // exception
  91.   EBufferUDP = Exception;
  92. procedure Register;
  93. resourcestring
  94.   EUDPNOTACTIVE = 'UDP Socket not connected';
  95.   EUDPACTIVED = 'UDP Socket already connected';
  96.   EWSAError = 'Socket Error : %d';
  97.   EUNABLERESOLVEHOST = 'Unable to resolve host: %s';
  98.   EUNABLERESOLVEIP = 'Unable to resolve IP: %s';
  99.   EZEROBYTESEND = '0 bytes were sent.';
  100.   EPACKAGETOOBIG = 'Package Size Too Big: %d';
  101.   ENOREMOTESIDE = 'Remote Host/IP not identified!';
  102.   ESIZEOUTOFBOUNDARY = 'Size value is out of boundary!';
  103.   EWSAENOBUFS        = 'An operation on a socket could not be performed because the system lacked sufficient buffer space or because a queue was full.';
  104.   EWSANOTINITIALISED = 'A successful WSAStartup must occur before using this function.';
  105.   EWSAENETDOWN       = 'The network subsystem has failed.';
  106.   EWSAEFAULT         = 'optval is not in a valid part of the process address space or optlen argument is too small.';
  107.   EWSAEINPROGRESS    = 'A blocking Windows Sockets 1.1 call is in progress, or the service provider is still processing a callback function.';
  108.   EWSAEINVAL         = 'level is not valid, or the information in optval is not valid.';
  109.   EWSAENETRESET      = 'Connection has timed out when SO_KEEPALIVE is set.';
  110.   EWSAENOPROTOOPT    = 'The option is unknown or unsupported for the specified provider.';
  111.   EWSAENOTCONN       = 'Connection has been reset when SO_KEEPALIVE is set.';
  112.   EWSAENOTSOCK       = 'The descriptor is not a socket.';
  113.   EWSAUNKNOW         = 'Unknow socket error.';
  114. implementation
  115. procedure Register;
  116. begin
  117.   RegisterComponents('Samples', [TUDPSender, TUDPReceiver]);
  118. end;
  119. Type
  120.   TIMR = Packed Record
  121.     imr_multiaddr: LongInt;
  122.     imr_interface: LongInt;
  123.   End;
  124. { TUDPSender }
  125. procedure TUDPSender.Connect;
  126. Var
  127.   Faddr: TSockAddrIn;
  128. begin
  129.   CS.Enter;
  130.   try
  131.     If FActive then
  132.       Raise EBufferUDP.CreateRes(@EUDPACTIVED);
  133.     If ((FRemoteHost='') and (FRemoteIP='')) then
  134.       Raise EBufferUDP.CreateRes(@ENOREMOTESIDE);
  135.     If Not (csDesigning in ComponentState) then
  136.     Begin
  137.       FHandle:= WinSock.Socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
  138.       If FHandle = INVALID_SOCKET then
  139.         Raise EBufferUDP.CreateResFmt(@EWSAError, [WSAGetLastError]);
  140.       with faddr do begin
  141.         sin_family := PF_INET;
  142.         sin_port := WinSock.htons(FRemotePort);
  143.     //    sin_addr.s_addr := WinSock.ResolveHost(fsHost, fsPeerAddress);
  144.         if length(FRemoteIP) > 0 then begin
  145.           sin_addr.s_addr := WinSock.inet_addr(PChar(FRemoteIP));
  146.         end;
  147.       end;
  148.       WinSock.connect(FHandle, faddr, Sizeof(faddr));
  149.     End;
  150.     FActive:= True;
  151.   finally
  152.     CS.Leave;
  153.   end;
  154. end;
  155. constructor TUDPSender.Create(AOwner: TComponent);
  156. begin
  157.   inherited;
  158.   CS:= TCriticalSection.Create;
  159.   FActive:= False;
  160.   FHandle := INVALID_SOCKET;
  161. //  FReceiveTimeout := -1;
  162. end;
  163. destructor TUDPSender.Destroy;
  164. begin
  165.   Active:= False;
  166.   CS.Free;
  167.   inherited;
  168. end;
  169. procedure TUDPSender.Disconnect;
  170. Var
  171.   OldHandle: TSocket;
  172. begin
  173.   CS.Enter;
  174.   try
  175.     If FActive then
  176.     Begin
  177.       OldHandle:= FHandle;
  178.       FHandle:= INVALID_SOCKET;
  179.       CloseSocket(OldHandle);
  180.     End;
  181.   finally
  182.     FActive:= False;
  183.     CS.Leave;
  184.   end;
  185. end;
  186. class function TUDPSender.ResolveHost(const psHost: string;
  187.   var psIP: string): u_long;
  188. Var
  189.   pa: PChar;
  190.   sa: TInAddr;
  191.   aHost: PHostEnt;
  192. begin
  193.   psIP := psHost;
  194.   // Sometimes 95 forgets who localhost is
  195.   if CompareText(psHost, 'LOCALHOST') = 0 then
  196.   begin
  197.     sa.S_un_b.s_b1 := #127;
  198.     sa.S_un_b.s_b2 := #0;
  199.     sa.S_un_b.s_b3 := #0;
  200.     sa.S_un_b.s_b4 := #1;
  201.     psIP := '127.0.0.1';
  202.     Result := sa.s_addr;
  203.   end else begin
  204.     // Done if is tranlated (ie There were numbers}
  205.     Result := inet_addr(PChar(psHost));
  206.     // If no translation, see if it resolves}
  207.     if Result = u_long(INADDR_NONE) then begin
  208.       aHost := Winsock.GetHostByName(PChar(psHost));
  209.       if aHost = nil then
  210.       begin
  211.         Result:= 0;
  212.         psIP:= '';
  213.         Exit;
  214.         //Raise EBufferUDP.CreateResFmt(@EUNABLERESOLVEHOST, [psHost]);
  215.       end else
  216.       begin
  217.         pa := aHost^.h_addr_list^;
  218.         sa.S_un_b.s_b1 := pa[0];
  219.         sa.S_un_b.s_b2 := pa[1];
  220.         sa.S_un_b.s_b3 := pa[2];
  221.         sa.S_un_b.s_b4 := pa[3];
  222.         psIP:= String(inet_ntoa(sa));
  223.         //psIP := TInAddrToString(sa);
  224.       end;
  225.       Result := sa.s_addr;
  226.     end;
  227.   end;
  228. end;
  229. class function TUDPSender.ResolveIP(const psIP: string): string;
  230. var
  231.   i: Integer;
  232.   P: PHostEnt;
  233. begin
  234.   result := '';
  235.   if CompareText(psIP, '127.0.0.1') = 0 then
  236.   begin
  237.     result := 'LOCALHOST';
  238.   end else
  239.   begin
  240.     i := Winsock.inet_addr(PChar(psIP));
  241.     P := Winsock.GetHostByAddr(@i, 4, PF_INET);
  242.     If P = nil then
  243.     Begin
  244.       Result:= '';
  245.       Exit;
  246.       // Raise EBufferUDP.CreateResFmt(@EUNABLERESOLVEIP, [psIP]);
  247.       //CheckForSocketError2(SOCKET_ERROR, [WSANO_DATA]);
  248.     End else
  249.     Begin
  250.       result := P.h_name;
  251.     End;
  252.   end;
  253. end;
  254. Function TUDPSender.SendBuf(var Buffer; BufSize: Integer): Integer;
  255. begin
  256.   CS.Enter;
  257.   try
  258.     Result:= 0;
  259.     If BufSize<=0 then
  260.       Exit;
  261.     If Not FActive then
  262.       Raise EBufferUDP.CreateRes(@EUDPNOTACTIVE);
  263.     Result:= Winsock.send(FHandle, Buffer, BufSize, 0);
  264.     If Result<>BufSize then
  265.     Begin
  266.       Case Result of
  267.         0:
  268.           Raise EBufferUDP.CreateRes(@EZEROBYTESEND);
  269.         SOCKET_ERROR:
  270.           If WSAGetLastError = WSAEMSGSIZE then
  271.             Raise EBufferUDP.CreateResFmt(@EPACKAGETOOBIG, [BufSize])
  272.       End;{CASE}
  273.     End;
  274.   finally
  275.     CS.Leave;
  276.   end;
  277. end;
  278. procedure TUDPSender.SetActive(const Value: Boolean);
  279. begin
  280.   If FActive<>Value then
  281.   Begin
  282.     If Value then
  283.       Connect
  284.     Else
  285.       Disconnect;
  286.   End;
  287. end;
  288. procedure TUDPSender.SetRemoteHost(const Value: String);
  289. Var
  290.   IsConnected: Boolean;
  291. begin
  292.   If FRemoteHost<>Value then
  293.   Begin
  294.     IsConnected:= Active;
  295.     Active:= False;
  296.     FRemoteHost:= Value;
  297.     If Not (csDesigning in ComponentState) then
  298.       ResolveHost(FRemoteHost, FRemoteIP);
  299.     // Resovle IP
  300.     Active:= IsConnected;
  301.   End;
  302. end;
  303. procedure TUDPSender.SetRemoteIP(const Value: String);
  304. Var
  305.   IsConnected: Boolean;
  306. begin
  307.   If FRemoteIP<>Value then
  308.   Begin
  309.     IsConnected:= Active;
  310.     Active:= False;
  311.     FRemoteIP:= Value;
  312.     // Resovle Host name
  313.     If Not (csDesigning in ComponentState) then
  314.       FRemoteHost:= ResolveIP(FRemoteIP);
  315.     Active:= IsConnected;
  316.   End;
  317. end;
  318. procedure TUDPSender.SetRemotePort(const Value: Word);
  319. Var
  320.   IsConnected: Boolean;
  321. begin
  322.   If FRemotePort<>Value then
  323.   Begin
  324.     IsConnected:= Active;
  325.     Active:= False;
  326.     FRemotePort:= Value;
  327.     Active:= IsConnected;
  328.   End;
  329. end;
  330. { TUDPReceiver }
  331. class function TUDPReceiver.BindMulticast(const Socket: TSocket;
  332.   const IP: String): LongInt;
  333. Var
  334.   lpMulti: TIMR;
  335. Begin
  336.   lpMulti.imr_multiaddr := inet_addr(PChar(IP));
  337.   lpMulti.imr_interface := 0;
  338.   Result:= SetSockOpt(Socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, @lpMulti, Sizeof(lpMulti));
  339. End;
  340. procedure TUDPReceiver.Connect;
  341. var
  342.   m_addr: TSockAddrIn;
  343. begin
  344.   If FActive then
  345.     Raise EBufferUDP.CreateRes(@EUDPACTIVED);
  346.   If csDesigning in ComponentState then
  347.   Begin
  348.     FActive:= True;
  349.     Exit;
  350.   End;
  351.   // SOCKET
  352.   FHandle := Winsock.Socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
  353.   If FHandle = INVALID_SOCKET then
  354.     Raise EBufferUDP.CreateResFmt(@EWSAError, [WSAGetLastError]);
  355.   // BIND
  356.   With m_addr do begin
  357.     sin_family := PF_INET;
  358.     sin_port := Winsock.htons(FPort);
  359.     sin_addr.s_addr := INADDR_ANY;
  360.   End;
  361.   If WinSock.bind(FHandle, m_addr, Sizeof(m_addr))=SOCKET_ERROR then
  362.     Raise EBufferUDP.CreateResFmt(@EWSAError, [WSAGetLastError]);
  363.   // Bind Multicast
  364.   If FMulticastIP<>'' then
  365.     If BindMulticast(FHandle, FMulticastIP)=SOCKET_ERROR then
  366.       Case WSAGetLastError of
  367.         WSAENOBUFS:        Raise EBufferUDP.CreateRes(@EWSAENOBUFS       );
  368.         WSANOTINITIALISED: Raise EBufferUDP.CreateRes(@EWSANOTINITIALISED);
  369.         WSAENETDOWN:       Raise EBufferUDP.CreateRes(@EWSAENETDOWN      );
  370.         WSAEFAULT:         Raise EBufferUDP.CreateRes(@EWSAEFAULT        );
  371.         WSAEINPROGRESS:    Raise EBufferUDP.CreateRes(@EWSAEINPROGRESS   );
  372.         WSAEINVAL:         Raise EBufferUDP.CreateRes(@EWSAEINVAL        );
  373.         WSAENETRESET:      Raise EBufferUDP.CreateRes(@EWSAENETRESET     );
  374.         WSAENOPROTOOPT:    Raise EBufferUDP.CreateRes(@EWSAENOPROTOOPT   );
  375.         WSAENOTCONN:       Raise EBufferUDP.CreateRes(@EWSAENOTCONN      );
  376.         WSAENOTSOCK:       Raise EBufferUDP.CreateRes(@EWSAENOTSOCK      );
  377.         Else
  378.           Raise EBufferUDP.CreateRes(@EWSAUNKNOW);
  379.       End; {CASE}
  380.   // Thread read
  381.   FUDPReceiverThread := TUDPReceiverThread.Create(True);
  382.   With FUDPReceiverThread do
  383.   Begin
  384.     Receiver:= Self;
  385.     BufSize:= FBufferSize;
  386.     FreeOnTerminate := True;
  387.     Resume;
  388.   End;
  389.   FActive:= True;
  390. end;
  391. constructor TUDPReceiver.Create(AOwner: TComponent);
  392. begin
  393.   inherited;
  394.   FHandle := INVALID_SOCKET;
  395.   FActive:= False;
  396.   FBufferSize:= 65000;
  397.   FMulticastIP:= '';
  398. end;
  399. destructor TUDPReceiver.Destroy;
  400. begin
  401.   Active:= False;
  402.   inherited;
  403. end;
  404. procedure TUDPReceiver.Disconnect;
  405. Var
  406.   OldHandle: TSocket;
  407. begin
  408.   If Not FActive then
  409.     Exit;
  410.   try
  411.     OldHandle:= FHandle;
  412.     FHandle:= INVALID_SOCKET;
  413.     CloseSocket(OldHandle);
  414.   finally
  415.     FActive:= False;
  416.   end;
  417.   If FUDPReceiverThread <> nil then
  418.   Begin
  419.     FUDPReceiverThread.Terminate;
  420.     FUDPReceiverThread.WaitFor;
  421.   End;
  422. end;
  423. procedure TUDPReceiver.DoUDPRead(const Buffer: Pointer; const RecvSize:Integer;
  424.   const Peer: string; const Port: Integer);
  425. begin
  426.   If Assigned(FOnUDPData) then begin
  427.     FOnUDPData(Self, Buffer, RecvSize, Peer, Port);
  428.   End;
  429. end;
  430. procedure TUDPReceiver.SetActive(const Value: Boolean);
  431. begin
  432.   If FActive<>Value then
  433.   Begin
  434.     If Value then
  435.       Connect
  436.     Else
  437.       Disconnect;
  438.   End;
  439. end;
  440. procedure TUDPReceiver.SetBufferSize(const Value: Integer);
  441. begin
  442.   If FBufferSize<>Value then
  443.   Begin
  444.     If ((Value>=1024) and (Value<=65000)) then
  445.       FBufferSize:= Value
  446.     Else
  447.       Raise EBufferUDP.CreateRes(@ESIZEOUTOFBOUNDARY);
  448.   End;
  449. end;
  450. procedure TUDPReceiver.SetMulticastIP(const Value: String);
  451. Var
  452.   IsConnected: Boolean;
  453. begin
  454.   If Value<>FMulticastIP then
  455.   Begin
  456.     IsConnected:= Active;
  457.     Active:= False;
  458.     FMulticastIP:= Value;
  459.     Active:= IsConnected;
  460.   End;
  461. end;
  462. procedure TUDPReceiver.SetPort(const Value: Word);
  463. Var
  464.   IsConnected: Boolean;
  465. begin
  466.   If FPort<>Value then
  467.   Begin
  468.     IsConnected:= Active;
  469.     Active:= False;
  470.     FPort:= Value;
  471.     Active:= IsConnected;
  472.   End;
  473. end;
  474. { TUDPReceiverThread }
  475. procedure TUDPReceiverThread.Execute;
  476. var
  477.   i: Integer;
  478.   addr_remote: TSockAddrin;
  479.   arSize: Integer;
  480. begin
  481.   GetMem(FBuffer, FBufSize);
  482.   arSize:= SizeOf(addr_remote);
  483.   while FReceiver.Active and not Terminated do
  484.   Begin
  485.     i := arSize;
  486.     FRecvSize := Winsock.RecvFrom(FReceiver.Handle, FBuffer^, FBufSize, 0, addr_remote, i);
  487.     If FReceiver.Active and (FRecvSize>0) then
  488.     Begin
  489.       //fsData := Copy(fListener.fsUDPBuffer, 1, iByteCount);
  490.       FPeer := String(inet_ntoa(addr_remote.sin_addr));
  491.       //FPeer := String(TWinshoe.TInAddrToString(addr_remote.sin_addr));
  492.       FPort := Winsock.NToHS(addr_remote.sin_port);
  493.       Synchronize(UDPRead);
  494.     End;
  495.   End;
  496.   FreeMem(FBuffer);
  497. end;
  498. procedure TUDPReceiverThread.SetBufSize(const Value: Integer);
  499. begin
  500.   If FBufSize<> Value then
  501.     FBufSize:= Value;
  502. end;
  503. procedure TUDPReceiverThread.UDPRead;
  504. begin
  505.   FReceiver.DoUDPRead(FBuffer, FRecvSize, FPeer, FPort);
  506. end;
  507. Var
  508.   GWSADATA: TWSADATA;
  509. initialization
  510.   WSAStartup(MakeWord(2, 0), GWSADATA);
  511. finalization
  512.   WSACleanup;
  513. end.