Einfacher TCP socket server für single Verbindung

Alle Fragen zur Netzwerkkommunikation
DL3AD
Beiträge: 478
Registriert: Fr 13. Sep 2013, 12:07
OS, Lazarus, FPC: Debian Bullseye (L 2.2.0)
CPU-Target: 64Bit
Wohnort: Rügen

Einfacher TCP socket server für single Verbindung

Beitrag von DL3AD »

Hallo,
ich habe ein Server Gerät (Raspi) das Daten in simplen Strings auf Anfrage liefern soll.
Diese Daten möchte ich auf dem Client PC anfragen und abholen.

Die Communikation soll per TCP erfolgen.
Hier mein Testprogramm

Code: Alles auswählen

 
//Initialisierungen
procedure TForm1.FormShow(Sender: TObject);
begin
  sockS:= TTCPBlockSocket.Create;
  sockC:= TTCPBlockSocket.Create;
  //Server Socket
  socks.Bind('127.0.0.1','10001');
  if sockS.LastError <> 0 then
  begin
    ShowMessage('Server Fehler');
    Form1.Close;
  end
  else
  begin
    sockS.Listen;
  end;
  //Client Socket
  sockC.Connect('127.0.0.1','10001');
  if sockC.LastError = 0 then
  begin
    sockC.ConvertLineEnd:= true;
  end
  else
  begin
    ShowMessage('Keine Verbindung !');
    Form1.Close;
  end;
  Memo1.Clear;
  Memo2.Clear;
end;
 
//Beenden
procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);
begin
  sockC.Free;
  sockS.Free;
end;
 
//Server =======================================================================
//Senden
procedure TForm1.Btn_STxClick(Sender: TObject);
begin
  sockS.SendString(Edit2.Text + Chr($13));
end;
 
//Empfang
procedure TForm1.Btn_SRxClick(Sender: TObject);
begin
  Memo2.Append(sockS.RecvPacket(50));
end;
 
//Client =======================================================================
//Senden
procedure TForm1.Btn_CTxClick(Sender: TObject);
begin
  sockC.SendString(Edit1.Text + Chr($13));
end;
 
//Empfang
procedure TForm1.Btn_CRxClick(Sender: TObject);
begin
  Memo1.Append(sockC.RecvPacket(50));
end;                             
 


Der Client Teil funktioniert schon mal prinzipiell - getestet mit einem anderen TCP-Server.
Was mache ich hier an den Serverpart falsch ?
Die IP stellt er zwar zur verfügung und der Client kann sich auch verbinden - aber es gibt keine Kommunikation.

Gruß Frank
Dateianhänge
xSocket Test.zip
(225.51 KiB) 377-mal heruntergeladen

Socke
Lazarusforum e. V.
Beiträge: 3158
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Einfacher TCP socket server für single Verbindung

Beitrag von Socke »

Da du blockierende Sockets verwendest, musst du Client und Server Socket zwingend auf separate Threads oder Prozesse verteilen.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

DL3AD
Beiträge: 478
Registriert: Fr 13. Sep 2013, 12:07
OS, Lazarus, FPC: Debian Bullseye (L 2.2.0)
CPU-Target: 64Bit
Wohnort: Rügen

Re: Einfacher TCP socket server für single Verbindung

Beitrag von DL3AD »

... ok dann mache ich zum Test mal zwei Programme draus

DL3AD
Beiträge: 478
Registriert: Fr 13. Sep 2013, 12:07
OS, Lazarus, FPC: Debian Bullseye (L 2.2.0)
CPU-Target: 64Bit
Wohnort: Rügen

Re: Einfacher TCP socket server für single Verbindung

Beitrag von DL3AD »

... habe nun Client und Server als einzelne Programme laufen - Kommunikation funktioniert immer noch nicht :(

Warf
Beiträge: 1908
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: Einfacher TCP socket server für single Verbindung

Beitrag von Warf »

Fehlt da nicht ein accept beim Server?
Der listens die ganze Zeit, kann aber wenn eine Verbindung kommt die nicht annehmen

DL3AD
Beiträge: 478
Registriert: Fr 13. Sep 2013, 12:07
OS, Lazarus, FPC: Debian Bullseye (L 2.2.0)
CPU-Target: 64Bit
Wohnort: Rügen

Re: Einfacher TCP socket server für single Verbindung

Beitrag von DL3AD »

... wie und wo baut man das accept ein ?

Benutzeravatar
theo
Beiträge: 10467
Registriert: Mo 11. Sep 2006, 19:01

Re: Einfacher TCP socket server für single Verbindung

Beitrag von theo »

Ich hatte vor rund hundert Jahren hier mal eine kleine Demo gebastelt: https://lazarusforum.de/viewtopic.php?p=2626#p2626 und jetzt nochmal unten angehängt.
Vllt. hilft das ein bisschen. Benutzt allerdings für den Server einen sep. Thread.
Dateianhänge
chat.zip
(127.12 KiB) 437-mal heruntergeladen

DL3AD
Beiträge: 478
Registriert: Fr 13. Sep 2013, 12:07
OS, Lazarus, FPC: Debian Bullseye (L 2.2.0)
CPU-Target: 64Bit
Wohnort: Rügen

Re: Einfacher TCP socket server für single Verbindung

Beitrag von DL3AD »

Hallo theo,

danke Für die Demo - aber da steige ich nicht durch und mit Threads habe ich noch nix gemacht. :shock:
Schau doch mal bitte in den ersten Post - was muss ich da Ändern damit es geht.
Habe mittlerweile Client und Server als separate Programme - so ist es ja auch später.
Der Client läuft - aber der Server nicht.

Gruß Frank

Benutzeravatar
theo
Beiträge: 10467
Registriert: Mo 11. Sep 2006, 19:01

Re: Einfacher TCP socket server für single Verbindung

Beitrag von theo »

Ohne Threads habe ich das nie gemacht. Weiß gar nicht ob das geht.
Funktioniert die Demo denn nicht?
Zu Threads kannst du hier lesen: http://wiki.lazarus.freepascal.org/Mult ... n_Tutorial

DL3AD
Beiträge: 478
Registriert: Fr 13. Sep 2013, 12:07
OS, Lazarus, FPC: Debian Bullseye (L 2.2.0)
CPU-Target: 64Bit
Wohnort: Rügen

Re: Einfacher TCP socket server für single Verbindung

Beitrag von DL3AD »

Hallo theo,

Danke für deine Hilfe - habe es mal mit LNet versucht - da war ein Beispiel bei - das funktioniert 1A.
Was ich besonders erfreulich bei LNet ist, es stellt verschidene Ereignisse zur Verfügung im Gegensatz zu Synapse.

Gruß Frank

Benutzeravatar
theo
Beiträge: 10467
Registriert: Mo 11. Sep 2006, 19:01

Re: Einfacher TCP socket server für single Verbindung

Beitrag von theo »

DL3AD hat geschrieben:Danke für deine Hilfe - habe es mal mit LNet versucht - da war ein Beispiel bei - das funktioniert 1A.
Was ich besonders erfreulich bei LNet ist, es stellt verschidene Ereignisse zur Verfügung im Gegensatz zu Synapse.


OK, LNet Ist da für den Einstieg (Server) vielleicht etwas einfacher.

Warf
Beiträge: 1908
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: Einfacher TCP socket server für single Verbindung

Beitrag von Warf »

DL3AD hat geschrieben:Für nen TCP server externe komponenten


Sorry das ich erst jetzt richtig antworten kann (war damals nur am Handy).

Also ein Server läuft normalerweise so ab:
1. Socket Create
2. An Adresse und Port Binden
3. Listen (Socket für einkommende verbindungen öffnen)
4. Accept -> neues Socket für die Client verbindung
5. Thread für neuen Clienten starten, der kann über das client Socket kommunizieren
6. Gehe zu schritt 4 und nimm ne neue verbindung auf oder warte auf beendete verbindungen

Alternativ kannst du auch eine verbindung akzeptieren, auf dem Haupthread kommunizieren und erst wenn die verbindung mit dem Client beendet wurde den Nächsten anzunehmen (das Betriebsystem sollte eingehende verbindungen buffern). Somit brauchst du keine Threads. Wenn du aber mehr als eine verbindung gleichzeitig brauchst musst du aber wohl auf threads zurückgreifen (oder non blocking sockets verwenden, und selbst schedulen, das wird aber sehr schnell sehr hässlich).

Außerdem, du brauchst keine Externen Komponenten für ne TCP verbindung, weder Synapse noch lNet. FreePascal stellt in der FCL die Unit Sockets für low level Cross Platform Socket handling, und die Unit ssockets mit einer sehr angenehmen OOP klassenstruktur für Sockets. Für einen TCP server kannst du einfach die klasse TINetServer verwenden, geht kinderleicht und ist gut erweiterbar, ich hab mal einen beispiel Server angehängt.

Leider gibts praktisch keine Dokumentation und ich hab auch nur durch blick in den Source Code von TFPHTTPServer gefunden, aber die benutzung ist selten einfach:

Code: Alles auswählen

...
// Server erstellen
  FServer := TINetServer.Create(port);
// Keine max connections
  FServer.MaxConnections:=-1;
// Methode die eingehende Connections verarbeiten
  FServer.OnConnect:=@HandleConnection;
 
  FServer.Bind;
  FServer.Listen;
  FServer.StartAccepting; // blockiert bis der server ausgeschaltet wird mit StopAccepting
 
...
 
procedure TServer.HandleConnection(Sender: TObject; Data: TSocketStream);
begin
  // Starte Thread mit Data als Socket zum lesen (Data.Read) und schreiben (Data.Write)
end
Dateianhänge
Server.pas
(2.96 KiB) 395-mal heruntergeladen

Benutzeravatar
fliegermichl
Lazarusforum e. V.
Beiträge: 1430
Registriert: Do 9. Jun 2011, 09:42
OS, Lazarus, FPC: Lazarus Fixes FPC Stable
CPU-Target: 32/64Bit
Wohnort: Echzell

Re: Einfacher TCP socket server für single Verbindung

Beitrag von fliegermichl »

Unter Linux kann man auch fpFork() verwenden. Das erstellt eine exakte Kopie des Prozesses. Dann kann man auf die Multithreading Geschichte verzichten.

Warf
Beiträge: 1908
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: Einfacher TCP socket server für single Verbindung

Beitrag von Warf »

fliegermichl hat geschrieben:Unter Linux kann man auch fpFork() verwenden. Das erstellt eine exakte Kopie des Prozesses. Dann kann man auf die Multithreading Geschichte verzichten.


Nicht nur unter Linux, unter jedem Posix, also auch unter BSD oder MacOS. Oder um es anders zu sagen, unter jedem Betriebsystem außer Windows.

Aber fork, obwohl es solche Sachen echt angenehm macht ist verdammt langsam. Auch wenn Copy on Write implementiert ist muss dennoch über alle Memorypages iteriert werden und diese als kopiert markiert werden, das sind c.a. Virtuelle Speichergröße / 4kb iterationen. Das kann bei lange laufenden Programmen gut und gerne mal ein paar Sekunden dauern (im Gegensatz zu den Milli/Nanosekunden die es kostet einen pthread zu spawnen). Mein Rekord liegt bei 6 Stunden pro Fork call, ich weiß bis heute nicht warum, konnte durch vFork das Problem allerdings umgehen. Mal ganz davon abgesehen das ne ganze menge infos im neuen Prozess nicht benötigt werden, z.B. das Server socket. Man umgeht zwar die ganzen Multithreading Probleme, die kann man aber auch umgehen indem man keine Kommunikation zwischen Threads macht.

Fork kommt aus einer zeit als Prozesse nur 2 memory pages hatten, heutzutage ist es aber eher selten eine gute Idee, vor allem da Threading verdammt einfach geworden ist

Benutzeravatar
fliegermichl
Lazarusforum e. V.
Beiträge: 1430
Registriert: Do 9. Jun 2011, 09:42
OS, Lazarus, FPC: Lazarus Fixes FPC Stable
CPU-Target: 32/64Bit
Wohnort: Echzell

Re: Einfacher TCP socket server für single Verbindung

Beitrag von fliegermichl »

Ich hatte mal einen Serverprozess gebaut, der verschiedene Datendateien zur Vefügung stellen soll. Da wurde am Anfang nur ein sog. Masterprozess gestartet der auf Verbindungen gewartet hat.
Wenn ein Client den kontaktiert hat, konnte er die zur Verfügung stehenden Datendateien abfragen und in einer separaten Verbindung eine bestimmte Datendatei auswählen.

Der Master hat dann per fpFork eine Kopie seines Prozesses angelegt. Die Kopie hat dann die entsprechende Datendatei geladen und auf einem separaten Port auf Anfragen gelauscht.
Der anfragende Client hat vom Masterprozess dann die Portnummer der Kopie bekommen.

Nun hat der Client die Kopie auf dem neuen Port konnektiert. Der zweite Datenprozess hat danach alsogleich wieder per fpFork eine Kopie von sich angelegt. So konnte der zweite Prozess auf weitere Anfragen zur selben Datendatei warten. Die dritte Kopie hat dann solange mit dem Clienten Daten ausgetauscht wie sie gebraucht wurde.

Das hat jahrlang im praktischen Einsatz einwandfrei funktioniert. Ein Fehler hatte sich aber doch eingeschlichen. Wenn der Client die Verbindung nicht sauber getrennt hat, blieb ein Zombieprozess übrig und dem System gingen dann irgendwann die Prozesshandles aus.

Aber zeitliche Verzögerungen durch das fork konnte ich nicht feststellen.

Antworten