ins Netzwerk senden mit Threads

Für allgemeine Fragen zur Programmierung mit PureBasic.
Sven
Beiträge: 374
Registriert: 23.09.2004 12:01

Re: ins Netzwerk senden mit Threads

Beitrag von Sven »

Verständnisproblem?

Wie kommst Du auf die Idee, SendNetworkString() würde nur einen Teil des Strings senden und Du müsstest die Anzahl der Zeichen aufaddieren? Und dann schickst Du den gleichen String nochmal? Addierst aber die Zeichen auf?

SendNetworkString() schickt natürlich den kompletten String, der bei TCP 2^16-1 Zeichen enthalten darf. Da mußt Du nicht auf Länge prüfen, nur auf -1 für Fehler, wenn inzwischen die Verbindung abgebrochen ist. Und Dein Delay(20) macht da auch nichts besser.

Du kannst das einfach ins normale Programm packen, für die verschiedenen Clients legst Du eine LinkedList an, der Du die Clients zufügst. Die LinkedList erstellst Du mit einer Structure, die die Client-IDs und den Text oder einen Pointer auf den Text enthält, sowie bei langem Text > 2^16 Zeichen die Info, welcher Teil schon geschrieben wurde. Dann gehst Du durch die LinkedList durch und schickst den Text raus, ohne Warten. Ist der Text größer als 2^16 Zeichen, schickt der Client eine Erfolgsmeldung, die in der LinkedList gespeichert wird, und erst nach der Erfolgsmeldung wird der nächste Teil für diesen Client geschickt, in der Zwischenzeit können aber alle anderen Clients bedient werden.

Ich mach sowas ähnliches grad, um mehrere Clients mit spezifischen Daten zu versorgen. Durch die LinkedList kann man beliebig Clients aufnehmen und wieder schließen.
Benutzeravatar
Sicro
Beiträge: 963
Registriert: 11.08.2005 19:08
Kontaktdaten:

Re: ins Netzwerk senden mit Threads

Beitrag von Sicro »

stevie1401 hat geschrieben:Noch schöner wäre natürlich, wenn ich den langsamen Clients die Strings "nachreichen" könnte
Du könntest eine Strings-Abarbeitungsliste statt einer schlichten String-Variable verwenden:

Code: Alles auswählen

Structure SpielerStruc
  ClientID.i
  List StringsList.s()
EndStructure
Neue Strings fügst du der StringsList hinzu.
Beim Senden sendest du immer das erste Element der Liste ( FirstElement() ). Wurde der String vollständig gesendet, löscht du das erste Element der Liste, wodurch das zweite das erste Element wird usw., bis du die Liste durch hast.

Code: Alles auswählen

; Erstes Element löschen und zweites Element als aktuelles Element setzten
DeleteElement(Liste(), 1)
Die Fragen sind zwar nicht an mich gerichtet ...
Sven hat geschrieben:Wie kommst Du auf die Idee, SendNetworkString() würde nur einen Teil des Strings senden [...] SendNetworkString() schickt natürlich den kompletten String, der bei TCP 2^16-1 Zeichen enthalten darf. Da mußt Du nicht auf Länge prüfen
Es wird nicht immer der komplette String gesendet - auch 2^16-1 Zeichen sind nicht garantiert. Wenn beim Empfänger der Empfangsbuffer fast voll ist, kann bereits nach einem Zeichen schon Schluss sein. Empfangsbuffer: https://de.wikipedia.org/wiki/TCP_Receive_Window
In seinen anderen Threads geht auch hervor, dass er nicht nur Text als Strings senden möchte, sondern auch Binärdaten (Bilder) kodiert per Base64 - was die Binärdaten besonders aufbläht -, wird der Empfangsbuffer sicherlich oft voll sein.
Sven hat geschrieben:Und dann schickst Du den gleichen String nochmal?
Ja, das ist noch nicht korrekt, habe ich übersehen.
So könnte man es bei ASCII-Format machen:

Code: Alles auswählen

gesendet=SendNetworkString(*Client\ClientID, Mid(*Client\String, sentBytes+1), #PB_Ascii)
Bei UTF8 oder Unicode sollte man lieber per SendNetworkData() senden, da man dort die Startposition in Bytes angeben kann.
Bild
Warum OpenSource eine Lizenz haben sollte :: PB-CodeArchiv-Rebirth :: Pleasant-Dark (Syntax-Farbschema) :: RegEx-Engine (kompiliert RegExes zu NFA/DFA)
Manjaro Xfce x64 (Hauptsystem) :: Windows 10 Home (VirtualBox) :: Neueste PureBasic-Version
stevie1401
Beiträge: 700
Registriert: 19.10.2014 15:51
Kontaktdaten:

Re: ins Netzwerk senden mit Threads

Beitrag von stevie1401 »

Erst einmal vielen Dank für eure Hilfen.
Ich bleibe bei TCP, weil ich so einigermaßen sicherstellen kann, was angekommen ist und was nicht.
@auser
Ich habe mir die ThreadNummern mal angesehen. Bei mir werden die immer (wirklich immer) um 1 erhöht, wenn ich x=CreateThread() mache. Wie kann es da passieren, dass 2x die selbe Nr vergeben wird?

Mit dem Nachreichen von Strings an die Clients ist das so eine Sache.
Es handelt sich ja um einen Doppelkopf-Server.
Was nützt es Spieler Willi, wenn er nach 3 Minuten erfährt, dass irgendwer eine bestimmt Karte gelegt hat. Da kann der Stich schon lange weg sein. Das macht wenig Sinn.
Zumal es am Spieltisch einen "Refresh"-Button gibt, den man drücken kann, wenn man meint, nicht alle Infos bekommen zu haben (z.B. ob ein Spielpartner schon seine Karte gelegt hat.) Dann sendet der Server alle relevaten Infos des Spieles dem Spieler.

Erst mal vielen Dank an alle.
Ich programmiere nur noch mit Linux.
Linux Mint 21.x
auser
Beiträge: 58
Registriert: 17.05.2011 10:56

Re: ins Netzwerk senden mit Threads

Beitrag von auser »

stevie1401 hat geschrieben: Ich habe mir die ThreadNummern mal angesehen. Bei mir werden die immer (wirklich immer) um 1 erhöht, wenn ich x=CreateThread() mache.
Möglich daß das in Windows so ist (ob zufällig oder ob man sich darauf verlassen kann weiß ich nicht). In Linux ist das definitiv nicht der Fall.
Benutzeravatar
Chimorin
Beiträge: 451
Registriert: 30.01.2013 16:11
Computerausstattung: MSI GTX 660 OC mit TwinFrozr III
6Gb DDR 3 RAM
AMD Phenom II X4 B55 @ 3,6GHz
Windows 7 Home Premium 64-bit

Re: ins Netzwerk senden mit Threads

Beitrag von Chimorin »

Ich denke nicht, dass du dich darauf verlassen kannst.
Normalerweise sind die PBHandles die Speicheradresse. Ob das hier auch der Fall ist, ka.
Bild

- formerly known as Bananenfreak -
Sven
Beiträge: 374
Registriert: 23.09.2004 12:01

Re: ins Netzwerk senden mit Threads

Beitrag von Sven »

Sicro hat geschrieben:Es wird nicht immer der komplette String gesendet - auch 2^16-1 Zeichen sind nicht garantiert. Wenn beim Empfänger der Empfangsbuffer fast voll ist, kann bereits nach einem Zeichen schon Schluss sein.
Ist das sicher oder vermutest Du das? Das sollte doch das TCP-Protokoll eine Ebene tiefer erledigen, da muss ich mich doch auf Programmebene nicht drum kümmern. TCP_Receive_Window ist hier nicht der bei ReceiveData angegebene "DatenPuffer". Und bei einem Receive_Window kleiner 2^16 muß der Empfänger die Daten wieder zusammenstückeln, das mach aber das System und nicht mein Programm.

Ansonsten wäre die Aussage in der PB-Hilfe zu ReceiveNetworkData() sinnlos: "Gibt die Anzahl an empfangenen Bytes zurück. Ist das 'Ergebnis' gleich der 'DatenPufferLänge', dann sind weitere Daten zum Einlesen verfügbar."

Es müssen also mehr Daten im Empfangsspeicher liegen können, als der "DatenPuffer" lang ist.

Es könnte natürlich sein, daß der Sendestring mehr als 2^16 Zeichen hat. Aber das kann man ja vorher klären.
Benutzeravatar
mhs
Beiträge: 224
Registriert: 11.01.2009 16:30
Wohnort: Graben
Kontaktdaten:

Re: ins Netzwerk senden mit Threads

Beitrag von mhs »

Ich hab schon länger nichts mehr mit der Netzwerklib gemacht, aber mir ist das auch so im Kopf, dass beim Senden (und Empfangen) die Anzahl der gesendeten Bytes überprüft und ggf. der Rest nachgeholt werden muss.

Aus diesem Grund geben auch die SendNetworkString/-Data Funktionen die Anzahl der gesendeten Bytes zurück.

Und das musst du auf Programmebene regeln, da TCP ja nicht weiß, was du vor hast, falls der Empfangspuffer voll ist...
Michael Hack

Michael Hack Software :: Softwareentwicklung | Webentwicklung | IT-Dienstleistungen
www.michaelhacksoftware.de :: www.mh-s.de :: www.michael-hack.de
Sven
Beiträge: 374
Registriert: 23.09.2004 12:01

Re: ins Netzwerk senden mit Threads

Beitrag von Sven »

mhs hat geschrieben:Und das musst du auf Programmebene regeln, da TCP ja nicht weiß, was du vor hast, falls der Empfangspuffer voll ist...
Ich würde sagen, das geht mich nichts an. Das handelt der TCP/IP-Treiber von Windows aus.

Laut https://de.wikipedia.org/wiki/Transmiss ... P-Segmente können in einem IP-Paket maximal 1460 Byte Nutzdaten übertragen werden. Die ganze Segmentierung, Nummerierung und das Wiederzusammensetzen übernimmt der TCP/IP-Treiber des Betriebssystems. Und dieser schreibt meine ankommenden Daten in einen beliebig großen Speicher. Aus dem ich dann mit ReadNetworkData wieder 65535 Bytes große Blöcke abholen kann.

Da gibt es keinen Grund für "Puffer voll", wenn man nicht gerade TCP/IP auf einem AVR Controller implementiert. Der einzige Grund, warum Sendstring nicht alle Bytes schicken soll wäre, wenn die Verbindung zwischenzeitlich unterbrochen wird.

Für die Reihenfolge mehrerer Strings kann man jeden String mit einem Zeitstempel (ElapsedMilliseconds) versehen.

Ich bin für sowas inzwischen Fan von XML: Einen XML-Baum anlegen, Spielerkennung, Zeitstempel und Spieleraktion bzw. Spielstand als Nodes bzw. Attribute ablegen. XML Exportieren und mit SendNetworkData rausjagen. Auf der Gegenseite mit ReadNetworkData einlesen, mit CatchXML den XML-Baum aus dem Speicher auslesen und die Daten auswerten. Das funktioniert besser und übersichtlicher, als wenn man den String selbst parsen muß, und man kann problemlos Parameter zufügen oder abändern.
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8807
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Re: ins Netzwerk senden mit Threads

Beitrag von NicTheQuick »

Bei TCP muss man sich nicht um die Reihenfolge kümmern. Es kommt immer alles in der richtigen Reihenfolge an.
Benutzeravatar
mhs
Beiträge: 224
Registriert: 11.01.2009 16:30
Wohnort: Graben
Kontaktdaten:

Re: ins Netzwerk senden mit Threads

Beitrag von mhs »

Sven hat geschrieben:
mhs hat geschrieben:Und das musst du auf Programmebene regeln, da TCP ja nicht weiß, was du vor hast, falls der Empfangspuffer voll ist...
Ich würde sagen, das geht mich nichts an. Das handelt der TCP/IP-Treiber von Windows aus.
Ich hab es mit einem kurzen Beispiel getestet... sieht so aus, als ob du Recht hast. Das bedeutet aber auch, dass wenn ein Empfänger seinen Empfangspuffer aus irgendeinem Grund nicht leert, der Sender bei SendNetworkString wartet bis er schwarz wird und du nicht darauf reagieren kannst...

Hier das Beispiel:

Code: Alles auswählen

EnableExplicit

Define.i Quit, Bytes
Define *Buffer

OpenConsole()

If InitNetwork() = 0
  PrintN("Kein Netzwerk...") : Input()
  End
EndIf

*Buffer = AllocateMemory(1000)

If Not CreateNetworkServer(0, 6832)
  PrintN("Server wurde nicht gestartet...") :  Input()
  End
EndIf

Repeat

  Select NetworkServerEvent()
  
    Case #PB_NetworkEvent_Connect
      PrintN("Neuer Client")

    Case #PB_NetworkEvent_Data
      Bytes = ReceiveNetworkData(EventClient(), *Buffer, 1000)
      Print("Empfangen (" + Str(Bytes) + ") --> Warten auf Enter") : Input()

    Case #PB_NetworkEvent_Disconnect
      PrintN("Getrennt")
      Quit = #True

  EndSelect
  
Until Quit

Input()
CloseNetworkServer(0)

Code: Alles auswählen

EnableExplicit

Define.i i, Bytes, Connection

OpenConsole()

If InitNetwork() = 0
  PrintN("Kein Netzwerk...") : Input()
  End
EndIf

Connection = OpenNetworkConnection("127.0.0.1", 6832)
If Not Connection
  PrintN("Keine Verbindung...") : Input()
  End
EndIf

For i = 0 To 10
  Bytes = SendNetworkString(Connection, Space(65536), #PB_UTF8)
  PrintN("Gesendet: " + Str(Bytes))
Next i

Input()
CloseNetworkConnection(Connection)
Bei mir werden 3x 65536 Bytes gesendet und dann ist der Empfangspuffer voll und der Sender wartet und wartet ...
Michael Hack

Michael Hack Software :: Softwareentwicklung | Webentwicklung | IT-Dienstleistungen
www.michaelhacksoftware.de :: www.mh-s.de :: www.michael-hack.de
Antworten