cjsh
Delphi、Java学习笔记

我这几天在找这方面的资料,看到了lich的解决方法,就把它贴到富翁笔记与大家分享。
如果技术上有什么问请与lich联系(mastercn@163.com),版权归lich所有。
详细请看:
http://www.delphibbs.com/delphibbs/DispQ.asp?LID=2019869
下面是引用他回答的内容。
-------------------------------------------------
我也没有找到能像SocketClient的能阻塞工作的Socket对象,
只好自己实现代理协议了,我修改了SConnect.pas文件,
加入了免费Socks5代理的支持,主要进行了以下几处修改

将SConnect.pas 复制到程序目录下

1.
在 TSocketConnection 的 published 部分加入
    property Socks5Addr: String read FSocks5Addr write FSocks5Addr;
    property Socks5Port: Integer read FSocks5Port write FSocks5Port;
然后按 Ctrl + Shift + C 进行代码自动完成
2.
在 TSocketTransport 的 public 部分加入
    property SocksAddr: String read FSocksAddr write FSocksAddr;
    property SocksPort: Integer read FSocksPort write FSocksPort;
然后按 Ctrl + Shift + C 进行代码自动完成

3.
在 TSocketConnection.CreateTransport 方法的最后一句代码
  Result := SocketTransport as ITransport;
前面加上:
  SocketTransport.SocksAddr := Socks5Addr;
  SocketTransport.SocksPort := Socks5Port;

4.
修改 TSocketTransport.SetConnected 方法,修改后如下所示:
procedure TSocketTransport.SetConnected(Value: Boolean);
var
  Buff: array[1..500] of Char;
  Len, t: Integer;
  IsFail: Boolean;
  saddr: String;
begin
  if GetConnected = Value then Exit;
  if Value then
  begin
    if (FAddress = '') and (FHost = '') then
      raise ESocketConnectionError.CreateRes(@SNoAddress);
    FClientSocket := TClientSocket.Create(nil);
    FClientSocket.ClientType := ctBlocking;
    FSocket := FClientSocket.Socket;
    if Trim(FSocksAddr) = '' then
    begin
      FClientSocket.Port := FPort;
      if FAddress <> '' then
        FClientSocket.Address := FAddress else
        FClientSocket.Host := FHost;
      FClientSocket.Open;
    end
    else
    begin
      //使用代理服务器的端口进行连接
      FClientSocket.Port := FSocksPort;
      //使用代理服务器的地址进行连接
      FClientSocket.Host := FSocksAddr;
      if FAddress = '' then saddr := FHost else saddr := FAddress;
      FClientSocket.Open;
      //传递协议数据
      if FSocket.Connected then
      begin
        //请求使用不需要验证的Socks5代理
        Buff[1] := #5;
        Buff[2] := #1;
        Buff[3] := #0;
        FSocket.SendBuf(Buff, 3);
        Len := FSocket.ReceiveBuf(Buff, 2);
        IsFail := not ((Len = 2) and (Buff[1] = #5) and (Buff[2] = #0));
        if not IsFail then
        begin
          //发送连接远程主机的命令
          Buff[1] := #5;
          Buff[2] := #1;
          Buff[3] := #0;
          Buff[4] := #3;
          //设置主机名长度
          Buff[5] := Chr(Length(saddr));
          //复制主机名
          Move(saddr[1], Buff[6], Ord(Buff[5]));
          //计算端口的位置
          t := 5 + Ord(Buff[5]) + 1;
          //设置目标端口参数
          Buff[t] := Chr((FPort shr 8) and $ff);
          Buff[t + 1] := Chr(FPort and $ff);
          FSocket.SendBuf(Buff, t + 1);
          Len := FSocket.ReceiveBuf(Buff, 5);
          //验证是否连接成功
          IsFail := not ((Len = 5) and (Buff[1] = #5) and (Buff[2] = #0));
          if not IsFail then
          begin
            if Buff[4] = #1 then
              t := 5
            else
              t := Ord(Buff[5]) + 2;
            Len := FSocket.ReceiveBuf(Buff[6], t);
            IsFail := not (Len = t);
          end;
        end;
        if IsFail then
        begin
          raise Exception.Create('connect via proxy fail.');
        end;
      end;
    end;
  end else
  begin
    FSocket.Close;
    FClientSocket.Free;
    if FEvent <> 0 then WSACloseEvent(FEvent);
  end;
end;

这样,当TSocketConnection.Socks5Addr 不为空时,会自动使用Socks5代理连接
我仅仅实现了免费代理的连接方法,
其他的连接方法请参照Socks的 RFC 文档 rfc1928.txt

http://archive.socks.permeo.com/rfc/rfc1928.txt
http://archive.socks.permeo.com/rfc/rfc1929.txt

如果想索取我修改的源代码,请发信到 mastercn@163.com

---------------------------------------------------
关于发送的Socks5代理协议的数据,
请参照 rfc1928.txt 中的说明

相关中文文档
http://www.vckbase.com/document/listdoc.asp?mclsid=9&sclsid=917
http://www.vckbase.com/document/viewdoc.asp?id=852
或者:
http://hoversoft.net/devinfo/0112doc/25socks5/

posted on 2004-07-29 14:26  cjsh  阅读(1541)  评论(0编辑  收藏  举报