Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Netzwerke (https://www.delphipraxis.net/14-netzwerke/)
-   -   Delphi WinSock: recv()-Puffer wird überschrieben (https://www.delphipraxis.net/75921-winsock-recv-puffer-wird-ueberschrieben.html)

Nogge 27. Aug 2006 12:40


WinSock: recv()-Puffer wird überschrieben
 
Hallo Community!
Ich habe einen Server mithilfe der WinSock programmiert, der Daten von einem Client zum anderen versendet. Jetzt kommt es allerdings oft vor, dass Client 1 10x in der sec. einen string an den server sendet, die recv()-func allerdings nicht sofort ausgeführt wird. Wenn die recv()-func ausgeführt wird, befinden sich ca. 6.3 (von 10) strings in dem Puffer, obwohl ich mithilfe von recv() jeden string einzeln erhalten möchte.
Hier mal der wichtigste Ausschnitt:
Delphi-Quellcode:
  FTimeVal.tv_sec := 0;
  FTimeVal.tv_usec := 1;

  ClientList := TIntegerList.Create;
  try
    while Server.FServerRunning do
    begin
      FD_ZERO(FDSet);    
      FD_SET(Server.AccSock, FDSet);
      for i := 0 to ClientList.Count-1 do
        FD_SET(ClientList[i], FDSet);
      {
        If time-out is a null pointer, select will block indefinitely
        until at least one descriptor meets the specified criteria.
        -------------------------------------------------------------
        -1 = SOCKET_ERROR
         0 = keine Daten vorhanden
      }
      if (select(0, @FDSet, nil, nil, @FTimeVal) > 0) then
      begin
        if not FD_ISSET(Server.AccSock, FDSet) then
        begin
          w := 0;
          count := ClientList.Count;

          while (w < count) do
          begin
            if FD_ISSET(ClientList[w], FDSet) then
            begin
              SetLength(Buffer, MAXLEN);
              BytesRead := recv(ClientList[w], Buffer[1], MAXLEN, 0);
              [...]
Könnt ihr mir sagen, was ich ändern muss, damit ich den Thread jederzeit, wann ich will, mithilfe der Variablen Server.FServerRunning (einfach innerhalb einer Critical Section auf false setzen) beenden kann und doch auf JEDES Datenpaket des Clients reagieren kann?

mfg Nogge

Bernhard Geyer 27. Aug 2006 12:46

Re: WinSock: recv()-Puffer wird überschrieben
 
Du mußt dir eine protokoll definieren in dem du die einzelnen gesendeten Datenpackete auf Clientseite wieder zerlegen kannst. Für ein einfaches Protokoll könntest Du z.B. ein im normalen Datenstrom nicht vorkommendes Zeichen verwenden.

Nogge 27. Aug 2006 12:55

Re: WinSock: recv()-Puffer wird überschrieben
 
Sorry, Bernhard Geyer, aber ich verstehe absolut nicht, was das mit meinem Problem zu tun haben soll.
Normalerweise sollte BytesRead die Länge eines strings (= ein Datenpaket des CLients) haben. Jedoch erreicht BytesRead ständig MAXLEN, da im Puffer von recv() mehr als ein Datenpaket enthalten ist. Der Client sendet seine Datenpakete so schnell, dass der recv()-Puffer zwischen dem ersten Mal Auslesen und dem nächsten erfolgreichen select() mehr als nur ein Datenpaket vom Client enthält.
Sehr schön wäre es z.B., wenn ich select() als blocking call (@FTimeVal = nil) außerhalb des Threads beenden könnte. Ich weiß leider nicht, ob und wenn, wie das geht.

Bernhard Geyer 27. Aug 2006 14:43

Re: WinSock: recv()-Puffer wird überschrieben
 
Also wenn du wirklich einen blockierenden Modus benötigst mußt du:

- Entweder im Client implementieren das erst nach bestätigung vom Server das nächste Packet gesendet wird (Wieder benötigst du die definition eines eigene Protokolls)

- Oder du nimmst komponenten die sowas können wie die Synapse-Komponenten

Soweit ich die mit Delphi gelieferten Socket-Komponeten kenne wirst Du dein gewünschte Verhalten nicht Out-Of-The-Box bekommen.

Muetze1 28. Aug 2006 17:39

Re: WinSock: recv()-Puffer wird überschrieben
 
@Nogge: Du verstehst uns nicht. Die Sockets übertragen die Daten einfach nur. Da wird nix in so grosse Packete gepackt wie du sie sendest und es gibt nirgendwo auch nur ansatzweise irgendein Teil der Sockets, welche dir garantieren die Daten so geteilt wieder zu empfangen wie du sie losgeschickt hast. Wie kommst du also auf die Idee, dass du genauso aufgeteilte Blöcke wieder empfängst? Ganz im Gegenteil: bei einer schlechten Verbindung kann es sogar sehr gut sein, dass du mehrere recv() haben musst um auch nur einen von deinen Blöcken komplett empfangen zu haben.

Deshalb der Hinweis zum Protokoll, hoffentlich nun verständlicher..

Nogge 1. Sep 2006 14:04

Re: WinSock: recv()-Puffer wird überschrieben
 
Ihr hattet recht. Ich habe die recv()-func nicht richtig verstanden. Selbst wenn diese als blocking-call definiert wird (TimeVal := nil), kann der recv()-Puffer mehr als ein Paket von einem Client empfangen haben ;_;
Nun gut, ich werde jetzt den Vorschlag von Bernhard Geyer umsetzen, bei dem der Client erst nach einer Bestätigung des Servers das nächste Paket senden darf. Dazu muss ich aber noch eins wissen: Jeder Socket, sozusagen jeder Client, hat einen eigenen recv()-Puffer, richtig? Es kann also nicht bei mehreren Sockets ein Paket des ersten Clients mit dem Paket des 2. Clients in einem Puffer enthalten bzw. sogar "vermischt" sein?

Muetze1 1. Sep 2006 15:04

Re: WinSock: recv()-Puffer wird überschrieben
 
Nein, nicht bei auf TCP basierenden Dingen.


Alle Zeitangaben in WEZ +1. Es ist jetzt 21:46 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz