onlyou13

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

udpHelper.pas

unit udpHelper;

interface

uses
  Classes, Windows, SysUtils, WinSock;

type
  TRecv = procedure(RIP: string; buf: PChar; Bufsize: Integer) of object;
  TRecvExpand = procedure(RIP: string; Port: Integer; buf: PChar; Bufsize: Integer) of object;

  TUdp = class(TThread)
  private
    { Private declarations }
    WSocket: TSocket;
    FActive: Boolean;
    FPort, FSendPort: Integer;
    Addr: TSockAddr;
    FSockAddrIn: TSockAddrIn;
    FOnRecv: TRecv;
    FOnRecvExpand: TRecvExpand;
    Rtl: TRTLCriticalSection;
    procedure SetPort(Value: Integer);
    procedure SetOnRecv(value: TRecv);
    procedure SetOnRecvExpand(value: TRecvExpand);
    function GetCurPort: Integer;
  protected
    procedure Execute; override;
  public
    constructor Create;
    destructor Destroy; override;
    function SendBuf(Host: string; Buf: PAnsiChar; BufSize: Integer; Broadcast: Boolean = false): Integer;
    function GetLocalIP(): string;
  published
    property Port: Integer read FPort write SetPort default 0;
    property SendPort: Integer read FSendPort write FSendPort default 0;
    property OnRecv: TRecv read FOnRecv write SetOnRecv;
    property OnRecvExpand: TRecvExpand read FOnRecvExpand write SetOnRecvExpand;
    property CurPort: Integer read GetCurPort;
  end;

implementation

{ TUdp }

constructor TUdp.Create();
var
  wsadata: Twsadata;
begin
  InitializeCriticalSection(rtl);
  if wsastartup($2, wsadata) <> 0 then
  begin
    raise Exception.Create(SysErrorMessage(GetLastError));
  end
  else
    WSocket := socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
  if WSocket = INVALID_SOCKET then
    raise Exception.Create(SysErrorMessage(GetLastError))
  else
    inherited Create(true);
end;

destructor TUdp.Destroy;
begin
  closesocket(WSocket);
  wsacleanup();
  DeleteCriticalSection(Rtl);
  inherited;
end;

procedure TUdp.Execute;
var
  buf: PChar;
  Len: Integer;
  FDS: TFDSet;
  TimeOut: TimeVal;
begin
  buf := AllocMem(10240);
  TimeOut.tv_sec := 0;
  TimeOut.tv_usec := 10;
  FSockAddrIn.SIn_Port := htons(FPort);
  while not Terminated do
  begin
    EnterCriticalSection(rtl);
    fillchar(FDS, sizeof(FDS), 0);
    FD_SET(WSocket, FDS);
    Len := select(0, @FDS, nil, nil, @TimeOut);
    if Len > 0 then
    begin
      Len := sizeof(FSockAddrIn);
      fillchar(buf[0], 10240, 0);
      Len := recvfrom(WSocket, buf[0], 10240, 0, FSockAddrIn, Len);
      if (Len <> 0) and (Len <> -1) then
      begin
        if Assigned(fonRecv) then
          FOnRecv(inet_ntoa(FSockAddrIn.sin_addr), buf, Len);
        if Assigned(fOnRecvExpand) then
          FOnRecvExpand(inet_ntoa(FSockAddrIn.sin_addr), htons(FSockAddrIn.sin_port), buf, Len);
      end;
    end;
    LeaveCriticalSection(rtl);
    Sleep(10);
  end;
  FreeMem(buf);
  closesocket(WSocket);
end;

function TUdp.GetCurPort: Integer;
begin
  Result := htonl(FSockAddrIn.SIn_Port);
end;

function TUdp.GetLocalIP(): string;
var
  HostEnt: PHostEnt;
  Ip: string;
  addr: PAnsiChar;
  Buffer: array[0..63] of AnsiChar;
  GInitData: TWSADATA;
begin
  Result := '';
  try
    WSAStartup(2, GInitData);
    GetHostName(Buffer, SizeOf(Buffer));
    HostEnt := GetHostByName(Buffer);
    if HostEnt = nil then
      Exit;
    addr := HostEnt^.h_addr_list^;
    Ip := Format('%d.%d.%d.%d', [byte(addr[0]), byte(addr[1]), byte(addr[2]), byte(addr[3])]);
    Result := Ip;
  finally
    WSACleanup;
  end;
end;

function TUdp.SendBuf(Host: string; Buf: PAnsiChar; BufSize: Integer; Broadcast: boolean = false): Integer;
var
  optval: Integer;
begin
  if Broadcast then
  begin
    optval := 1;
    if setsockopt(WSocket, SOL_SOCKET, SO_BROADCAST, PAnsiChar(@optval), sizeof(optval)) = SOCKET_ERROR then
      raise Exception.Create(SysErrorMessage(GetLastError))
    else
    begin
      FSockAddrIn.SIn_Family := AF_INET;
      FSockAddrIn.SIn_Port := htons(FSendPort);
      FSockAddrIn.SIn_Addr.S_addr := INADDR_BROADCAST;
      result := sendto(WSocket, Buf[0], BufSize, 0, FSockAddrIn, sizeof(FSockAddrIn));
    end;
  end
  else
  begin
    FSockAddrIn.SIn_Family := AF_INET;
    FSockAddrIn.SIn_Port := htons(FSendPort);
    FSockAddrIn.SIn_Addr.S_addr := inet_addr(PAnsiChar(Host));
    result := sendto(WSocket, Buf[0], BufSize, 0, FSockAddrIn, sizeof(FSockAddrIn));
  end;
end;

procedure TUdp.SetOnRecv(value: TRecv);
begin
  if @FOnRecv = @value then
    Exit;
  FOnRecv := value;
  addr.sin_family := AF_INET;
  addr.sin_addr.S_addr := INADDR_ANY;
  addr.sin_port := htons(FPort);
  if Bind(WSocket, addr, sizeof(addr)) <> 0 then
    raise Exception.Create(SysErrorMessage(GetLastError));
  Resume;
end;

procedure TUdp.SetOnRecvExpand(value: TRecvExpand);
begin
  if @FOnRecvExpand = @value then
    Exit;
  FOnRecvExpand := value;
  addr.sin_family := AF_INET;
  addr.sin_addr.S_addr := INADDR_ANY;
  addr.sin_port := htons(FPort);
  if Bind(WSocket, addr, sizeof(addr)) <> 0 then
    raise Exception.Create(SysErrorMessage(GetLastError));
  Resume;
end;

procedure TUdp.SetPort(Value: Integer);
begin
  if FPort = Value then
    Exit;
  if FActive then
    Suspend;
  FPort := Value;
end;

end.

使用:

var
  sText: AnsiString;
begin
  sText := AnsiString(Edit1.Text);
  FUdp.SendPort := 9000;
  FUdp.SendBuf('192.168.x.x', PAnsiChar(sText), Length(sText), True);
end;

 

posted on 2020-09-07 22:15  onlyou13  阅读(42)  评论(0编辑  收藏  举报