我正在创建套接字连接,并使用线程使用以下代码通过套接字连续发送数据:
if (FSocketSession.Connected) and (Msg.JSONEvent <> '') then
begin
FSocketSession.Send(TEncoding.UTF8.GetBytes(Msg.JSONEvent))
Msg.Free;
end
else
begin
FSocketSession.Connect;
end;
这是FSocketSession.Send调用:
function TSocketSession.Send(const ADataToSend: TBytes): Integer;
var
Stopwatch: TStopwatch;
SentBytes: Integer;
const
SleepTimeMS = 10;
begin
SiMain.TrackMethod(Self, 'Send');
{$IFDEF USE_SSL}
if FIsSSL then
begin
SiMain.LogInteger('SslState', Ord(FSocket.SslState));
end;
{$ENDIF}
FDataSent := False;
if FSocket.State = wsConnected then
begin
SentBytes := FSocket.Send(@(ADataToSend[Low(ADataToSend)]), Length(ADataToSend));
SiMain.LogInteger('SentBytes', SentBytes);
Stopwatch := TStopwatch.StartNew;
end;
while (FSocket.State = wsConnected) and (not FDataSent) do
begin
FSocket.MessagePump;
Sleep(SleepTimeMS);
if (Stopwatch.ElapsedMilliseconds >= FTimeout) then
begin
FError := CErrorCommTimeout;
break;
end;
end;
Result := FError;
end;
我注意到在某些PC上,套接字只是在一段时间后停止发送数据(通常是在大约1或2分钟后发生),而在其他PC运行时没有任何问题。有没有人在代码中看到可能导致这种情况发生的事情?如果需要,我可以提供更多信息。
答案 0 :(得分:1)
我发现您的代码存在一些问题。
如果JSONEvent
为空,即使Connect()
已经为真,您也会调用Connected
,并且您会泄漏Msg
对象。代码看起来应该更像这样:
if FSocketSession.Connected then
begin
if Msg.JSONEvent <> '' then
FSocketSession.Send(TEncoding.UTF8.GetBytes(Msg.JSONEvent));
Msg.Free;
end
else
begin
FSocketSession.Connect;
end;
现在,在TSocketSession.Send()
内,您应该在循环中调用FSocket.Send()
。 TCP套接字不能保证发送您请求的字节数,它可以返回更少的字节。这就是它返回实际发送的字节数的原因。您需要考虑到这一点:
function TSocketSession.Send(const ADataToSend: TBytes): Integer;
const
SleepTimeMS = 10;
var
Stopwatch: TStopwatch;
SentBytes, BytesToSend: Integer;
PData: PByte;
begin
SiMain.TrackMethod(Self, 'Send');
{$IFDEF USE_SSL}
if FIsSSL then
begin
SiMain.LogInteger('SslState', Ord(FSocket.SslState));
end;
{$ENDIF}
FDataSent := False;
if FSocket.State = wsConnected then
begin
PData := PByte(ADataToSend);
BytesToSend := Length(ADataToSend);
while BytesToSend > 0 do
begin
SentBytes := FSocket.Send(PData, BytesToSend);
SiMain.LogInteger('SentBytes', SentBytes);
if SentBytes <= 0 then
begin
// error handling ...
Result := ...;
Exit;
end;
Inc(PData, SentBytes);
Dec(BytesToSend, SentBytes);
end;
Stopwatch := TStopwatch.StartNew;
end;
while (FSocket.State = wsConnected) and (not FDataSent) do
begin
FSocket.MessagePump;
Sleep(SleepTimeMS);
if (Stopwatch.ElapsedMilliseconds >= FTimeout) then
begin
FError := CErrorCommTimeout;
break;
end;
end;
Result := FError;
end;