Pergunta

Primeira Pergunta:

É o seguinte rotina de uma correta aplicação de um Indy 9 IdTcpServer.OnExecute rotina?

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;

Segundo (na verdade, o mais importante) Pergunta:

Agora há, ocasionalmente, uma violação de acesso (leitura de endereço 000000).Obviamente, na linha:

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

mas de verificar se AContext / Conexão / InputBuffer / IOHandler = nil ANTES, é falso.APÓS a chamada (e depois a exceção foi gerada) o IOHandler é nula.

Estamos usando RAD Studio / Delphi 2007.

Foi útil?

Solução

A única forma de IOHandler pode tornar-se nulo, como você descreve, se outro thread no seu aplicativo chamado Desligar() a ligação enquanto o thread de trabalho ainda estava correndo.

Outras dicas

Bem, o manipulador Onexecute mais simples que tenho é assim. (Desculpe C ++ em vez de Delphi, mas você terá a ideia.

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

O único problema óbvio que posso ver é que você está tentando usar o "tempo" dos dados para determinar quando você tem uma string completa. Este é um verdadeiro não-não com TCP. Você pode ter o primeiro byte de uma corda, ou pode ter várias strings enviadas de uma só vez. Com o TCP, não há garantia de que cada "envio" termine como único "receber" na outra extremidade.

Você precisa "delimitar" sua string de outra maneira. O Readln usa o caractere nova linha como terminador - outra abordagem é prefixar cada pedaço de dados com um campo de comprimento. Você lê o comprimento e lê os dados restantes.

O código funciona assim, mas não acho que seja uma opção limpa:

  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;
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top