用indy做数据转发代理服务器的实现?(50分)

  • 主题发起人 主题发起人 netants017
  • 开始时间 开始时间
N

netants017

Unregistered / Unconfirmed
GUEST, unregistred user!
示意图
<---2---- ----4----->
[Server]     [Client 代理服务器 Server] [Client 工作站]
---3----> <----1----

请求工作过程:

客户端[IdTCPClient]--------->[IdTCPServer]代理服务器[IdTCPClient]----------->unix服务器

响应工作过程:

客户端[IdTCPClient]<---------[IdTCPServer]代理服务器[IdTCPClient]<-----------unix服务器

我以前是用ClientSocket与ServerSocket做的,在代理服务器上ClientSocket与ServerSocket的数据交换
还好实现部分代码在后面。
现在我想用IdTCPServer与IdTCPClient来实现有几个问题想请教各位

1、我是否要当每有一个客户请求 在我的代理上都要创建一个相对应与UXIX連接的客户IdTCPClient
2、IdTCPServer与IdTCPClient在代理服器上如何进行数据交换。
3、如果各位手头上有相似功能的CODE 请帖上一点。

多谢!!!!!

procedure TForm1.ServerSocket1ClientConnect(Sender: TObject;
Socket: TCustomWinSocket);
var
i,j: integer;
begin
j:=-1;
for i:=1 to sessions do {查找是否有空白项}
if not session[i-1].Used and not session[i-1].CSocket.active then
begin
j:=i-1; {有,分配它}
session[j].Used:=true; {置为在用}
break;
end
else
if not session[i-1].Used and session[i-1].CSocket.active then
session[i-1].CSocket.active:=false;
if j=-1 then
begin {无,新增一个}
j:=sessions;
inc(sessions);
setlength(session,sessions);
session[j].Used:=true; {置为在用}
session[j].CSocket:=TClientSocket.Create(nil);
session[j].CSocket.OnConnect:=ClientSocket1Connect;
session[j].CSocket.OnDisconnect:=ClientSocket1Disconnect;
session[j].CSocket.OnError:=ClientSocket1Error;
session[j].CSocket.OnRead:=ClientSocket1Read;
session[j].CSocket.OnWrite:=ClientSocket1Write;
session[j].Lookingup:=false;
end;
session[j].SS_Handle:=socket.socketHandle; {保存句柄,实现绑定}
session[j].Request:=false; {无请求}
session[j].client_connected:=true; {客户机已连接}
session[j].remote_connected:=false; {远程未连接}
edit1.text:=inttostr(sessions);
end;
for i:=1 to sessions do {判断是哪一个会话}
if session[i-1].Used and (session[i-1].SS_Handle=socket.sockethandle)
then
begin
//以下是对处工作站发送来的请求进行处理分析
str_request:=socket.ReceiveText;
str_tmp:='';
case strtoint(copy(str_request,1,4)) of
100: str_tmp:='0100'+ycbh+copy(str_request,5,19);
200:
begin
// 分调集离客户的预订单位号
end; // end of case
session[i-1].request_str:=str_tmp; {保存整理后的请求数据}
tmp:=session[i-1].request_str; {存放到临时变量}

if tmp<>'' then {有效的请求}
begin
case strtoint(copy(str_request,1,4)) of
100: memo1.lines.add('查询请求('+inttostr(socket.sockethandle)+'): '+tmp);
200: memo1.lines.add('转帐请求('+inttostr(socket.sockethandle)+'): '+tmp);
end; //end of case
if not session[i-1].remote_connected then {假如远征尚未连接}
begin
session[i-1].Request:=true; {置请求数据就绪标志}
session[i-1].CSocket.host:=yh_ipaddress; {设置远程主机地址}
session[i-1].CSocket.port:=strtoint(yh_port); {设置端口}
session[i-1].CSocket.active:=true; {连接远程主机}
session[i-1].Lookingup:=true; {置标志}
session[i-1].LookupTime:=0; {从0开始计时}
end
else {假如远程已连接,直接发送请求}
session[i-1].CSocket.socket.sendtext(session[i-1].request_str);
end //end of if not session[i-1].remote_connected then
else
memo1.lines.add('客户无效请求('+inttostr(socket.sockethandle)+')'+socket.ReceiveText);
//end of if tmp<>'' then
break; {停止循环}
end;
end;

procedure TForm1.ClientSocket1Read(Sender: TObject;
Socket: TCustomWinSocket);
var
i,j: integer;

rec_text,answer,sql:string;
begin
for i:=1 to sessions do
if (session[i-1].CSocket.tag=socket.SocketHandle) and session[i-1].Used then
begin
// rec_bytes:=socket.ReceiveBuf(rec_buffer,2048); {接收数据}
rec_text:=socket.ReceiveText;
//要对返回的数据进行整理,要对响应代码进行判断。
case strtoint(copy(rec_Text,1,4)) of
100: if copy(rec_text,5,4)='1111' then //为全'1111'时表示正常返回
begin
answer:=copy(rec_text,49,12);
memo1.lines.add('查询正常返回('+inttostr(session[i-1].SS_Handle)+'): '+rec_text);
end
else
begin
answer:='error';
memo1.lines.add('查询失败返回('+inttostr(session[i-1].SS_Handle)+'): '+rec_text);
end;
// end of 100
200: begin
//更新预订单表中的订单状态!!!

//写入日志到数据库

end; //end of 200
else
begin
answer:='error answer';
memo1.lines.add('返回信息格式不对('+inttostr(session[i-1].SS_Handle)+'): '+rec_text);
end;

end;
for j:=1 to serversocket1.Socket.ActiveConnections do
if serversocket1.Socket.Connections[j-1].SocketHandle=session[i-1].SS_Handle then
begin
serversocket1.Socket.Connections[j-1].SendText(answer);
break;
end;
break;
end;
end;
 
上面的叠在一起了,不好意思!!!


procedure TForm1.ServerSocket1ClientRead(Sender: TObject; Socket: TCustomWinSocket);

var
tmp,str_tmp,line,host,str_request,tmp_rdid,bank_rdid,ccuscode,iunitcost,sql: string;
i,j,m,port: integer;
begin
for i:=1 to sessions do {判断是哪一个会话}
if session[i-1].Used and (session[i-1].SS_Handle=socket.sockethandle)
then
begin
//以下是对处工作站发送来的请求进行处理分析
str_request:=socket.ReceiveText;
str_tmp:='';
case strtoint(copy(str_request,1,4)) of
100: str_tmp:='0100'+ycbh+copy(str_request,5,19);
200:
begin
// 分调集离客户的预订单位号
end; // end of case
session[i-1].request_str:=str_tmp; {保存整理后的请求数据}
tmp:=session[i-1].request_str; {存放到临时变量}

if tmp<>'' then {有效的请求}
begin
case strtoint(copy(str_request,1,4)) of
100: memo1.lines.add('查询请求('+inttostr(socket.sockethandle)+'): '+tmp);
200: memo1.lines.add('转帐请求('+inttostr(socket.sockethandle)+'): '+tmp);
end; //end of case
if not session[i-1].remote_connected then {假如远征尚未连接}
begin
session[i-1].Request:=true; {置请求数据就绪标志}
session[i-1].CSocket.host:=yh_ipaddress; {设置远程主机地址}
session[i-1].CSocket.port:=strtoint(yh_port); {设置端口}
session[i-1].CSocket.active:=true; {连接远程主机}
session[i-1].Lookingup:=true; {置标志}
session[i-1].LookupTime:=0; {从0开始计时}
end
else {假如远程已连接,直接发送请求}
session[i-1].CSocket.socket.sendtext(session[i-1].request_str);
end //end of if not session[i-1].remote_connected then
else
memo1.lines.add('客户无效请求('+inttostr(socket.sockethandle)+')'+socket.ReceiveText);
//end of if tmp<>'' then
break; {停止循环}
end;
end;
 
刚才做了一个DEMO,你试试,看能否满足你的要求,程序主要使用了INDY中的TIdMappedPortTcp控件,他可以用来做PROXY,如果你需要对转发中的数据处理
(我看你的程序好象是对数据进行了修改),那么你只需要写少量的代码,以下
代码供你参考,我没有测试运行,不知道能否正常运行,但流程应该是对了,
随手写的.

proxy.dpr
///////////////////////////////////////////
program proxy;

uses
Forms,
main in 'main.pas' {Tcp_Proxy};

{$R *.res}

begin
Application.Initialize;
Application.CreateForm(TTcp_Proxy, Tcp_Proxy);
Application.Run;
end.
//////////////////////////////////
main.dfm
////////////////////////////////
object Tcp_Proxy: TTcp_Proxy
Left = 192
Top = 114
Width = 618
Height = 290
Caption = 'Tcp_Proxy'
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
OldCreateOrder = False
PixelsPerInch = 96
TextHeight = 13
object Panel1: TPanel
Left = 0
Top = 0
Width = 610
Height = 41
Align = alTop
TabOrder = 0
object Proxy_Control: TCheckBox
Left = 416
Top = 13
Width = 97
Height = 17
Caption = '启动PROXY'
TabOrder = 0
OnClick = Proxy_ControlClick
end
object ListenPort: TLabeledEdit
Left = 72
Top = 8
Width = 41
Height = 21
EditLabel.Width = 57
EditLabel.Height = 13
EditLabel.Caption = '侦听端口 '
LabelPosition = lpLeft
TabOrder = 1
end
object Remote_Host: TLabeledEdit
Left = 176
Top = 8
Width = 97
Height = 21
EditLabel.Width = 54
EditLabel.Height = 13
EditLabel.Caption = '远程主机 '
LabelPosition = lpLeft
TabOrder = 2
end
object Remote_Port: TLabeledEdit
Left = 344
Top = 8
Width = 41
Height = 21
EditLabel.Width = 57
EditLabel.Height = 13
EditLabel.Caption = '远程端口 '
LabelPosition = lpLeft
TabOrder = 3
end
end
object ProxyLog: TMemo
Left = 0
Top = 41
Width = 610
Height = 215
Align = alClient
TabOrder = 1
end
object MappedPort_Tcp: TIdMappedPortTCP
Bindings = <>
CommandHandlers = <>
DefaultPort = 0
Greeting.NumericCode = 0
MaxConnectionReply.NumericCode = 0
OnExecute = MappedPort_TcpExecute
ReplyExceptionCode = 0
ReplyTexts = <>
ReplyUnknownCommand.NumericCode = 0
MappedPort = 0
Left = 544
Top = 8
end
end


/////////////////////////////////
main.pas

//////////////////////////////////
unit main;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, StdCtrls, IdBaseComponent, IdComponent, IdTCPServer,
IdMappedPortTCP;

type
TTcp_Proxy = class(TForm)
MappedPort_Tcp: TIdMappedPortTCP;
Panel1: TPanel;
ProxyLog: TMemo;
Proxy_Control: TCheckBox;
ListenPort: TLabeledEdit;
Remote_Host: TLabeledEdit;
Remote_Port: TLabeledEdit;
procedure Proxy_ControlClick(Sender: TObject);
procedure MappedPort_TcpExecute(AThread: TIdMappedPortThread);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Tcp_Proxy: TTcp_Proxy;

implementation

{$R *.dfm}

procedure TTcp_Proxy.Proxy_ControlClick(Sender: TObject);
begin
try
if Proxy_Control.Checked and (not MappedPort_Tcp.Active) then
begin
MappedPort_Tcp.DefaultPort:=strtoint(ListenPort.text);
MappedPort_Tcp.MappedHost:=Remote_Host.Text;
MappedPort_Tcp.MappedPort:=strtoint(Remote_Port.Text);
end;
MappedPort_Tcp.Active:=Proxy_Control.Checked;
except
Proxy_Control.checked:=MappedPort_Tcp.Active;
ProxyLog.Lines.Add('代理服务控制出错')
end;

end;

procedure TTcp_Proxy.MappedPort_TcpExecute(AThread: TIdMappedPortThread);
var
Str_Request,Str_Tmp,ycbh:String;
begin
//这个时候客户端已经连接近来,并且程序也连接到了服务端,MappedPort_Tcp就建立
//了一个线程来转发客户端和服务端的转发,如果要做数据修改就要进行以下操作
ycbh:='0001';
//先判断一下客户端和到服务端的连接是否正常
try
if Athread.Connection.Connected and Athread.OutboundClient.Connected then
begin
// 读取转发中的数据
str_request:=Athread.NetData;
str_tmp:='';
// 判断数据的内容是否合法,并做出相应的修改
case strtoint(copy(str_request,1,4)) of
100: begin
// 重组数据
str_tmp:='0100'+ycbh+copy(str_request,5,19);
// 纪录请求
ProxyLog.Lines.add('查询请求('+inttostr(Athread.Connection.Socket.Binding.Handle)+'): '+str_tmp);
end;
200: begin
str_tmp:='0200'+ycbh+copy(str_request,5,19);
ProxyLog.Lines.add('转帐请求('+inttostr(Athread.Connection.Socket.Binding.Handle)+'): '+str_tmp);
// 分调集离客户的预订单位号
end;
// 来至服务端的返回数据判断
// ... :begin
// end;
else
// 纪录无效的请求
ProxyLog.lines.add('客户无效请求('+inttostr(Athread.Connection.Socket.Binding.Handle)+')'+
Athread.Connection.AllData);
// 如果客户端的数据无效,则断开到服务端的连接
// Athread.OutboundClient.Disconnect;
// 如果服务端的数据无效,则清除发送到客户端的数据
// Athread.NetData:='';
exit;
end; //end of
// 转发合法的数据
// Athread.NetData:=str_temp;
end
else
// 如果该线程中的客户或服务端正常断开,则关闭该线程
Athread.Terminate;
finally
//如果操作发生异常则退出线程,一般发生在客户或服务端异常中断时
Athread.Terminate;
end;
end;

end.
////////////

 
本人用indy(通过SOCKS5)做过,WINclient->UNIT socks5->unixserver
如果需socks5 for sco unix,本人可以提供!

 
to mryzy
如果我这样做是否可行
http://expert.csdn.net/Expert/topic/2267/2267102.xml?temp=.6168634

我要实现的功能与楼主的差不多,我的服务器地址是固定的,clientsocket 与服务器的通讯采用异步方式,只创建一个长连接(这不存在频繁申请释放的问题)。每笔交易都有一个流水号,服务器在收到消息后保存该流水号,并在应答消息中原样返回。程序根据流水号判断是那个Connection发送的消息,然后转发返回信息给工作站。
 对于每条消息都在动态数组中进行记录,
type
session_record=record
used:boolean;
   ss_handle:integer; {serversocket1.socket.connections.sockethandle}  
lxh:integer; {流水号}     
....
不知这样是否可行?
 
后退
顶部