TCP套接字停止发送数据(Delphi)

时间:2017-04-06 21:24:29

标签: sockets delphi networking tcp

我正在创建套接字连接,并使用线程使用以下代码通过套接字连续发送数据:

    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运行时没有任何问题。有没有人在代码中看到可能导致这种情况发生的事情?如果需要,我可以提供更多信息。

1 个答案:

答案 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;