【发布时间】:2017-01-17 05:04:51
【问题描述】:
当我们将自定义属性分配给 TIdTCPServer 上的连接的 Context 时,如何以线程安全的方式访问这些属性(读/写)?示例:
自定义属性:
type
Local_Socket = class(TIdContext)
public
Tunnel_Requested: bool;
Remote_Tunnel: TIdContext;
end;
type
Remote_Socket = class(TIdContext)
public
Local_Tunnel: TIdContext;
end;
分配它们:
procedure TForm1.IdTCPServer1Connect(AContext: TIdContext);
begin
if AContext.Binding.PeerIP = '127.0.0.1' then
begin
Local_Socket(AContext).Tunnel_Requested:= false;
Local_Socket(AContext).Remote_Tunnel:= Nil;
end
else
begin
AssignRemoteTunnel(AContext);
end;
end;
procedure TForm1.AssignRemoteTunnel(AContext: TIdContext);
var
iContext: integer;
List: TIdContextList;
Assigned: bool;
begin
Assigned:= false;
List:= IdTCPServer1.Contexts.LockList;
try
for iContext:= 0 to List.Count - 1 do
begin
if (TIdContext(List[iContext]).Binding.PeerIP = '127.0.0.1') and
(Local_Socket(List[iContext]).Remote_Tunnel = Nil) then
begin
Local_Socket(List[iContext]).Remote_Tunnel:= AContext;
Remote_Socket(AContext).Local_Tunnel:= TIdContext(List[iContext]);
Assigned:= true;
end;
end;
if Assigned = false then
AContext.Connection.Disconnect;
finally
IdTCPServer1.Contexts.UnlockList;
end;
end;
我尝试使用此代码实现的是,如果连接是本地连接 (127.0.0.1),我需要将其重定向到远程连接,这将在下面的代码中请求。远程连接到达服务器后,我分配RemoteTunnel,将local_socket.remote_tunnel 属性与远程连接关联,将remote_socket.local_tunnel 与本地连接关联起来,这样我就可以在隧道之间进行透明通信:
procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
var
Buffer: TIdBytes;
begin
if AContext.Binding.PeerIP = '127.0.0.1' then
begin
if Local_Socket(AContext).Tunnel_Requested = false then
begin
TunnelSocket.Connection.IOHandler.Write(REQ_TUNNEL);
Local_Socket(AContext).Tunnel_Requested:= true;
end;
if (Local_Socket(AContext).Remote_Tunnel <> Nil) and
(Local_Socket(AContext).Remote_Tunnel.Connection.Connected) then
begin
AContext.Connection.IOHandler.CheckForDataOnSource(500);
if not AContext.Connection.IOHandler.InputBufferIsEmpty then
begin
AContext.Connection.IOHandler.InputBuffer.ExtractToBytes(Buffer);
Local_Socket(AContext).Remote_Tunnel.Connection.IOHandler.Write(Buffer);
end;
end;
这里我正在观察我是否分配了一个 remote_tunnel 属性来通过这个 remote_tunnel 发送缓冲区...但是当我阅读这个属性时,也许我正在将它写在 AssignRemoteTunnel 过程中。这样可以吗?
【问题讨论】:
-
线程安全可以通过 TMonitor.Lock - mikejustin.wordpress.com/2010/11/21/… 实现,但真正的问题似乎是类型安全。 ` Local_Socket(AContext).Tunnel_Requested ` - 正确吗?我认为您应该检查
IF AContext IS Local_Socket THEN BEGIN ...或更好地在这里检查WITH AContext AS Local_Socket DO BEGIN Tunnel_Requested:= false; Remote_Tunnel:= Nil; END; -
感谢您的信息。关于 TMonitor.Lock,我正在考虑使用 TIdThreadSafe 类,这样我将所有内容都保留在 Indy 类中。
-
我不精通 Indy...但是为什么您认为您的上下文不是标准的 Indy 课程而是您自己的扩展课程?
-
不确定我是否收到了您的最后一个问题,但我只想使用 Indy 类保持模式,因为我已经在使用 IdTCPServer / IdTCPClient。我会寻找 TMonitor 并尝试更好地理解它。
-
Local_Socket不是 Indy 类,为什么要使用它?为什么您认为您的Local_Socket(AContext).Tunnel_Requested := ...行是正确的并且不会给您 Access Violation ?对我来说,它看起来和Local_Socket(Button1).Tunnel_Requested := ...或Local_Socket(i).Tunnel_Requested := ...一样缺乏证据