Почему я получаю AccessViolation в Indy Sockets 9 IdTcpServer ServerExecute? - PullRequest
0 голосов
/ 19 июня 2009

Первый вопрос:

Является ли следующая подпрограмма правильной реализацией подпрограммы Indy 9 IdTcpServer.OnExecute?

procedure TMyConnServer.ServerExecute(AContext: TIdPeerThread);
var
  buffSize: integer;
  str:      string;
begin
  AContext.Connection.ReadFromStack(True, 600, False);
  buffSize := AContext.Connection.InputBuffer.Size;
  if (buffSize > 0) then
    { Extract input buffer as string }
    str := AContext.Connection.ReadString(buffSize);

    { Notify connection object of received data }
    if (AContext.Data <> nil) then
    begin
      TConnectionHandler(AContext.Data).Read(str);
    end;
  end;
end;

Второй (на самом деле более важный) вопрос:

Теперь время от времени происходит нарушение доступа (читай с адреса 000000). Очевидно в строке:

  AContext.Connection.ReadFromStack(True, 600, False);

но проверяется, является ли AContext / Connection / InputBuffer / IOHandler = nil ДО ложным. ПОСЛЕ вызова (и после возникновения исключения) IOHandler равен нулю.

Мы используем RAD Studio / Delphi 2007.

Ответы [ 3 ]

0 голосов
/ 19 июня 2009

Код работает так, но я не думаю, что это чистый вариант:

  if (AContext.Connection.Connected) then
  begin
    try
      AContext.Connection.ReadFromStack(false, 1, false);
    except on E: EAccessViolation do
      // ignore
    end;
  end; 
  buffSize := AContext.Connection.InputBuffer.Size;
0 голосов
/ 19 июня 2009

Единственный способ, которым IOHandler может стать nil, как вы описываете, - это если другой поток в вашем приложении с именем Disconnect () подключается, когда ваш рабочий поток еще работал.

0 голосов
/ 19 июня 2009

Ну, самый простой обработчик onExecute, который у меня есть, выглядит следующим образом. (извините C ++ вместо Delphi, но вы поймете идею.

void __fastcall MyPanel::DoTCPExecute(TIdPeerThread * AThread)
{
  AnsiString text =AThread->Connection->ReadLn();
  // now do something with text
}

Единственная очевидная проблема, которую я вижу, это то, что вы пытаетесь использовать «синхронизацию» данных, чтобы определить, когда у вас есть полная строка. Это настоящее нет-нет с TCP. У вас может быть только первый байт строки, или вы можете отправить сразу несколько строк. С TCP нет гарантии, что каждое «send» закончится как одиночное «receive» на другом конце.

Вам необходимо «разделить» вашу строку другим способом. Readln использует символ новой строки в качестве терминатора - другой подход заключается в добавлении префикса к каждой части данных в поле длины. Вы читаете длину, а затем читаете оставшиеся данные.

...