我有一个小问题,当连接到服务器 TIdTcpClient 时,在
FConn.IOHandler.ReadLn
的 procedure TReadingThread.Execute;
上生成“连接正常关闭”错误,这种情况不会一直发生,只是一些,如果一次又一次尝试,则不会发生,也不会发生在服务器运行的另一个 VPS 上。但没关系。
我做了一些更改来解决该错误,如果发生错误,它基本上会断开连接,终止线程并重试。我的问题是,我所做的可能会导致一些问题或工作正常吗?在解决的测试中,它失败了 8 次,尝试 9 次后才连接。
我做了什么:
procedure TReadingThread.Execute;
var
Recebeu : String;
begin
while not Terminated do
begin
try
Recebeu := FConn.IOHandler.ReadLn;
except
on E: Exception do
begin
THD.Terminate;
FConn.IOHandler.InputBuffer.Clear;
FConn.Disconnect(False);
if rt <> nil then rt.Terminate;
THD := TThreadCon.Create;
THD.Start;
end;
end;
if not Recebeu.IsEmpty then
begin
总谐波失真为
THD : TThreadCon = nil
procedure TThreadCon.Execute;
var
Attempt : Integer;
begin
Attempt := 0;
try
while not Terminated do
begin
if TCPClient.IOHandler <> nil then TCPClient.IOHandler.InputBuffer.Clear;
try
Inc(Attempt);
TCPClient.Connect;
try
TCPClient.IOHandler.WriteLn('Connect');
except
TCPClient.Disconnect(False);
raise;
end;
except
on E: Exception do
begin
if (Attempt >= 3) then
begin
THD.Terminate;
end;
if FTermEvent.WaitFor(2500) <> wrTimeout then Exit;
Continue;
end;
end;
rt := TReadingThread.Create(TCPClient);
try
try
while not Terminated do
begin
if FTermEvent.WaitFor(5000) <> wrTimeout then Exit;
end;
except
end;
finally
rt.Terminate;
try
TCPClient.Disconnect(False);
finally
rt.WaitFor;
rt.Free;
end;
end;
end;
finally
TCPClient.Free;
end;
end;
正如我所见,由于我在执行时声明并设置尝试,它永远不会在
if (Attempt >= 3) then
上触发 on E: Exception do
,但没关系。
仅当服务器关闭连接时才会发生“连接正常关闭”错误?
“连接正常关闭”意味着连接被远程对等方有意关闭,通常服务器是的,但如果客户端和服务器之间的防火墙/路由器由于不活动等原因关闭了连接,也可能会发生这种情况。
该错误在客户端是正常的,你的解决方案基本正确——关闭连接并重新连接。
尽管如此,我确实质疑为什么你要在单独的线程中调用
Connect()
和 ReadLn()
,为什么不在单个线程中调用呢?有一个调用 Connect()
和 WriteLn()
的外循环,然后是调用 ReadLn()
的内循环,例如:
procedure TThreadCon.Execute;
var
Attempt : Integer;
Recebeu : String;
begin
Attempt := 0;
try
while (not Terminated) and (FTermEvent.WaitFor(0) = wrTimeout) do
begin
if TCPClient.IOHandler <> nil then
TCPClient.IOHandler.InputBuffer.Clear;
try
Inc(Attempt);
TCPClient.Connect;
try
TCPClient.IOHandler.WriteLn('Connect');
except
TCPClient.Disconnect(False);
raise;
end;
except
on E: Exception do
begin
if (Attempt >= 3) then Terminate;
if FTermEvent.WaitFor(2500) = wrSignaled then Exit;
Continue;
end;
end;
try
while (not Terminated) and (FTermEvent.WaitFor(0) = wrTimeout) do
begin
try
Recebeu := TCPClient.IOHandler.ReadLn(LF, 5000);
if (not TCPClient.IOHandler.ReadLnTimedOut) and (Recebeu <> '') then
begin
...
end;
except
on E: Exception do
begin
...
end;
end;
end;
finally
TCPClient.Disconnect(False);
Attempt := 0;
end;
end;
finally
TCPClient.Free;
end;
end;