Forum: PC-Programmierung String Transmission Protocoll mit posix sockets


von Stefanie B. (sbs)



Lesenswert?

Hallo Leute,

da ich ein größeres Projekt plane, welches übers Netzwerk läuft habe ich 
mir die posix Sockets angeschaut.

Ich brauche eine zuverlässige Verbinung, die Datagramme(einzele Pakete, 
zb Strings) verschicken kann.

Da dort nur Streams zuverlässig funktioneren (jedenfalls habe ich nichts 
dergleichen gefunden), habe ich die Funktionalität selbst eintwickelt 
und das ganze hochtrabend "String Transmission Protocoll" genannt. ;-)

Hier ein kleiner Ausblick:
1
stp_connection* stp_connect(char* host, int port);
2
3
void stp_accept_connections(int port, void callback(stp_connection* new_connection));
4
5
char* stp_recv(stp_connection* stp );
6
7
int stp_send(stp_connection* stp, char* line);
8
9
void stp_shutdown(stp_connection* stp );

Im Anhang sind die Sourcen dafür, sowie zwei Testprogramme.

Einen kleine Fehler gibt es noch im Server Testprogramm:
Durch die Verwendung von pthreads wird Speicher allokiert, den ich nicht 
freigeben kann(finde keinen pointer dafür :( ).

Ich bitte um Kommentare (Funktionalität, API, Programmierstil, etc.).

Viele Grüße
Stefan Beller

von Karl H. (kbuchegg)


Lesenswert?

Das hier
1
      if(! (stp->offset < stp->maxSize)){  
2
        char* newwaitingline;
3
        newwaitingline = (char*)malloc(stp->maxSize*2*sizeof(char));
4
        memmove(newwaitingline,stp->waitingline,stp->maxSize);
5
        free(stp->waitingline);
6
        stp->waitingline=newwaitingline;
7
        stp->maxSize*=2;
8
      }

also die Vergrößerung des Buffers, hättest du auch billiger bekommen 
können. Stichwort: realloc
realloc vergrößert den Buffer, falls das möglich ist. Wenn es dabei 
ausnutzen kann, dass es im Speicher hinter dem Buffer brachliegenden 
Speicher mitbenutzen kann, dann wird es das tun und sich so das 
Umkopieren der Daten sparen. Andernfalls allokiert realloc neuen 
Speicher und erledigt auch das Umkopieren.


1
    switch(bytes_sent){
2
...
3
      case -1:
4
        /*an error occured, return 1 to indicate*/
5
        return 1;
6
        break;

Hmm. Denkst du nicht, dass du zumindest versuchen solltest, den 
Empfänger zu benachrichtigen?
Wenigstens soweit, dass du den Empfänger durch Übermittlung einer '\0' 
aus seiner Warteschleife rauslässt.


Für eine Basis-Lib fehlt mir da die Abfrage von Fehlern. Du benutzt 
malloc als ob du unendlich viel Speicher hättest. Für eine Lib-Funktion 
ist das aber nicht akzeptabel. Der Returnwert von malloc muss abgefragt 
werden und, viel spannender, man muss sich etwas überlegen wie es weiter 
gehen soll, wenn man keinen Speicher mehr hat. Akzeptabel ist fast 
alles, nur eines nicht: Das das Programm deswegen crasht bzw. 
anderweitig Daten zerstört.

Aus diesen und ähnlichen Gründen wird daher bei Übertragungen gerne die 
Länge des nun folgenden Datensatzes zuerst übertragen. Denn dann kann 
sich der Empfänger einen entsprechend großen Buffer zurechtlegen. Die 
Länge hat zwar den Nachteil, dass man einen Datentyp dafür vereinbaren 
muss, auf der anderen Seite wiegt aber der Vorteil, dass der Empfänger 
weiß was auf ihn zukommt, vieles auf.

von Stefanie B. (sbs)



Lesenswert?

Okay,

ich habe das Ganze ein wenig umgeschrieben.
Man muss zum Verbindungsaufbau nicht mehr angeben wie lang der längste 
String ist, sondern am Anfang jeder Übertragung wird die Länge 
übermittelt.

Das reallocate habe ich auch eingebaut.
(Dieses wird ohnehin nur im Fehlerfall aufgerufen.)

Alle malloc-Fehler werden auch abgefangen.


Nun den zweiten Punkt, den Karl Heinz ansprach, habe ich so umgebaut, 
dass eine Fehlermeldung geworfen wird.

Gegenfrage: Wie teile ich dem Gegenüber mit, dass bei mir irgendetewas 
nicht stimmt, wenn der Fehler darin besteht, das die send-Funktion nicht 
ordnungsgemäß funktioniert?
1
    switch(bytes_sent){
2
...
3
      case -1:
4
        /*an error occured, return 1 to indicate*/
5
        perror("stp_send");
6
        return 1;
7
        break;

von Karl H. (kbuchegg)


Lesenswert?

Stefan B. schrieb:

> Gegenfrage: Wie teile ich dem Gegenüber mit, dass bei mir irgendetewas
> nicht stimmt, wenn der Fehler darin besteht, das die send-Funktion nicht
> ordnungsgemäß funktioniert?

Das ist natürlich eine gute Frage und hängt auch davon ab, warum genau 
eigentlich send das Versenden der Daten verweigert hat.

Jetzt fängt die Sache nämlich an komplizierter zu werden. Wie eigentlich 
meistens wen Fehlerbehandlung ins Spiel kommt :-)

von sebastians (Gast)


Lesenswert?

> Gegenfrage: Wie teile ich dem Gegenüber mit, dass bei mir irgendetewas
> nicht stimmt, wenn der Fehler darin besteht, das die send-Funktion nicht
> ordnungsgemäß funktioniert?

Z.B. indem du einen Watchdog nicht mehr triggerst.

von Stefanie B. (sbs)


Angehängte Dateien:

Lesenswert?

Hallo,

so ich habe ein wenig an dem API herumgespielt.

send/recv sind threadsafe, dh. jeweils mit einem Mutex geschützt.

Das serverseitige stp_accept_connections läuft auch mit threads, sodass
diese Funktion nicht blockiert.
Damit ist dann zb so etwas möglich:
1
  a = stp_accept_connections(port, &callback);  
2
  sleep(180);//warte 3 Minuten  
3
  stp_stop_accepting(a);//es werden keine neuen eingehenden Verbindungen akzeptiert.


Nun Fehlerbehandlung, wer mag sie nicht ? ;-)

Ich habe das soweit abstrahiert, dass man entweder senden/empfangen kann 
oder nicht. Also der Systemzustand ist relativ binaer: funktioniert oder 
funktioniert nicht.

Natürlich geht nichts in der Bibliothek derart schief, das das Programm 
crashed, sondern es wird nur per Rückgabewert mitgeteilt, das die 
Verbindung defekt ist.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.