Entwickler-Ecke

Internet / Netzwerk - [TWinSocket] Stream von mit ClientSocket empfangen


Jakob Schöttl - Do 07.09.06 13:43
Titel: [TWinSocket] Stream von mit ClientSocket empfangen
Hallo,
ich mach grad ein programm, das Dateien über eine Socketverbindung schicken soll.
Genauer gesagt:

Delphi-Quelltext
1:
2:
Image1.Picture.Bitmap.SaveToStream(WinSocketStream);
ServerSocket1.Socket.SendStream(WinSocketStream);


Jetzt soll natürlich ClientSocket1 den Stream empfangen, bloß ich finde nicht die richtige Methode!

Für SendText -> ReceiveText
Für SendBuf -> ReceiveBuf

Für SendStream -> ?

Hoffentlich könnt ihr mir helfen!
Danke schon mal


Narses - Do 07.09.06 14:29

Moin!

user profile iconbokaj hat folgendes geschrieben:
Jetzt soll natürlich ClientSocket1 den Stream empfangen, bloß ich finde nicht die richtige Methode!

Für SendText -> ReceiveText
Für SendBuf -> ReceiveBuf

Für SendStream -> ?

Es gibt keine Stream-Empfangsmethode, weil diese ja nicht wissen kann, wie groß der Datenblock ist, der da empfangen werden soll. ;)

Beim Senden wird intern .SendStream auf wiederholte .SendBuf-Aufrufe runtergebrochen. Fazit: Du mußt die Daten mit .ReceiveBuf annehmen und selbst rausfinden, was davon zu deinem Stream gehört. :D

Daraus folgt: du brauchst ein Protokoll (wie auch immer das aussieht, ist ein anderes Problem). Ein Beispiel, wie man ein Protokoll entwickelt, findest du hier [http://www.delphi-library.de/topic_ProtokollChatTutorial+TServerSocketTClientSocket+v300_54269.html].

cu
Narses

PS: Den WinSocketStream brauchst du nur für blocking-socket-calls, du kannst ruhig "normale" Streams nehmen, wenn du non-blocking arbeitest. ;)


Jakob Schöttl - Do 07.09.06 16:16

Danke Narses, in Sachen Netzwerk ist auf dich immer Verlass!
In meinem Fall brauche ich (glaub ich) gar kein Protokoll, weil der Server immer eine gleichgroße bmp-Datei an den Client schickt.

Wenn aber der Server mit SendStream den Stream schickt, dann kommt beim Client kein OnRead-Ereignis. Wie kann ich also dann ReceivedBuf abfragen?

Liegt es vllt daran, dass beim Server steht

Delphi-Quelltext
1:
2:
3:
ServerSocket1.Socket.SendStream(Stream);
//und nicht
ServerSocket1.Socket.Connections[0].SendStream(Stream);

??


Narses - Do 07.09.06 16:57

Moin!

user profile iconbokaj hat folgendes geschrieben:
In meinem Fall brauche ich (glaub ich) gar kein Protokoll, weil der Server immer eine gleichgroße bmp-Datei an den Client schickt.

Ob du ein Protokoll brauchst oder nicht, mußt du natürlich selbst entscheiden. Wenn du schon vorher weißt, wie groß der Stream ist, den du empfangen willst, dann geht das natürlich auch ohne. Wenn allerdings die Größe variabel ist (oder sich später mal ändert), dann wäre ein Protokoll-Ansatz sicherlich die bessere Wahl.

user profile iconbokaj hat folgendes geschrieben:
Wenn aber der Server mit SendStream den Stream schickt, dann kommt beim Client kein OnRead-Ereignis.

Dann machst du was falsch, es muss ein Ereignis ausgelöst werden (s.u.).

user profile iconbokaj hat folgendes geschrieben:
Liegt es vllt daran, dass beim Server steht

Delphi-Quelltext
1:
2:
3:
ServerSocket1.Socket.SendStream(Stream);
//und nicht
ServerSocket1.Socket.Connections[0].SendStream(Stream);

??

Ja, du mußt an die Connections aus dem Array des Servers senden, da hängen die Clients dran. ;) Alternativ kannst du auch den Socket: TCustomWinSocket-Parameter aus der Ereignisprozedur nehmen, das ist garantiert immer die Richtige Verbindung. Siehe auch FAQ-Beitrag [http://www.delphi-library.de/topic_die+Clients+von+TServerSocket+auseinanderhalten_47183.html].

cu
Narses


Jakob Schöttl - Do 07.09.06 17:15

Narses, vllt siehst du ja sofort, was ich falsch mache: :cry:

Beim Server:
Zuerst lese ich aus der Verbindung, und schicke gleich anschließen den Stream zurück. Beide ShowMessage tauchen auf, und ich klicke ok.

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
procedure TMainForm.ServerSocket1ClientRead(Sender: TObject;
  Socket: TCustomWinSocket);
var Picture: TPicture;
    s: string;
    n: integer;
begin
  Picture := TPicture.Create;
  Stream := TMemoryStream.Create;
  try
    ShowMessage('Client Read');
    s := Socket.ReceiveText;
    if s = 'SendScreenShot' then begin
      MakeScreenShot(Picture.Bitmap);
      //Image1.Picture := Picture; //Funktioniert
      Picture.Bitmap.SaveToStream(Stream);
      //Picture.Bitmap.SaveToFile('c:\win98\profiles\jakob\eigene dateien\snap1.bmp'); //Funktioniert
      ShowMessage('Stream wird verschickt');
      Socket.SendStream(Stream);
    end;
  finally
    Picture.Free;
    //Stream.Free;
  end;
end;

Dann beim Client:
Die ShowMessage taucht nicht auf, und auch bei einem Haltepunkt bleibt er nicht stehen.

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
procedure TMainForm.ClientSocket1Read(Sender: TObject;
  Socket: TCustomWinSocket);
var Stream: TMemoryStream;
begin
  ShowMessage('Read');
  Stream := TMemoryStream.Create;
  try
    showMessage(s);
  finally
    Stream.Free;
  end;
end;


Narses - Do 07.09.06 17:34

Moin!

user profile iconbokaj hat folgendes geschrieben:
Narses, vllt siehst du ja sofort, was ich falsch mache: :cry:

Der Fehler ist vermutlich hier:

Delphi-Quelltext
1:
2:
3:
4:
5:
      Picture.Bitmap.SaveToStream(Stream);
      ShowMessage('Stream wird verschickt');
      Stream.Position := 0; // an den Anfang des Streams, sonst wird nix gesendet. ;)
      Socket.SendStream(Stream);
    end;

Allerdings würde ich da noch andere Dinge ändern:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
procedure TMainForm.ServerSocket1ClientRead(Sender: TObject;
  Socket: TCustomWinSocket);
var
  Bitmap: TBitmap;
  s: string;
  n: integer;
begin
  Bitmap := TBitmap.Create;
  Stream := TMemoryStream.Create;
  try
    ShowMessage('Client Read');
    s := Socket.ReceiveText;
    if (s = 'SendScreenShot'then begin // wer sagt denn, dass hier nur der Text ankommt? s.u.
      MakeScreenShot(Bitmap);
      // Image1.Picture.Bitmap.Assign(Bitmap); // wenn schon, dann so, aber nicht den Zeiger zuweisen!
      Bitmap.SaveToStream(Stream);
      // Bitmap.SaveToFile('c:\win98\profiles\jakob\eigene dateien\snap1.bmp');
      ShowMessage('Stream wird verschickt');
      Stream.Position := 0// an den Anfang des Streams, sonst wird nix gesendet. ;)
      Socket.SendStream(Stream); // der Socket wird Eigentümer des Streams und gibt ihn frei
    end;
  finally
    Bitmap.Free;
    // Stream.Free; // das darfst du auf keinen Fall machen, weil .SendStream Eigentümer wird!
  end;
end;

Wenn ich mir so den Code ansehe, dann machst du einen klassischen Fehler: du verläßt dich auf die Ereignisse als Signalisierung. Das ist allgemein ein Fehler, siehe FAQ-Beitrag [http://www.delphi-library.de/topic_Datenpakete+bei+den+SocketKomponenten+auseinanderhalten_56194.html]. ;)

Und da du Befehle und Daten in deiner Übertragung hast, würde ich dir hiermit GANZ DRINGEND ein Protokoll ans Herz legen. Schau mal in das Tut, im Kapitel 8 wird eine Bitmap übertragen, zusätzlich zum Chatten, das ist genau das, was du hier auch machen willst. ;) Sorry, aber die meisten Probleme laufen einfach immer wieder darauf hinaus, dass ein Protokoll die Lösung ist; nur die Problemstellung variiert leicht... :D

cu
Narses


Jakob Schöttl - Do 07.09.06 17:51

Einarbeiten muss ich mich sowieso, dann mach ichs genau, so wie dus im Tutorial empfiehlst, denn jetzt kommt zwar das Ereignis OnRead beim Client, aber auch eine Exception beim Server: ESocketError, Meldung 'Asynchroner Socket-Fehler'.

Ich dachte es kann nicht so schwer sein, eine Datei übers Netzwerk zu verschicken...
Es gibt da keinen einfachen Befehl, oder so?


Narses - Do 07.09.06 18:00

Moin!

user profile iconbokaj hat folgendes geschrieben:
Ich dachte es kann nicht so schwer sein, eine Datei übers Netzwerk zu verschicken...
Es gibt da keinen einfachen Befehl, oder so?

Wenn ich einen kennen würde, hätte ich dann das Tut geschrieben? :mrgreen:

Aber sagen wir mal so: wenn du einen findest, sag mir bescheid! ;)

cu
Narses


Jakob Schöttl - Do 07.09.06 18:05

OK, Danke trotzdem für deine Hilfe Narses!
Ich schaff das schon :roll: - Vielleicht, wenn ich genügend nerve habe ...


Narses - Mo 09.10.06 21:24

Moin!

Ich habe den Thread bzw. die Frage mal eingedampft in die FAQ [http://www.delphi-library.de/topic_Warum+gibt+es+kein+ReceiveStream+bei+den+Sockets_65367.html] gestellt. ;)

cu
Narses