Gegebenes Server- / Client-Protokoll wie realisieren?
-
Hallo zusammen,
ich stehe hier gerade vor einem großen Problem und weiß nicht recht, wie ich es umsetzen kann. Vielleicht kann mir hier jemand den entscheidenden Hinweis geben.
Problem ist folgendes. Ich habe Geräte die mir Daten in einem bestimmten Übertragungsprotokoll senden wollen.
Das Protokoll sieht folgendermaßen aus:
Beginn der Übertragung:
!geräte-ID,START,diverse,para,meter\r\nDarauf der Server:
#ACK\r\nDas kriege ich ja noch hin, aber dann kommt das Problem:
Das Gerät sendet mir 30 Zeilen, die folgendermaßen aussehen:
!geräte-id,datentyp,die,daten,mit,komma,getrennt\nAbschließend mit der Zeile:
!geräte-id,ende,anzahl-der-zeilen\r\nDie letzte Zeile muß wieder mit #ACH\r\n bestätiht werden.
Allerdings erstreckt sich der Datenblock über mehrere TCP/IP-Frames. Irgendwie bekomme ich das nicht sauber auf die Reihe. Threads und alles klappt, nur bekomme ich dieses verfluchte Protokoll, was eigentlich simpel ist, nicht auf die Reihe. Die Daten nachher auseinander zu fummeln und zu speichern ist nicht das problem. (hoffe ich)

Ich muß gestehen, das dieses Gebiet neuland für mich ist und ich mich etwas schwer tu. Zumal ich mich mit C++ noch nicht so lange befasse.
Vielen Dank im Voraus für eure hilfe.
Wenn ich die Sorces noch posten soll, dann bitte ich um entsprechende Response.
Gruß,
Dirk
-
Das mit den "TCP/IP-Frames" versteh ich nicht. Mal abgesehen davon, dass das nicht gibt, scheinst du Probleme zu sehen, wo keine sind. Was genau klappt denn da nicht?
-
Bashar schrieb:
Das mit den "TCP/IP-Frames" versteh ich nicht. Mal abgesehen davon, dass das nicht gibt, scheinst du Probleme zu sehen, wo keine sind. Was genau klappt denn da nicht?
Hallo,
mit den Frames meine ich, Das der mir einen Teil sendet und dann den Nächsten. Das bedeutet, das es 2 Pakete sind, im Hauptteil. Wenn ich die Daten abrufe, dann habe ich da nur einen Teil drin stehen, der Rest fehlt. Wenn ich die Daten dann zur Verarbeitung aufsplitten will, fliege ich mit einem Out Of Range. Ich darf die Daten erst weiter benutzen, wenn sie komplett sind, so scheint es mir. Ich weiß allerdings nicht, wie ich das genau abfangen soll.
Ich habe nun folgendes gemacht:
#include <cstdlib> #include <iomanip> #include <exception> #include <fcntl.h> #include <string> #include <unistd.h> #include <netinet/in.h> #include <netinet/tcp.h> #include <netdb.h> #include <syslog.h> #include <vector> #include <fstream> #include <algorithm> #include <iostream> #include <iterator> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <syslog.h> #include <fcntl.h> #include <errno.h> #include <netdb.h> #include <sys/types.h> #include <sys/socket.h> #include <pthread.h> #include <mysql/mysql.h> #include <mysql++/mysql++.h> // Definition von Parametern und Umgebunsvariablen #define MYSQLPP_MYSQL_HEADERS_BURIED #define exit_if(expr) \ if(expr) { \ syslog(LOG_WARNING, "exit_if() %s: %d: %s: Error %s\n", \ __FILE__, __LINE__, __PRETTY_FUNCTION__, strerror(errno)); \ exit(1); \ } #define return_if(expr, retvalue) \ if(expr) { \ syslog(LOG_WARNING, "return_if() %s: %d: %s: Error %s\n\n", \ __FILE__, __LINE__, __PRETTY_FUNCTION__, strerror(errno)); \ return(retvalue); \ } #define MAXLEN 1024 #define MAXFD 20 #define OKAY 0 #define ERROR (-1) using namespace std; volatile fd_set the_state; pthread_mutex_t mutex_state = PTHREAD_MUTEX_INITIALIZER; int tcp_server_init ( int port ) { int listen_fd; int ret; struct sockaddr_in sock; int yes = 1; listen_fd = socket ( PF_INET, SOCK_STREAM, 0 ); exit_if ( listen_fd < 0 ); /* vermeide "Error Address already in use" Fehlermeldung */ ret = setsockopt ( listen_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof ( int ) ); exit_if ( ret < 0 ); memset ( ( char * ) &sock, 0, sizeof ( sock ) ); sock.sin_family = AF_INET; sock.sin_addr.s_addr = htonl ( INADDR_ANY ); sock.sin_port = htons ( port ); ret = bind ( listen_fd, ( struct sockaddr * ) &sock, sizeof ( sock ) ); exit_if ( ret != 0 ); ret = listen ( listen_fd, 5 ); exit_if ( ret < 0 ); return listen_fd; } int tcp_server_init2 ( int listen_fd ) { int fd; struct sockaddr_in sock; socklen_t socklen; socklen = sizeof ( sock ); fd = accept ( listen_fd, ( struct sockaddr * ) &sock, &socklen ); return_if ( fd < 0, ERROR ); return fd; } int tcp_server_write ( int fd, char buf[], int buflen ) { int ret; ret = write ( fd, buf, buflen ); return_if ( ret != buflen, ERROR ); return OKAY; } void *tcp_server_read ( void *arg ) { int rfd; char buf[MAXLEN]; int buflen; int wfd; rfd = ( int ) arg; for ( ;; ) { /* lese Meldung */ buflen = read ( rfd, buf, sizeof ( buf ) ); if ( buflen <= 0 ) { /* End of TCP Connection */ pthread_mutex_lock ( &mutex_state ); FD_CLR ( rfd, &the_state ); /* toten Client rfd entfernen */ pthread_mutex_unlock ( &mutex_state ); close ( rfd ); pthread_exit ( NULL ); } if ( buflen > 0 ) { string data = buf; size_t dbs_pos = data.find("DBS"); size_t dbe_pos = data.find("DBE"); char ack[] = "#ACK\r\n"; int acklen = sizeof ( ack ); if (dbs_pos != string::npos) { tcp_server_write(rfd, ack, acklen); } else if (dbe_pos != string::npos) { tcp_server_write(rfd, ack, acklen); } string linebegin = "!"; string lineend = "\n"; string dataend = "\r\n"; storelines(dataline); } pthread_mutex_unlock ( &mutex_state ); } return NULL; } void loop ( int listen_fd ) { pthread_t threads[MAXFD]; FD_ZERO ( &the_state ); for ( ;; ) /* Endlosschleife */ { int rfd; void *arg; /* TCP Server LISTEN Port (Client connect) pruefen */ rfd = tcp_server_init2 ( listen_fd ); if ( rfd >= 0 ) { if ( rfd >= MAXFD ) { close ( rfd ); continue; } pthread_mutex_lock ( &mutex_state ); FD_SET ( rfd, &the_state ); /* neuen Client fd dazu */ pthread_mutex_unlock ( &mutex_state ); arg = ( void * ) rfd; pthread_create ( &threads[rfd], NULL, tcp_server_read, arg ); } } } int main ( int argc, char *argv[] ) { int tcpport = 4711; /* Fehler Logging einschalten */ openlog ( NULL, LOG_PERROR, LOG_WARNING ); /* open Chat as TCP server */ loop ( tcp_server_init ( tcpport ) ); return OKAY; } int storelines(line) { // Soll die Daten später verarbeiten und in eine SQL-DB jagen }Für den Server an sich habe ich bestehende Beispiele aus dem Internet umgeschrieben, aber jetzt plagt mich noch das Problem mit dem Protokoll an Sich. Da ich akum mit C++ angefangen habe, habe ich mir nun wohl etwas zuviel zugetraut. Aber irgendwie muß das ja hin zu bekommen sein.
Gruß,
Dirk
-
omg...
1. cpp-tags statt code-tags nutzen
2. sollte man nicht alles in einer datei zusammenmanschen
3. erkenne ich keine wirkliche frage... und es ist auch zu viel dran, was ich komplett anders machen würde, als das ich hier anfangen würde: zeile x ist doof etc...
4. die includes sind bestimmt nicht alle nötig?! xD
...bb
-
Wie gesagt, sowas wie TCP-Frames gibt es nicht. Das Modell von TCP ist ein kontinuierlicher, zuverlässiger Bytestrom, nicht unähnlich einer Datei oder einer Pipe. Du kannst also einfach solange empfangen, bis du deine komplette Nachricht zusammen hast.
Letztlich ist der Grund dafür, dass recv die Daten in Schüben ausgibt, natürlich daran, dass das unterliegende IP mit Paketen arbeitet, aber diese Tatsache verbirgt TCP vor dir, so gut es kann.