我也没有找到能像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