?? httpproxy.pas
字號:
var
I: Integer;
begin
New(Result);
for I := 0 to SessionCount - 1 do
if SessionRecs[I].csRemoteClient.Socket.SocketHandle = ASocketHandle then
begin
Result := @SessionRecs[I];
Exit;
end;
end;
{
從會話中的客戶端 SocketHandle 獲得相應的客戶端 Socket
}
function TProxy.GetClientFromHandle(const ASocketHandle: Integer): TCustomWinSocket;
var
I: Integer;
begin
Result := nil;
with FProxyServer.Socket do for I := 0 to ActiveConnections do
if Connections[I].SocketHandle = ASocketHandle then
begin
Result := Connections[I];
Exit;
end;
end;
{
遠程客戶端發送數據。
}
procedure TProxy.FRemoteClientWrite(Sender: TObject;
Socket: TCustomWinSocket);
begin
AddMessage('Send message to remote' + IntToStr(Socket.SocketHandle));
with GetSessionRemote(Socket.SocketHandle)^ do
if IsClientRequesting then
begin
csRemoteClient.Socket.SendText(RequestString);
IsClientRequesting := False;
end;
end;
{
功能:根據客戶端的 Socket 獲取相應的會話。
參數:ASocket - 客戶端的 Socket
返回值:對應客戶端 Socket 的會話。
}
function TProxy.GetSessionClient(const ASocket: TCustomWinSocket): PSessionRec;
var
I: Integer;
begin
New(Result);
for I := 0 to SessionCount - 1 do
if SessionRecs[I].ClientSocketHandle = ASocket.SocketHandle then
begin
Result := @SessionRecs[I];
Exit;
end;
end;
{
當客戶端斷開連接時,改變相應的會話的狀態。
}
procedure TProxy.EndSessionClient(const ASocket: TCustomWinSocket);
begin
with GetSessionClient(ASocket)^ do
begin
ClientConnected := False;
if not RemoteConnected then
Used := False
else csRemoteClient.Active := False;
end;
end;
{
客戶端斷開連接
}
procedure TProxy.FProxyServerClientDisconnect(Sender: TObject;
Socket: TCustomWinSocket);
begin
AddMessage('Client disconnected. ' + IntToStr(Socket.SocketHandle));
EndSessionClient(Socket);
end;
procedure TProxy.EndSessionRemote(const ASocket: TCustomWinSocket);
begin
with GetSessionRemote(ASocket.SocketHandle)^ do
begin
RemoteConnected := False;
if not ClientConnected then Used := False
else GetClientFromHandle(ClientSocketHandle).Close;
end;
end;
{
遠程客戶端斷開到目標主機的連接
}
procedure TProxy.FRemoteClientDisconnect(Sender: TObject;
Socket: TCustomWinSocket);
begin
AddMessage('Remote disconnected.' + IntToStr(Socket.SocketHandle));
EndSessionRemote(Socket);
end;
{
遠程客戶端產生錯誤
}
procedure TProxy.FRemoteClientError(Sender: TObject;
Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
var ErrorCode: Integer);
begin
AddMessage('Remote error!' + IntToStr(Socket.SocketHandle));
EndSessionRemote(Socket);
end;
{
顯示消息
}
procedure TProxy.AddMessage(const Msg: String);
begin
FOutPut.Add(Msg);
end;
{
初始化代理服務器
}
constructor TProxy.Create;
procedure InitProxyServer;
begin
with FProxyServer do
begin
OnClientConnect := FProxyServerClientConnect;
OnClientDisconnect := FProxyServerClientDisconnect;
OnClientRead := FProxyServerClientRead;
OnListen := FProxyServerListen;
end;
end;
procedure InitLookupTimer;
begin
with FLookupTimer do
begin
Interval := 200;
Enabled := False;
OnTimer := FLookupTimerTimer;
end;
end;
begin
FPort := 5555;
FProxyServer := TServerSocket.Create(nil);
InitProxyServer;
FLookupTimeLimite := 15000;
FLookupTimeLimited := False;
FLookupTimer := TTimer.Create(nil);
InitLookupTimer;
end;
destructor TProxy.Destroy;
begin
FLookupTimer.Free;
FProxyServer.Free;
inherited;
end;
procedure TProxy.StopServer;
begin
FLookupTimer.Enabled := False;
FProxyServer.Active := False;
end;
procedure TProxy.StartServer;
begin
FProxyServer.Port := FPort;
FProxyServer.Active := True;
end;
procedure TProxy.SetPort(const Value: Integer);
begin
if FProxyServer.Active then
begin
MessageBox(0, '代理服務器在運行時不能改變端口。',
'要改變端口,請先關閉代理服務器', 0);
Exit;
end;
FPort := Value;
end;
procedure TProxy.FLookupTimerTimer(Sender: TObject);
var
I: Integer;
begin
for I := 0 to SessionCount - 1 do with SessionRecs[I] do
begin
if Lookingup then
begin
Inc(LookupTime, FLookupTimer.Interval);
if LookupTime > FLookupTimeLimite then // 連接超時,斷開連接
begin
csRemoteClient.Active := False;
// GetClientFromHandle(ClientSocketHandle).Close;
end;
end;
end;
end;
procedure TProxy.FProxyServerListen(Sender: TObject;
Socket: TCustomWinSocket);
begin
if FLookupTimeLimited and not FLookupTimer.Enabled then
FLookupTimer.Enabled := True;
end;
procedure TProxy.SetLookupTimeLimit(const Value: Integer);
begin
FLookupTimeLimite := Value;
end;
procedure TProxy.SetLookupTimeLimited(const Value: Boolean);
begin
FLookupTimeLimited := Value;
if not FLookupTimeLimited then
FLookupTimer.Enabled := False
else if not FLookupTimer.Enabled then FLookupTimer.Enabled := True;
end;
{
History:
2003-05-12(0.01): 能通過該服務器連接到 www.google.com,但是連接到 www.delphibbs.com
等網站時出錯。
2003-05-12(0.02): 基本功能可以實現了(后來發現在遠程客戶端斷開連接時沒有
相應的斷開客戶端的連接,造成很多網站不能訪問。)
2003-05-13(0.03): 從原來的代碼中提取出 TProxy 類。放在另外一個單元中
Proxy003. 由于無法連接到網上,不能測試代理服務器。在內部的郵件服務器,
上面測試成功。到此為止,代理的最基本功能具備。
2003-05-13(0.04): 增加連接時間控制,在 TSessionRec 中增加 FLookupTime,
在 TProxy 中增加計時器 FLookupTimer,和時間限制 FLookupTimeLimite,
FLookupTimeLimited 并寫相應的事件處理。
2003-05-13(0.05): 準備加入客戶端訪問控制,根據客戶端的 IP ,決定是否有權
使用服務器。
Problems:
2003-05-12(0.02): [連接] 連接的斷開處理疑問。比如客戶端斷開連接時,不知
道是否該將遠程客戶端卻斷開,反過來也不知道是否合理。還有就是未確定
什么時候可以將該會話重新分配。
2003-05-12(0.02): [資源釋放] 遠程客戶端對象總是沒有釋放。
Solutions:
2003-05-12(0.02): [連接] 客戶端斷開連接,檢查遠程客戶端是否連接著,是
則斷開連接,否則可以將該會話重新分配;反過來也這樣。結果是可以打開
www.playicq.com,不過在 index.php 時 AV. 后來發現是在某個地方總在使用
SessionRecs[0],而沒有首先查找對應的會話。問題解決。
2003-05-13(0.03): [連接] 果然,把連接的問題解決了之后,就能比較正常
的工作。
2003-05-12(0.03): [資源釋放] 在創建遠程客戶端對象時,如果已經賦過值則
先釋放掉。
}
end.
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -