一个机子上有2张网卡,2个IP,用ServerSocket如何绑定其中一个呢

解决方案 »

  1.   

    TServerSocket固定写死了绑定INADDR_ANY,就是本机的所有地址
    要绑定的话要自己改tcp控件或者把ScktComp.pas重新修改编译一遍
      

  2.   

    unit Unit3;interfaceuses
      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;
    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.
      

  3.   

    前面的方法当中注意保存原来的FServerSocket.OnSocketEvent
    unit Unit3;interfaceuses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, ScktComp, StdCtrls;type
      TForm3 = class(TForm)    Button1: TButton;
        ServerSocket1: TServerSocket;
        procedure FormCreate(Sender: TObject);
        procedure Button1Click(Sender: TObject);  private
        FBindAddr: String;
        OldSocketEvent: TSocketEventEvent;
        procedure ServerSocketEvent(Sender: TObject; Socket: TCustomWinSocket;
        SocketEvent: TSocketEvent);
      public
        { Public declarations }
        property Address: String read FBindAddr write FBindAddr;
      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;//拦载LookupState为lsIdle状态,替代为 lsLookupAddress,从而使用自定义的地址替代原来的INADDR_ANY
    procedure TForm3.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;
      OldSocketEvent(Sender,Socket,SocketEvent);
    end;procedure TForm3.Button1Click(Sender: TObject);
    begin
      ServerSocket1.Open;
    end;procedure TForm3.FormCreate(Sender: TObject);
    begin
      ServerSocket1.Port := 9999;
      Address := '192.168.10.121';
      OldSocketEvent := ServerSocket1.Socket.OnSocketEvent;
      ServerSocket1.Socket.OnSocketEvent := ServerSocketEvent;
      if ServerSocket1.Active then
        begin
          ServerSocket1.Close;
          ServerSocket1.Active := False;
        end;
    end;
    end.
      

  4.   

    更正方法(在最后增加Event调用):
    //拦载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;
      

  5.   

    系统有BUG,我也是……
    退出之后再登录就行了