对TServerSocket实行IP绑定之二(继承方式,只用于演示,除非必要不推荐使用)

来源:互联网 发布:索尼爱立信w980 软件 编辑:程序博客网 时间:2024/04/29 09:19

BDS(Delphi/C++Builder)当中的TServerSocket估计是基于简单应用或者学习的目的考虑,所以直接就绑定了泛地址,而不支持针对性的IP地址绑定,这也就使得一些特殊的环境让人感觉有点不舒服,甚至有点无奈。本文就简单介绍一种“曲线破解”法来解决这个绑定的问题。本示例主要是基于BDS2007的TServerSocket,其它版本请根据实际情况进行调整未必都能实现。

//基于继承

unit Unit3;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ScktComp, StdCtrls;

type
  TForm3
= class(TForm)

    Button1: TButton;
   
procedure FormCreate(Sender: TObject);
   
procedure FormDestroy(Sender: TObject);
   
procedure Button1Click(Sender: TObject);

  private
    ServerSOcket1: TServerSocket;

  public
   
{ Public declarations }
 
end;

  TMyServerSocket
= class(TServerSocket)
    private
      FBindAddr: String;
    protected
     
procedure ServerSocketEvent(Sender: TObject; Socket: TCustomWinSocket;
    SocketEvent: TSocketEvent);
    public
      property Address: String read FBindAddr write FBindAddr;
      constructor Create(AOwner: TComponent); override;
 
end;
var
  Form3: TForm3;

implementation
Uses
  Winsock;

{$R *.dfm}

function IsIP(const AHost:String):Boolean;
var
    iLen
  , I
  , TestDigit
  , DotCount: Integer;
    TestIP:   String;
begin
  Result :
= false;
  TestIP :
= AHost + '.';
  iLen :
= Length(AHost);
 
if(iLen<7) or (iLen>15) then Exit;
  TestDigit :
= 0;
  DotCount :
= 0;
 
for i := 1 to iLen + 1 do
   
begin
     
if(((TestIP[i] < '0') or (TestIP[i] > '9')) and ((TestIP[i] <> '.') or (i = 0))) then Exit;
     
if(TestIP[i] = '.') then
     
begin
        
if (TestDigit > 255) or (TestDigit < 0) then Exit;
        
if(TestIP[i-1] = '.') then Exit;
         TestDigit :
= 0;
         Inc(DotCount);
     
end
     
else
         TestDigit :
= TestDigit * 10 + (ord(TestIP[i]) - 48);
  
end;
  Result :
= DotCount = 4;
end;

function LocalGetHostByName(const AHost:String):String;
var
  WSAData: TWSADATA;
  Host:    PHostEnt;
begin
  Result :
= AHost;
 
if(WSAStartup(MakeWord(1,1), WSAData) <> 0) then Exit;
  try
    Host :
= gethostbyname(PChar(AHost));
    Result :
= IntToStr(Byte(Host^.h_addr_list^[0])) + '.' +
              IntToStr(Byte(Host^.h_addr_list^[
1])) + '.' +
              IntToStr(Byte(Host^.h_addr_list^[
2])) + '.' +
              IntToStr(Byte(Host^.h_addr_list^[
3]));
   
if Not IsIP(Result) then Result:=AHost;
  finally
    WSACleanup;
 
end;
end;

function ResolveHost(const AHost: String): String;
begin
  Result :
= AHost;
 
if AnsiSameText(AHost, 'LOCALHOST') or AnsiSameText(AHost, '(Local)') or AnsiSameText(AHost, '.') then   // this computer
    Result :
= '127.0.0.1'
 
else if Not IsIP(Result) then
    Result :
= LocalGetHostByName(AHost);
end;

constructor TMyServerSocket.Create(AOwner: TComponent);
begin
  Inherited Create(AOwner);
  FServerSocket.OnSocketEvent :
= ServerSocketEvent; //可以进行绑定的事件拦截事件
end;

//拦载LookupState为lsIdle状态,替代为 lsLookupAddress,从而使用自定义的地址替代原来的INADDR_ANY
procedure TMyServerSocket.ServerSocketEvent(Sender: TObject; Socket: TCustomWinSocket;
    SocketEvent: TSocketEvent);
var
  Addr: TSockAddrIn;
  LookupState: TLookupState;
begin
 
case SocketEvent of
    seLookup:
     
begin
       
if Socket.LookupState = lsIdle then
         
begin
           
if FBindAddr <> '' then //Hack Bind Address
             
begin
                Addr :
= Socket.Addr;
                Addr.sin_addr.S_addr :
= inet_addr(PChar(ResolveHost(FBindAddr)));
                LookupState :
= lsLookupAddress;
                move( PChar(@Addr)^,
                      PChar(  Integer(Socket)                         
//首地址 (4字节对齐)
                           
+ sizeof(Pointer)                          //虚函数表
                           
+ sizeof(TSocket)//FSocket: TSocket;       //占4字节
                           
+ sizeof(Pointer)//FConnected: Boolean;     //注意字节对齐,由于后续为4字节,虽只有1字节,但是占4字节
                           
+ sizeof(TStream)//FSendStream: TStream;    //占4字节
                           
+ sizeof(Pointer)//FDropAfterSend: Boolean; //注意字节对齐,由于后续为4字节,虽只有1字节,但是占4字节
                           
+ sizeof(HWnd)//FHandle: HWnd;              //占4字节
                            )^,
                      sizeof(TSockAddrIn));
                move( PChar(@LookupState)^,
                      PChar(  Integer(Socket)
                           
+ sizeof(Pointer)
                           
+ sizeof(TSocket)//FSocket: TSocket;
                           
+ sizeof(Pointer)//FConnected: Boolean;     //注意字节对齐
                           
+ sizeof(TStream)//FSendStream: TStream;
                           
+ sizeof(Pointer)//FDropAfterSend: Boolean; //注意字节对齐
                           
+ sizeof(HWnd)//FHandle: HWnd;
                           
+ sizeof(TSockAddrIn)//FAddr: TSockAddrIn;
                           
+ sizeof(TASyncStyles)//FAsyncStyles: TASyncStyles; //注意字节对齐
                            )^,
                      sizeof(TLookupState));
             
end;

         
end;
     
end;
 
end;
  Event(Socket,SocketEvent);
end;


procedure TForm3.Button1Click(Sender: TObject);
begin
  ServerSocket1.Open;
end;

procedure TForm3.FormCreate(Sender: TObject);
begin
  ServerSocket1 :
= TMyServerSocket.Create(self);
  ServerSocket1.Port :
= 9999;
  TMyServerSocket(ServerSocket1).Address :
= '192.168.10.121';
 
//事件处理过程列表
 
//ServerSocket1.OnAccept := ...

end;

procedure TForm3.FormDestroy(Sender: TObject);
begin
  ServerSocket1.Free;
end;

end.

原创粉丝点击