我的筆記本電腦連接到TIdTCPServer. 問題是,它連接正常,發送了一個命令,但是當它再次嘗試發送它時,它會收到套接字錯誤 10053 或 10004 或 10054。
其他計算機上的相同代碼可以正常作業,只是在這臺筆記本電腦上會發生此錯誤。
我在執行緒中使用連接,這里是代碼:
type
TThreadCon = class(TThread)
private
TCPClient : TIdTCPClient;
protected
procedure Execute; override;
public
constructor Create;
destructor Destroy; override;
end;
procedure DJWRZORLBS(millisecs: Integer);
var
tick : dword;
AnEvent : THandle;
begin
AnEvent := CreateEvent(nil, False, False, nil);
try
tick := GetTickCount dword(millisecs);
while (millisecs > 0) and (MsgWaitForMultipleObjects(1, AnEvent, False, millisecs, QS_ALLINPUT) <> WAIT_TIMEOUT) do begin
Application.ProcessMessages;
if Application.Terminated then Exit;
millisecs := tick - GetTickcount;
end;
finally
CloseHandle(AnEvent);
end;
end;
constructor TThreadCon.Create;
begin
inherited Create(True);
TCPClient := TIdTCPClient.Create(Nil);
TCPClient.ReadTimeout := 3*60000;
TCPClient.ConnectTimeout := 3*60000;
TCPClient.Port := StrToInt(PortaPS);
TCPClient.Host := Host;
TCPClient.IPVersion := Id_IPv4;
TCPClient.UseNagle := True;
TCPClient.ReuseSocket := rsOSDependent;
end;
procedure TThreadCon.Execute;
begin
while True do
begin
//Sleep(2500);
try
if not TCPClient.Connected then
begin
TCPClient.Connect;
if TCPClient.Connected then
begin
Attempts:= 0;
WriteLn(Format('[%s] Connected to server. [%d]', [TimeToStr(Now), Attempts]));
TCPClient.IOHandler.WriteLn('connect');
if rt = nil then rt := TReadingThread.Create(TCPClient);
end;
end
else
begin
LastPing:= GetTickCount;
try
TCPClient.IOHandler.WriteLn('Ping');
except
on E: Exception do
begin
WriteLn(Format('[%s] Error while trying send ping: %s', [TimeToStr(Now), E.Message]));
end;
end;
WriteLn(Format('[%s] Ping send, Last Ping [%d]', [TimeToStr(Now), GetTickCount-LastPing]));
end;
except
on E: Exception do
begin
Inc(Attempts);
TCPClient.Disconnect(False);
if TCPClient.IOHandler <> nil then TCPClient.IOHandler.InputBuffer.Clear;
WriteLn(Format('[%s] Failed to connect, error: %s [%d]', [TimeToStr(Now), E.Message, Attempts]));
end;
end;
DJWRZORLBS(5000);
end;
end;
下面是發生問題的控制臺日志。它連接到服務器,然后當執行緒再次運行時,它應該發送的位置Ping開始出現問題,并且由于某種原因,在某些情況下,它總是在每個執行緒運行時顯示為已連接,例如TCPClient.Connected未連接。

這是正常作業的計算機上的正常日志:
[21:44:59] Connected to server. [0]
[21:45:04] Ping send, Last Ping [0]
[21:45:09] Ping send, Last Ping [0]
如果我關閉服務器,等待幾秒鐘并重新打開,它顯示如下:
[21:45:54] Failed to connect, error: Socket Error # 10054
Connection reset by peer. [1]
[21:46:01] Failed to connect, error: Socket Error # 10061
Connection refused. [2]
[21:46:08] Failed to connect, error: Socket Error # 10061
Connection refused. [3]
[21:46:14] Connected to server. [0]
[21:46:19] Ping send, Last Ping [0]
對我來說,這就是它應該如何正常作業。
What can cause this? Some problem on the server? But if it is at the server, why do other machines work fine?
Some network setting? If yes, what can I do to solve it?
uj5u.com熱心網友回復:
在內部,Connected執行讀取操作,這在您的情況下不是一件好事,因為如果Connect()成功,您有另一個執行緒同時從同一個套接字讀取。這兩個執行緒將爭奪對套接字的訪問權并將資料放入其IOHandler.InputBuffer.
在任何情況下,如果 中有任何未讀資料,即使底層套接字失敗,也會Connected回傳。TrueInputBuffer
你TThreadCon的結構不是很好。我建議對其進行重組以完全消除使用的需要Connected(并且DJWRZORLBS(),因為TThreadCon沒有需要泵送的訊息佇列)。更好的設計是讓執行緒回圈連接直到成功,然后回圈發送 ping,然后斷開連接,并根據需要重復。
嘗試更多類似的東西:
type
TThreadCon = class(TThread)
private
FTermEvent: TEvent;
protected
procedure Execute; override;
procedure DoTerminate; override;
procedure TerminatedSet; override;
public
constructor Create; reintroduce;
destructor Destroy; override;
end;
constructor TThreadCon.Create;
begin
inherited Create(True);
FTermEvent := TEvent.Create;
end;
destructor TThreadCon.Destroy;
begin
FTermEvent.Free;
inherited;
end;
procedure TThreadCon.TerminatedSet;
begin
FTermEvent.SetEvent;
end;
procedure TThreadCon.Execute;
var
TCPClient: TIdTCPClient;
rt: TReadingThread;
Attempts: Integer;
begin
TCPClient := TIdTCPClient.Create(nil);
try
TCPClient.ReadTimeout := 3*60000;
TCPClient.ConnectTimeout := 3*60000;
TCPClient.Port := StrToInt(PortaPS);
TCPClient.Host := Host;
TCPClient.IPVersion := Id_IPv4;
TCPClient.UseNagle := True;
TCPClient.ReuseSocket := rsOSDependent;
Attempts := 0;
while not Terminated do
begin
if TCPClient.IOHandler <> nil then
TCPClient.IOHandler.InputBuffer.Clear;
try
TCPClient.Connect;
try
TCPClient.IOHandler.WriteLn('connect');
except
TCPClient.Disonnect(False);
raise;
end;
except
on E: Exception do
begin
Inc(Attempts);
WriteLn(Format('[%s] Failed to connect, error: %s [%d]', [TimeToStr(Now), E.Message, Attempts]));
if FTermEvent.WaitFor(2500) <> wrTimeout then Exit;
Continue;
end;
end;
Attempts := 0;
WriteLn(Format('[%s] Connected to server.', [TimeToStr(Now)]));
rt := TReadingThread.Create(TCPClient);
try
try
while not Terminated do
begin
LastPing := GetTickCount;
TCPClient.IOHandler.WriteLn('Ping');
WriteLn(Format('[%s] Ping send, Last Ping [%d]', [TimeToStr(Now), GetTickCount-LastPing]));
if FTermEvent.WaitFor(5000) <> wrTimeout then Exit;
end;
except
on E: Exception do
begin
WriteLn(Format('[%s] Error while trying to send ping: %s', [TimeToStr(Now), E.Message]));
end;
end;
finally
rt.Terminate;
try
TCPClient.Disconnect(False);
finally
rt.WaitFor;
rt.Free;
end;
end;
end;
finally
TCPClient.Free;
end;
end;
procedure TThreadCon.DoTerminate;
begin
if FatalException <> nil then
WriteLn(Format('[%s] Fatal Error: %s', [TimeToStr(Now), Exception(E).Message]));
inherited;
end;
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/453964.html
