NMUDP.pas
上传用户:szzdds
上传日期:2013-09-18
资源大小:293k
文件大小:18k
源码类别:

Delphi控件源码

开发平台:

Delphi

  1. {$IFDEF VER100}
  2. {$DEFINE NMF3}
  3. {$ENDIF}
  4. {$IFDEF VER110}
  5. {$DEFINE NMF3}
  6. {$ENDIF}
  7. {$IFDEF VER120}
  8. {$DEFINE NMF3}
  9. {$ENDIF}
  10. {$IFDEF VER125}
  11. {$DEFINE NMF3}
  12. {$ENDIF}
  13. unit NMUDP;
  14. interface
  15. uses
  16.   Winsock, Classes, Sysutils, WinTypes, Messages, Forms, NMConst;
  17. {$IFDEF VER110}
  18. {$OBJEXPORTALL On}
  19. {$ENDIF}
  20. {$IFDEF VER120}
  21. {$OBJEXPORTALL On}
  22. {$ENDIF}
  23. {$IFDEF VER125}
  24. {$OBJEXPORTALL On}
  25. {$ENDIF}
  26. const
  27.    //  CompName           ='TNMUDP';
  28.    //  Major_Version      ='4';
  29.    //  Minor_Version      ='02';
  30.    //  Date_Version       ='012798';
  31.    { Levels for reporting Status Messages}
  32.   Status_None = 0;
  33.   Status_Informational = 1;
  34.   Status_Basic = 2;
  35.   Status_Routines = 4;
  36.   Status_Debug = 8;
  37.   Status_Trace = 16;
  38.   WM_ASYNCHRONOUSPROCESS = WM_USER + 101; {Message number for asynchronous socket messages}
  39. const {protocol}
  40.   Const_cmd_true = 'TRUE';
  41. type
  42.   UDPSockError = class(Exception);
  43.    {Event Handlers}
  44.   TOnErrorEvent = procedure(Sender: TComponent; errno: word; Errmsg: string) of object;
  45.   TOnStatus = procedure(Sender: TComponent; status: string) of object;
  46.   TOnReceive = procedure(Sender: TComponent; NumberBytes: Integer; FromIP: string; Port: Integer) of object;
  47.   THandlerEvent = procedure(var handled: boolean) of object;
  48.   TBuffInvalid = procedure(var handled: boolean; var Buff: array of char; var Length: Integer) of object;
  49.   TStreamInvalid = procedure(var handled: boolean; Stream: TStream) of object;
  50.   TNMUDP = class(TComponent)
  51.   private
  52.     IBuff: array[0..2048] of char;
  53.     IBuffSize: Integer;
  54.     FRemoteHost: string;
  55.     FRemotePort: Integer;
  56.     FLocalPort: Integer; {Port at server to connect to}
  57.     RemoteAddress, RemoteAddress2: TSockAddr; {Address of remote host}
  58.     FSocketWindow: hwnd;
  59.     Wait_Flag: boolean; {Flag to indicate if synchronous request completed or not}
  60.     RemoteHostS: PHostEnt; {Entity to store remote host linfo from a Hostname request}
  61.     Canceled: boolean; {Flag to indicate request cancelled}
  62.     Succeed: boolean; {Flag for indicating if synchronous request succeded}
  63.     MyWSAData: TWSADATA; {Socket Information}
  64.     FOnStatus: TOnStatus; {} {Event handler on a status change}
  65.     FReportLevel: Integer; {Reporting Level}
  66.     _status: string; {Current status}
  67.     _ProcMsg: boolean; {Flag to supress or enable socket message processing}
  68.     FLastErrorno: Integer; {The last error Encountered}
  69.     FOnErrorEvent: TOnErrorEvent; {} {Event handler for error nitification}
  70.     FOnDataReceived: TOnReceive;
  71.     FOnDataSend: TNotifyEvent;
  72.     FOnInvalidHost: THandlerEvent;
  73.     FOnStreamInvalid: TStreamInvalid;
  74.     FOnBufferInvalid: TBuffInvalid;
  75.     procedure WndProc(var message: TMessage);
  76.     procedure ResolveRemoteHost;
  77.     procedure SetLocalPort(NewLocalPort: Integer);
  78.     procedure ProcessIncomingdata;
  79.   protected
  80.     procedure StatusMessage(Level: byte; value: string);
  81.     function ErrorManager(ignore: word): string;
  82.     function SocketErrorStr(errno: word): string;
  83.     procedure Wait;
  84.   public
  85.     EventHandle: THandle;
  86.     ThisSocket: TSocket; {The socket number of the Powersocket}
  87.     constructor Create(AOwner: TComponent); override;
  88.     destructor Destroy; override;
  89.     procedure Loaded; override;
  90.     procedure Cancel;
  91.     procedure SendStream(DataStream: TStream);
  92.     procedure SendBuffer(Buff: array of char; Length: Integer);
  93.     procedure ReadStream(DataStream: TStream);
  94.     procedure ReadBuffer(var Buff: array of char; var Length: Integer);
  95.   published
  96.     property RemoteHost: string read FRemoteHost write FRemoteHost; {Host Nmae or IP of remote host}
  97.     property RemotePort: Integer read FRemotePort write FRemotePort; {Port of remote host}
  98.     property LocalPort: Integer read FLocalPort write SetLocalPort; {Port of remote host}
  99.     property ReportLevel: Integer read FReportLevel write FReportLevel;
  100.     property OnDataReceived: TOnReceive read FOnDataReceived write FOnDataReceived;
  101.     property OnDataSend: TNotifyEvent read FOnDataSend write FOnDataSend;
  102.     property OnStatus: TOnStatus read FOnStatus write FOnStatus;
  103.     property OnInvalidHost: THandlerEvent read FOnInvalidHost write FOnInvalidHost;
  104.     property OnStreamInvalid: TStreamInvalid read FOnStreamInvalid write FOnStreamInvalid;
  105.     property OnBufferInvalid: TBuffInvalid read FOnBufferInvalid write FOnBufferInvalid;
  106.   end; {_ TNMUDP               = class(TComponent) _}
  107. implementation
  108. procedure WaitforSync(Handle: THandle);
  109. begin
  110.   repeat
  111.     if MsgWaitForMultipleObjects(1, Handle, False,
  112.       INFINITE, QS_ALLINPUT)
  113.       = WAIT_OBJECT_0 + 1
  114.       then Application.ProcessMessages
  115.     else Break;
  116.   until True = False;
  117. end; {_WaitforSync_}
  118. procedure TNMUDP.Cancel;
  119. begin
  120.   StatusMessage(Status_Debug, sPSk_Cons_msg_Cancel); {Status Message}
  121.   Canceled := True; {Set Cancelled to true}
  122.   SetEvent(EventHandle);
  123. end;
  124. constructor TNMUDP.Create(AOwner: TComponent);
  125. begin
  126.   inherited Create(AOwner);
  127.   _ProcMsg := False; {Inhibit Event processing for socket}
  128.    { Initialize memory }
  129.   GetMem(RemoteHostS, MAXGETHOSTSTRUCT); {Initialize memory for host address structure}
  130.   FSocketWindow := AllocateHWnd(WndProc); {Create Window handle to receive message notification}
  131.    { Set Variables }
  132.   FReportLevel := Status_Informational; {Set Default Reporting Level}
  133.   Canceled := False; {Cancelled flag off}
  134.   EventHandle := CreateEvent(nil, True, False, '');
  135.   StatusMessage(Status_Debug, Cons_Msg_Wsk); {Status Message}
  136.   if WSAStartUp($0101, MyWSAData) = 0 then
  137.   try
  138.     ThisSocket := Socket(AF_INET, SOCK_DGRAM, 0); {Get a new socket}
  139.     if ThisSocket = TSocket(INVALID_SOCKET) then
  140.       ErrorManager(WSAEWOULDBLOCK); {If error handle error}
  141.     setsockopt(ThisSocket, SOL_SOCKET, SO_DONTLINGER, Const_cmd_true, 4);
  142.   except
  143.     WSACleanup; {If error Cleanup}
  144.     raise; {Pass exception to calling function}
  145.   end {_ try _}
  146.   else {_ NOT if WSAStartUp($0101, MyWSADATA) = 0 then _}
  147.     ErrorManager(WSAEWOULDBLOCK); {Handle Statrtup error}
  148.   _ProcMsg := True;
  149. end; {_ constructor TNMUDP.Create(AOwner: TComponent); _}
  150. {*******************************************************************************************
  151. Destroy Power Socket
  152. ********************************************************************************************}
  153. destructor TNMUDP.Destroy;
  154. begin
  155.    {cancel; }
  156.   FreeMem(RemoteHostS, MAXGETHOSTSTRUCT); {Free memory for fetching Host Entity}
  157.   DeAllocateHWnd(FSocketWindow); {Release window handle for Winsock messages}
  158.   CloseHandle(EventHandle);
  159.   WSACleanup; {Clean up Winsock}
  160.   inherited Destroy; {Do inherited destroy method}
  161. end; {_ destructor TNMUDP.Destroy; _}
  162. procedure TNMUDP.SetLocalPort(NewLocalPort: Integer);
  163. begin
  164.   if ThisSocket <> 0 then closesocket(ThisSocket);
  165.   WSACleanup;
  166.   if WSAStartUp($0101, MyWSAData) = 0 then
  167.   try
  168.     ThisSocket := Socket(AF_INET, SOCK_DGRAM, 0); {Get a new socket}
  169.     if ThisSocket = TSocket(INVALID_SOCKET) then
  170.       ErrorManager(WSAEWOULDBLOCK); {If error handle error}
  171.   except
  172.     WSACleanup; {If error Cleanup}
  173.     raise; {Pass exception to calling function}
  174.   end {_ try _}
  175.   else {_ NOT if WSAStartUp($0101, MyWSADATA) = 0 then _}
  176.     ErrorManager(WSAEWOULDBLOCK); {Handle Statrtup error}
  177.   FLocalPort := NewLocalPort;
  178.   Loaded;
  179. end; {_ procedure TNMUDP.SetLocalPort(NewLocalPort: integer); _}
  180. procedure TNMUDP.Loaded;
  181. var
  182.   buf: array[0..17] of char;
  183. begin
  184.   if not (csDesigning in ComponentState) then
  185.   begin
  186.     RemoteAddress2.sin_addr.S_addr := Inet_Addr(StrPCopy(buf, '0.0.0.0'));
  187.     RemoteAddress2.sin_family := AF_INET; {Family = Internet address}
  188.     RemoteAddress2.sin_port := htons(FLocalPort); {Set port to given port}
  189.     Wait_Flag := False; {Set flag to wait}
  190.       {Bind Socket to given address}
  191.     Winsock.bind(ThisSocket, RemoteAddress2, SizeOf(RemoteAddress2));
  192.       {Direct reply message to WM_WAITFORRESPONSE handler}
  193.     WSAAsyncselect(ThisSocket, FSocketWindow, WM_ASYNCHRONOUSPROCESS, FD_READ);
  194.   end; {_ if not (csDesigning in ComponentState) then _}
  195. end; {_ procedure TNMUDP.Loaded; _}
  196. {*******************************************************************************************
  197. Resolve IP Address of Remote Host
  198. ********************************************************************************************}
  199. procedure TNMUDP.ResolveRemoteHost;
  200. var
  201.   buf: array[0..127] of char;
  202.   CTry: Integer;
  203.   handled: boolean;
  204. begin
  205.   RemoteAddress.sin_addr.S_addr := Inet_Addr(StrPCopy(buf, FRemoteHost));
  206.   if RemoteAddress.sin_addr.S_addr = SOCKET_ERROR then
  207.       {If given name not an IP address already}
  208.   begin
  209.     CTry := 0;
  210.     repeat
  211.       Wait_Flag := False; {Reset flag indicating wait over}
  212.          {Resolve IP address}
  213.       wsaasyncgethostbyname(FSocketWindow, WM_ASYNCHRONOUSPROCESS, buf, PChar(RemoteHostS), MAXGETHOSTSTRUCT);
  214.       repeat
  215.         Wait;
  216.       until Wait_Flag or Canceled; {Till host name resolved, Timed out or cancelled}
  217.          {Handle errors}
  218.       if Canceled then
  219.         raise UDPSockError.Create(Cons_Msg_Lkp);
  220.       if Succeed = False then
  221.       begin
  222.         if CTry < 1 then
  223.         begin
  224.           CTry := CTry + 1;
  225.           handled := False;
  226.           if Assigned(FOnInvalidHost) then FOnInvalidHost(handled);
  227.           if not handled then UDPSockError.Create(Cons_Msg_Lkp);
  228.         end {_ if CTry < 1 then _}
  229.         else {_ NOT if CTry < 1 then _}  raise UDPSockError.Create(Cons_Msg_Lkp);
  230.       end {_ if Succeed = FALSE then _}
  231.       else {_ NOT if Succeed = FALSE then _}
  232.             {Fill up remote host information with retreived results}
  233.         with RemoteAddress.sin_addr.S_un_b do
  234.         begin
  235.           s_b1 := RemoteHostS.h_addr_list^[0];
  236.           s_b2 := RemoteHostS.h_addr_list^[1];
  237.           s_b3 := RemoteHostS.h_addr_list^[2];
  238.           s_b4 := RemoteHostS.h_addr_list^[3];
  239.         end; {_ with RemoteAddress.sin_addr.S_un_b do _}
  240.     until Succeed = True;
  241.   end; {_ if remoteaddress.sin_addr.S_addr = SOCKET_ERROR then _}
  242. end; {_ procedure TNMUDP.ResolveRemoteHost; _}
  243. procedure TNMUDP.SendStream(DataStream: TStream);
  244. var CTry, i: Integer;
  245.   buf: array[0..2047] of char;
  246.   handled: boolean;
  247. begin
  248.   CTry := 0;
  249.   while DataStream.size = 0 do
  250.     if CTry > 0 then raise Exception.Create(Cons_Msg_InvStrm)
  251.     else {_ NOT if CTry > 0 then raise Exception.create(Cons_Msg_InvStrm) _}
  252.       if not Assigned(FOnStreamInvalid) then raise Exception.Create(Cons_Msg_InvStrm)
  253.       else {_ NOT if not assigned(FOnStreamInvalid) then raise Exception.create(Cons_Msg_InvStrm) _}
  254.       begin
  255.         handled := False;
  256.         FOnStreamInvalid(handled, DataStream);
  257.         if not handled then raise Exception.Create(Cons_Msg_InvStrm)
  258.         else {_ NOT if not Handled then raise Exception.create(Cons_Msg_InvStrm) _}  CTry := CTry + 1;
  259.       end; {_ NOT if not assigned(FOnStreamInvalid) then raise Exception.create(Cons_Msg_InvStrm) _}
  260.   Canceled := False; {Turn Canceled off}
  261.   ResolveRemoteHost; {Resolve the IP address of remote host}
  262.   if RemoteAddress.sin_addr.S_addr = 0 then
  263.     raise UDPSockError.Create(Cons_Err_Addr); {If Resolving failed raise exception}
  264.   StatusMessage(Status_Basic, Cons_Msg_Data); {Inform status}
  265.   RemoteAddress.sin_family := AF_INET; {Make connected true}
  266. {$R-}
  267.   RemoteAddress.sin_port := htons(FRemotePort); {If no proxy get port from Port property}
  268. {$R+}
  269.   i := SizeOf(RemoteAddress); {i := size of remoteaddress structure}
  270.    {Connect to remote host}
  271.   DataStream.position := 0;
  272.   DataStream.ReadBuffer(buf, DataStream.size);
  273.   Winsock.SendTo(ThisSocket, buf, DataStream.size, 0, RemoteAddress, i);
  274.   if Assigned(FOnDataSend) then FOnDataSend(self);
  275. end; {_ procedure TNMUDP.SendStream(DataStream: TStream); _}
  276. procedure TNMUDP.SendBuffer(Buff: array of char; Length: Integer);
  277. var CTry, i: Integer;
  278.   handled: boolean;
  279. begin
  280.   CTry := 0;
  281.   while Length = 0 do
  282.     if CTry > 0 then raise Exception.Create(Cons_Err_Buffer)
  283.     else {_ NOT if CTry > 0 then raise Exception.create(Cons_Err_Buffer) _}
  284.       if not Assigned(FOnBufferInvalid) then raise Exception.Create(Cons_Err_Buffer)
  285.       else {_ NOT if not assigned(FOnBufferInvalid) then raise Exception.create(Cons_Err_Buffer) _}
  286.       begin
  287.         handled := False;
  288.         FOnBufferInvalid(handled, Buff, Length);
  289.         if not handled then raise Exception.Create(Cons_Err_Buffer)
  290.         else {_ NOT if not Handled then raise Exception.create(Cons_Err_Buffer) _}  CTry := CTry + 1;
  291.       end; {_ NOT if not assigned(FOnBufferInvalid) then raise Exception.create(Cons_Err_Buffer) _}
  292.   Canceled := False; {Turn Canceled off}
  293.   ResolveRemoteHost; {Resolve the IP address of remote host}
  294.   if RemoteAddress.sin_addr.S_addr = 0 then
  295.     raise UDPSockError.Create(Cons_Err_Addr); {If Resolving failed raise exception}
  296.   StatusMessage(Status_Basic, Cons_Msg_Data); {Inform status}
  297.   RemoteAddress.sin_family := AF_INET; {Make connected true}
  298. {$R-}
  299.   RemoteAddress.sin_port := htons(FRemotePort); {If no proxy get port from Port property}
  300. {$R+}
  301.   i := SizeOf(RemoteAddress); {i := size of remoteaddress structure}
  302.   Winsock.SendTo(ThisSocket, Buff, Length, 0, RemoteAddress, i);
  303.   if Assigned(FOnDataSend) then FOnDataSend(self);
  304. end; {_ procedure TNMUDP.SendBuffer(Buff: array of char; length: integer); _}
  305. {*******************************************************************************************
  306. Handle Power socket error
  307. ********************************************************************************************}
  308. function TNMUDP.ErrorManager(ignore: word): string;
  309. var
  310.   slasterror: string;
  311. begin
  312.   StatusMessage(Status_Trace, Cons_Msg_Echk); {Report Status}
  313.   FLastErrorno := wsagetlasterror; {Set last error}
  314.   if (FLastErrorno and ignore) <> ignore then
  315.       {If the error is not the error to be ignored}
  316.   begin
  317.     slasterror := SocketErrorStr(FLastErrorno); {Get the description string for error}
  318.     if Assigned(FOnErrorEvent) then
  319.          {If error handler present excecute it}
  320.       FOnErrorEvent(self, FLastErrorno, slasterror);
  321.     raise UDPSockError.Create(slasterror); {Raise exception}
  322.   end; {_ if (FLastErrorno and ignore) <> ignore then _}
  323.   result := slasterror; {return error string}
  324. end; {_ function TNMUDP.ErrorManager(ignore: word): string; _}
  325. {*******************************************************************************************
  326. Return Error Message Corresponding To Error number
  327. ********************************************************************************************}
  328. function TNMUDP.SocketErrorStr(errno: word): string;
  329. begin
  330.   if errno <> 0 then
  331.       {If error exits}
  332.   begin
  333.       (*for x := 0 to 50 do                                {Get error string}
  334.         if winsockmessage[x].errorcode = errno then
  335.           Result := inttostr( winsockmessage[x].errorcode ) + ':' + winsockmessage[x].text; *)
  336.     if result = '' then {If not found say unknown error}
  337.       result := Cons_Msg_Eno + IntToStr(errno);
  338.   end; {_ if ErrNo <> 0 then _}
  339.   StatusMessage(Status_Debug, Cons_Msg_ELkp + result); {Status message}
  340. end; {_ function TNMUDP.SocketErrorStr(ErrNo: word): string; _}
  341. {*******************************************************************************************
  342. Output a Status message: depends on current Reporting Level
  343. ********************************************************************************************}
  344. procedure TNMUDP.StatusMessage(Level: byte; value: string);
  345. begin
  346.   if Level <= FReportLevel then
  347.       {If level of error less than present report level}
  348.   begin
  349.     _status := value; {Set status to vale of error}
  350.     if Assigned(FOnStatus) then
  351.       FOnStatus(self, _status); {If Status handler present excecute it}
  352.   end; {_ if level <= FReportLevel then _}
  353. end; {_ procedure TNMUDP.StatusMessage(Level: byte; value: string); _}
  354. {*******************************************************************************************
  355. Socket Message handler
  356. ********************************************************************************************}
  357. procedure TNMUDP.WndProc(var message: TMessage);
  358. begin
  359.   if _ProcMsg then {If Processing of messages enabled}
  360.     with message do
  361.       if msg = WM_ASYNCHRONOUSPROCESS then
  362.       begin
  363.         if lparamLo = FD_READ then
  364.           ProcessIncomingdata
  365.         else {_ NOT if lparamLo = FD_Read then _}
  366.         begin
  367.           Wait_Flag := True;
  368.           if lparamhi > 0 then
  369.                   {If no error}
  370.             Succeed := False {Succed flag not set}
  371.           else {_ NOT if lparamhi > 0 then _}
  372.             Succeed := True;
  373.         end; {_ NOT if lparamLo = FD_Read then _}
  374.         SetEvent(EventHandle);
  375.       end {_ if msg = WM_ASYNCHRONOUSPROCESS then _}
  376.       else
  377.         result := DefWindowProc(FSocketWindow, msg, wParam, lParam);
  378. end; {_ procedure TNMUDP.WndProc(var message: TMessage); _}
  379. procedure TNMUDP.ProcessIncomingdata;
  380. var
  381.   From: TSockAddr;
  382.   i: Integer;
  383.   s1: string;
  384.   p1: u_short; 
  385. begin
  386.   i := SizeOf(From);
  387.   IBuffSize := Winsock.RecvFrom(ThisSocket, IBuff, 2048, 0, From, i);
  388.   if Assigned(FOnDataReceived) then
  389.   begin
  390.     s1 := Format('%d.%d.%d.%d', [Ord(From.sin_addr.S_un_b.s_b1), Ord(From.sin_addr.S_un_b.s_b2), Ord(From.sin_addr.S_un_b.s_b3), Ord(From.sin_addr.S_un_b.s_b4)]);
  391.     p1 := ntohs(From.sin_port);
  392.     FOnDataReceived(self, IBuffSize, s1, p1);
  393.   end; {_ if assigned(FOnDataReceived) then _}
  394. end; {_ procedure TNMUDP.ProcessIncomingdata; _}
  395. procedure TNMUDP.ReadStream(DataStream: TStream);
  396. begin
  397.   DataStream.WriteBuffer(IBuff, IBuffSize);
  398.   DataStream.position := 0;
  399. end; {_ procedure TNMUDP.ReadStream(DataStream: TStream); _}
  400. procedure TNMUDP.Wait;
  401. begin
  402.   WaitforSync(EventHandle);
  403.   ResetEvent(EventHandle);
  404. end;
  405. procedure TNMUDP.ReadBuffer(var Buff: array of char; var Length: Integer);
  406. begin
  407.   Move(IBuff, Buff, IBuffSize);
  408.   Length := IBuffSize;
  409. end; {_ procedure TNMUDP.ReadBuffer(var Buff: array of char; var length: integer); _}
  410. end.