L'envoi et de la réception d'un TMemoryStream à l'aide de IdTCPClient et IdTCPServer

J'ai trouvé Remy Lebeau la démo de chat de IdTCP composants dans XE2 et je voulais jouer avec elle un peu. (Il peut être trouvé ici) je voudrais envoyer une photo à l'aide de ces éléments et de la meilleure approche semble être l'utilisation d'TMemoryStream. Si je envoyer des chaînes, la connexion fonctionne très bien, les cordes sont transmises avec succès, cependant, quand je l'ai changer pour diffuser au lieu de cela, il ne fonctionne pas. Voici le code:

Serveur

procedure TMainForm.IdTCPServerExecute(AContext: TIdContext);
var rcvdMsg: string;
  ms:TMemoryStream;
begin
// This commented code is working, it receives and sends strings.
//  rcvdMsg:=AContext.Connection.IOHandler.ReadLn;
//  LogMessage('<ServerExec> '+rcvdMsg);
//
//  TResponseSync.SendResponse(AContext, rcvdMsg);
  try
    ms:=TMemoryStream.Create;
    AContext.Connection.IOHandler.ReadStream(ms);

    ms.SaveToFile('c:\networked.bmp');
  except
    LogMessage('Failed to receive',clred);
  end;
end;

Client

procedure TfrmMain.Button1Click(Sender: TObject);
var ms: TMemoryStream;
    bmp: TBitmap;
    pic: TPicture;
    s: string;
begin
  // Again, this code is working for sending strings.
  // s:=edMsg.Text;
  // Client.IOHandler.WriteLn(s);
  ms:=TMemoryStream.Create;

  pic:=TPicture.Create;
  pic.LoadFromFile('c:\Back.png');

  bmp:=TBitmap.Create;
  bmp.Width:=pic.Width;
  bmp.Height:=pic.Height;
  bmp.Canvas.Draw(0,0,pic.Graphic);

  bmp.SaveToStream(ms);
  ms.Position:=0;
  Client.IOHandler.Write(ms);
  ms.Free;
end;

Lorsque j'essaie d'envoyer le flux de la part du client, rien observables qui se passe (point d'arrêt dans le OnExecute ne pas le feu). Cependant, lors de la fermeture de programmes(après l'envoi de la MemoryStream), deux choses se produisent:

  • Si le Client est fermé tout d'abord, alors seulement le except partie de traiter (le journal affiche le "pas d'erreur". Cependant, même si je place un point d'arrêt sur la première ligne de l'essai, à l'exception de bloc, de toute façon il a sauté et seul le message d'erreur est affiché).
  • Si le Serveur est fermé tout d'abord, l'IDE ne change pas de retour de debug, le Client ne change pas son état de déconnecté (comme il le fait normalement lorsque le serveur se déconnecte) et après que le Client est fermé ainsi, une erreur de Violation d'Accès de l'application de Serveur s'affiche. Je suppose que cela signifie qu'il y a un thread du Serveur toujours en cours d'exécution et le maintien de la connexion. Mais peu importe combien de temps je le donne, il ne se termine jamais la tâche de la réception de la MemoryStream.

Remarque: Le serveur utilise IdSchedulerOfThreadDefault et IdAntiFreeze, si ce qui compte.

Que je ne trouve pas de source fiable d'aide pour la nouvelle Indy 10 (il semble tout à appliquer pour les plus âgés d'Indy 10, ou même Indy 9), j'espère que vous pouvez me dire quel est le problème. Grâce


- RÉPONSE -

SERVEUR

procedure TMainForm.IdTCPServerExecute(AContext: TIdContext);
var size: integer;
    ms:TMemoryStream;
begin
  try
    ms:=TMemoryStream.Create;
    size:=AContext.Connection.IOHandler.ReadLongInt;
    AContext.Connection.IOHandler.ReadStream(ms, size);

    ms.SaveToFile('c:\networked.bmp');
  except
    LogMessage('Failed to receive',clred);
  end;
end;

CLIENT

procedure TfrmMain.Button1Click(Sender: TObject);
var ms: TMemoryStream;
    bmp: TBitmap;
    pic: TPicture;
begin
  ms:=TMemoryStream.Create;

  pic:=TPicture.Create;
  pic.LoadFromFile('c:\Back.png');

  bmp:=TBitmap.Create;
  bmp.Width:=pic.Width;
  bmp.Height:=pic.Height;
  bmp.Canvas.Draw(0,0,pic.Graphic);

  bmp.SaveToStream(ms);
  ms.Position:=0;
  Client.IOHandler.Write(ms, 0, True);
  ms.Free;
end;
envoyer la taille du flux de la première de sorte que le serveur ne sait exactement combien d'octets il faut lire.

OriginalL'auteur Martin Melka | 2012-08-28