Delphi TIdTCPServer完全断开客户端与服务器的连接
我正在使用Delphi TIdTCPServer完全断开客户端与服务器的连接,delphi,indy,indy10,Delphi,Indy,Indy10,我正在使用TIdTCPServer。我有一个客户端异常断开连接。 我正在尝试断开此客户端的连接,如下所示: //class TClientConnection = class(TIdServerContext) var Clienttodisconnect: TClientConnection; List := Server.Contexts.LockList; try for I := 0 to List.Count - 1 do begin Clienttodisco
TIdTCPServer
。我有一个客户端异常断开连接。
我正在尝试断开此客户端的连接,如下所示:
//class TClientConnection = class(TIdServerContext)
var
Clienttodisconnect: TClientConnection;
List := Server.Contexts.LockList;
try
for I := 0 to List.Count - 1 do
begin
Clienttodisconnect := TClientConnection(List.Items[I]);
if Clienttodisconnect.uuid = idtodiscnnect then
begin
try
Clienttodisconnect.Connection.Disconnect;
except
end;
end;
end;
finally
Server.Contexts.UnlockList;
end;
有时客户机会与服务器断开连接,有时在服务器重新启动之前会卡住
我做错了什么?我只想断开客户端与上下文的连接
下面是服务器OneExecute事件
var
Connection: TClientConnection;
CMD: String;
Cache, OutboundCmds: TStringList;
I: integer;
UConnected : Boolean;
Len: Integer;
begin
sleep(10);
Try
UConnected := AContext.Connection.Connected;
Except
UConnected := False;
End;
If UConnected <> True Then
begin
AContext.Connection.Disconnect;
exit;
end;
Len := AContext.Connection.IOHandler.InputBuffer.Size;
If Len >= 200000 then
begin
AContext.Connection.Disconnect;
exit;
end;
Connection := AContext as TClientConnection;
// check for pending outbound commands...
OutboundCmds := nil;
try
Cache := Connection.OutboundCache.Lock;
try
if Cache.Count > 0 then
begin
OutboundCmds := TStringList.Create;
OutboundCmds.Assign(Cache);
Cache.Clear;
end;
finally
Connection.OutboundCache.Unlock;
end;
if OutboundCmds <> nil then
begin
for I := 0 to OutboundCmds.Count - 1 do
begin
AContext.Connection.IOHandler.Writeln(OutboundCmds.Strings[I],
IndyTextEncoding_UTF8);
end;
Connection.LastSendRecv := Ticks64;
end;
finally
if OutboundCmds <> nil then
begin
for I := 0 to OutboundCmds.Count - 1 do
begin
OutboundCmds.Objects[I].Free;
end;
end;
OutboundCmds.Free;
end;
// check for a pending inbound command...
if AContext.Connection.IOHandler.InputBufferIsEmpty then
begin
AContext.Connection.IOHandler.CheckForDataOnSource(100);
AContext.Connection.IOHandler.CheckForDisconnect;
if AContext.Connection.IOHandler.InputBufferIsEmpty then
begin
if GetElapsedTicks(Connection.LastSendRecv) >= 30000 then
AContext.Connection.Disconnect;
Exit;
end;
end;
.......
........
var
连接:TClientConnection;
CMD:字符串;
缓存,OutboundCmds:TStringList;
I:整数;
u连接:布尔型;
Len:整数;
开始
睡眠(10);
尝试
UConnected:=AContext.Connection.Connected;
除了
u连接:=假;
结束;
如果u连接为True,则
开始
AContext.Connection.Disconnect;
出口
结束;
Len:=AContext.Connection.IOHandler.InputBuffer.Size;
如果Len>=200000,则
开始
AContext.Connection.Disconnect;
出口
结束;
Connection:=AContext作为TClientConnection;
//检查挂起的出站命令。。。
OutboundCmds:=nil;
尝试
缓存:=Connection.OutboundCache.Lock;
尝试
如果Cache.Count>0,则
开始
OutboundCmds:=TStringList.Create;
OutboundCmds.Assign(缓存);
缓存。清除;
结束;
最后
Connection.OutboundCache.Unlock;
结束;
如果OutboundCMD为零,则
开始
对于I:=0到OutboundCmds.Count-1 do
开始
AContext.Connection.IOHandler.Writeln(OutboundCmds.Strings[I],
INDYTEXTENCODE_UTF8);
结束;
Connection.LastSendRecv:=勾选64;
结束;
最后
如果OutboundCMD为零,则
开始
对于I:=0到OutboundCmds.Count-1 do
开始
OutboundCmds.Objects[I].Free;
结束;
结束;
OutboundCmds.Free;
结束;
//检查挂起的入站命令。。。
如果AContext.Connection.IOHandler.InputBufferIsEmpty,则
开始
AContext.Connection.IOHandler.checkforDataSource(100);
AContext.Connection.IOHandler.CheckForDisconnect;
如果AContext.Connection.IOHandler.InputBufferIsEmpty,则
开始
如果GetElapsedTicks(Connection.LastSendRecv)>=30000,则
AContext.Connection.Disconnect;
出口
结束;
结束;
.......
........
我建议做一些类似的事情:
type
TClientConnection = class(TIdServerContext)
public
Cache: TIdThreadSafeStringList;
uuid: string; // or TGuid or whatever you are using...
ForceDisconnect: Boolean; // <-- add this
end;
...
var
List: TList; // or TIdContextList in modern Indy versions
I: Integer;
Client: TClientConnection;
begin
List := Server.Contexts.LockList;
try
for I := 0 to List.Count - 1 do
begin
Client := TClientConnection(TIdContext(List.Items[I]));
if Client.uuid = idtodiscnnect then
begin
Client.ForceDisconnect := True; // <-- don't actually disconnect here, just signal it
Break;
end;
end;
finally
Server.Contexts.UnlockList;
end;
end;
...
procedure TMyForm.ServerConnect(AContext: TIdContext);
begin
(AContext as TClientConnection).LastSendRecv := Ticks64;
AContext.Connection.IOHandler.DefStringEncoding := IndyTextEncoding_UTF8;
AContext.Connection.IOHandler.ReadTimeout := 30000;
end;
procedure TMyForm.ServerExecute(AContext: TIdContext);
var
Client: TClientConnection;
CMD: String;
Cache, OutboundCmds: TStringList;
I: integer;
Len: Integer;
begin
Client := AContext as TClientConnection;
if Client.ForceDisconnect then // <-- do the actual disconnect here
begin
AContext.Connection.Disconnect;
Exit;
end;
Len := AContext.Connection.IOHandler.InputBuffer.Size;
if Len >= 200000 then
begin
AContext.Connection.Disconnect;
Exit;
end;
// check for pending outbound commands...
OutboundCmds := nil;
try
Cache := Connection.OutboundCache.Lock;
try
if Cache.Count > 0 then
begin
OutboundCmds := TStringList.Create;
OutboundCmds.Assign(Cache);
Cache.Clear;
end;
finally
Connection.OutboundCache.Unlock;
end;
if OutboundCmds <> nil then
begin
for I := 0 to OutboundCmds.Count - 1 do
begin
if Client.ForceDisconnect then // <-- and here, for good measure
begin
AContext.Connection.Disconnect;
Exit;
end;
AContext.Connection.IOHandler.WriteLn(OutboundCmds.Strings[I]);
end;
Connection.LastSendRecv := Ticks64;
end;
finally
if OutboundCmds <> nil then
begin
for I := 0 to OutboundCmds.Count - 1 do
begin
OutboundCmds.Objects[I].Free;
end;
end;
OutboundCmds.Free;
end;
// check for a pending inbound command...
if AContext.Connection.IOHandler.InputBufferIsEmpty then
begin
AContext.Connection.IOHandler.CheckForDataOnSource(100);
AContext.Connection.IOHandler.CheckForDisconnect;
if AContext.Connection.IOHandler.InputBufferIsEmpty then
begin
// if the client wants to stay connected, it should
// send a command every so often...
if GetElapsedTicks(Client.LastSendRecv) >= 30000 then
begin
AContext.Connection.Disconnect;
Exit;
end;
end;
end;
CMD := AContext.Connection.IOHandler.ReadLn;
Client.LastSendRecv := Ticks64;
...
end;
类型
TClientConnection=class(TIdServerContext)
公众的
缓存:TIdThreadSafeStringList;
uuid:string;//或者TGuid或者你正在使用的任何东西。。。
ForceDisconnect:Boolean;//idtodisconnect
从何而来?其余的(除了异常进食和找到正确的客户时没有退出循环)似乎都很好。不要让except块裸露!始终记录错误(或在对话框或其他地方显示错误),它可以为您的调试提供重要信息process@Victoriaidtodiconnect
是从客户端发送到服务器的常量参数。我在异常块上进行了一些日志跟踪,在断开异常断开连接的客户端时,它没有引发任何异常。您的OnExecute
处理程序是什么样子的?它的编码方式对TIdTCPServer
进程断开连接的方式有很大影响。无论如何,这个问题中显示的代码并不是断开客户端连接的最安全的方法。最好在OnExecute
事件中处理。使用超时,或标记TClientConnection
,并让OnExecute
查找该标记,以便可以在拥有客户端连接的线程中调用Disconnect()
。有时连接保持停滞我在您的answer@madammar然后使用调试器或日志消息,我试图在备忘录中记录断开连接过程始终执行,客户端的uuid到达,forcedisconnect布尔值设置为True@madammar1)如果不与主UI线程同步,则无法访问工作线程中的UI控件,并且TCP服务器事件在线程中激发。2) 调试OneExecute事件代码,而不是断开连接代码。我在表单中没有任何UI,我还在备忘录中添加了关键部分以记录日志,我会更深入地将服务器运行到调试器中,不会引发任何异常。我认为的第二次检查如果GetElapsedTicks(Client.LastSendRecv)>=30000,则开始执行AContext.Connection.Disconnect;出口结束代码>应替换为forceconnect布尔值?我不确定,但我现在正在测试这个