Frage zu UDP (datagram socket)
-
ich nicht schrieb:
Meinst du jemand guckt sich den ganzen Code an?
Man muss au net den ganzen code lesen. Der folgende codeabschnitt reicht.
Ein paar Personen im Forum (ich weiß nicht mehr wer das war) sagten , dass deren durchschnittlichen programme 1000 oder mehr code zeilen umfassen. Deswegen bin ich davon ausgegangen , dass mein code nicht all zu lang sei.if (proto == 'u') { sock = socket(PF_INET , SOCK_DGRAM , IPPROTO_UDP); if (sock < 0) { printf("error : cannot create socket (udp)\n"); exit(-1); } if (mode == 'c') { while (1) { if (read(input , &buf , 1) <= 0) exit(0); sendto(sock , &buf , 1 , 0 , (struct sockaddr*)&addr , sizeof(addr)); } }
Also nochmal: Kann mir jemand helfen? (Bitte ernste Antwort(en))
-
alex89ru schrieb:
Ein paar Personen im Forum (ich weiß nicht mehr wer das war) sagten , dass deren durchschnittlichen programme 1000 oder mehr code zeilen umfassen. Deswegen bin ich davon ausgegangen , dass mein code nicht all zu lang sei.
Klar, 1000 Zeilen sind nicht extrem viel für ein nontriviales Programm.
Aber selbst 20 Zeilen sind schon zu viel, um sich die mal so auf gut Glück nebenbei durchzulesen, nur weil jemand anders zu faul ist, den gesuchten Fehler näher einzugrenzen.
-
Vielleicht hilft dir das weiter, ist in C geschrieben und funktioniert nur ueber UPD (kannst du ja erweitern). Es ist ein kleiner Chat-Client, den ich vor einigen Wochen fuer die Uni schreiben musste.
Es gab da zwei Loesungen, eine mit fork und die andere mit filedeskriptoren (meine - find ich im diesem Fall eleganter).#include <arpa/inet.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <unistd.h> int main( argc, argv ) int argc; char **argv; { if ( argc < 4 ) { fprintf( stderr, "Wrong parameter count!\n\tchat <local port> <remote ip> <remote port>\n" ); exit( EXIT_FAILURE ); } else { int l_port = atoi( argv[1] ); int r_port = atoi( argv[3] ); char *r_addr = argv[2]; if ( l_port < 1024 || r_port < 1024 ) { fprintf( stderr, "Wrong port ranges!\n" ); exit( EXIT_FAILURE ); } else { int server_socket; int bytes; int max; int sel_result; unsigned int msize; char buffer[BUFSIZ]; char buffer_r[BUFSIZ]; fd_set filedesc; struct sockaddr_in server_address; struct sockaddr_in client_address; struct sockaddr_in message_address; msize = sizeof( message_address ); /* Verwende hier SOCK_DGRAM stat SOCK_STREAM um eine * UDP-Verbindung zu erstellen */ if ( ( server_socket = socket( PF_INET, SOCK_DGRAM, 0) ) == -1 ) { fprintf( stderr, "%s: socket() failure!\n", argv[0] ); exit( EXIT_FAILURE ); } /* Setzt Daten fuer den Port */ server_address.sin_family = PF_INET; server_address.sin_addr.s_addr = INADDR_ANY; server_address.sin_port = htons( l_port ); if ( bind( server_socket, (struct sockaddr*)&server_address, sizeof( server_address ) ) == -1 ) { fprintf( stderr, "%s: bind() failure!\n", argv[0] ); close( server_socket ); exit( EXIT_FAILURE ); } /* Hier wird die Nummer des hoechsten file-descriptors ermittelt. * STDIN_FILENO hat im Normalfall die Nummer 0, desshalb waere hier * die Ermittlung nicht unbedingt zwingend, ist aber aus * kompatibilitaetsgrunden zu empfehlen! */ max = MAX( server_socket, STDIN_FILENO ); for ( ; ; ) { FD_ZERO( &filedesc ); /* leere den filedescriptor */ FD_SET( server_socket, &filedesc ); /* server socket hinzufuegen */ FD_SET( STDIN_FILENO, &filedesc ); /* STDIN_FILENO hinzufuegen */ /* select ueber die fd's. Wartet so lange, bis ein ereignis an einen der fd's auftritt. * Alternativ koennte man eine Zeit-Struktur angeben (letzter Parameter). * Wenn der select() Aufruf zurueck kommt enthaelt er alle fd's, an deinen ein Ereignis anliegt, * da das mehrere sein koennen ist eine doppelte if-Konstruktionn der if-else-Konstruktion * vorzuziehen. */ sel_result = select( max+1, &filedesc, NULL, NULL, NULL ); if ( FD_ISSET( server_socket, &filedesc ) ) /* Testet ob am server socket ein Ereignis anliegt */ { if ( ( bytes = recvfrom( server_socket, buffer, BUFSIZ, 0, (struct sockaddr*)&message_address, &msize ) ) == -1 ) /* Empfange Daten */ { fprintf( stderr, "%s: recvfrom() failure!\n", argv[0] ); close( server_socket ); exit( EXIT_FAILURE ); } /* if ( buffer[bytes-1] != '\0' ) */ buffer[bytes] = '\0'; /* Hier liegt der Fehler begraben, warum? */ int c_port = htons( message_address.sin_port ); char *c_addr =inet_ntoa( message_address.sin_addr ); /* Ueberpruefe Daten der Gegenstelle und gib eine Fehlermeldung oder die Nachricht aus! */ if ( strlen( r_addr ) != strlen( c_addr ) || strncmp( r_addr, c_addr, strlen( r_addr ) ) != 0 ) { fprintf( stderr, "IP missmatch: REMOTE IP: %s, CLIENT IP: %s\n", r_addr, c_addr ); } else if ( r_port != c_port ) { fprintf( stderr, "PORT missmatch: REMOTE PORT: %d, CLIENT PORT: %d\n", r_port, c_port ); } else { fflush( stdout ); fprintf( stdout, "%s", buffer ); fflush( stdout ); } } if ( FD_ISSET( STDIN_FILENO, &filedesc ) ) /* Testet ob am standad input ein Ereignis anliegt. */ { fflush( stdout ); /* if ( fgets( buffer_r, BUFSIZ, STDIN_FILENO ) != NULL ) */ if ( ( bytes = read( STDIN_FILENO, buffer_r, BUFSIZ ) ) == -1 ) /* Lese von STDIN */ { fprintf( stderr, "%s: read() failure!\n", argv[0] ); close( server_socket ); exit( EXIT_FAILURE ); } buffer_r[bytes] = '\0'; fflush( stdin ); /* Richte die Daten fuer das Senden ein */ client_address.sin_family = AF_INET; client_address.sin_addr.s_addr = inet_addr( r_addr ); client_address.sin_port = htons( r_port ); /* Sende die eingegebenen Daten */ if( sendto( server_socket, buffer_r, strlen( buffer_r ), 0, (struct sockaddr *)&client_address, sizeof(client_address) ) == -1) { fprintf( stderr, "%s: sendto() failure!\n", argv[0] ); close( server_socket ); exit( EXIT_FAILURE ); } } /* Entferne die fd's, die im fd_set liegen. * Ist nicht unbedingt notwendig, weil bei jedem durchgang das * fd_set geleert wird. */ FD_CLR( server_socket, &filedesc ); FD_CLR( STDIN_FILENO, &filedesc ); } } } return EXIT_SUCCESS; }
Vielleicht kannst du etwas damit anfangen!
P.S.: Als argumente erhaelt das Programm den lokalen Port, auf den es horchen und senden soll, die IP-Adresse und den Port der Gegenstelle.
-
@moe szyslak:
Danke erstmal. Ähm , ich hab da ne Frage zu deinem code:
D hast folgendes geschrieben:server_address.sin_addr.s_addr = INADDR_ANY;
Muss das nicht so heißen?
server_address.sin_addr.s_addr = htonl(INADDR_ANY);
Oder ist es egal?
@nman:
Ich zu Faul? Sorry , aber ich hab selebr ne Zeit lang alles mögliche ausprobiert und ich komme einfach net weiter.
zu "fehler eingrenzen": Lies den anfang vom thread durch...
-
Ja, ich glaube schon - hab wahrscheinlich nur ne alte version am rechner.
Mit htonl funktionierts auf jeden Fall!Wenn du die Funktion verwendest bist du auf der sicheren Seite. Im Netzwerk-Verkehr ist es so, dass die Daten nach einem bestimmten Schema versendet werden (LITTLE/BIG ENDIAN). Das heist, verwendest du die Methode nicht kann es sein, dass du z.B. Probleme hast, wenn du von PowerPc auf x 86 sendest oder umgekehrt.
-
moe szyslak schrieb:
Ja, ich glaube schon - hab wahrscheinlich nur ne alte version am rechner.
Mit htonl funktionierts auf jeden Fall!Wenn du die Funktion verwendest bist du auf der sicheren Seite. Im Netzwerk-Verkehr ist es so, dass die Daten nach einem bestimmten Schema versendet werden (LITTLE/BIG ENDIAN). Das heist, verwendest du die Methode nicht kann es sein, dass du z.B. Probleme hast, wenn du von PowerPc auf x 86 sendest oder umgekehrt.
Ok. Hab mich nämlich schon gewundert , da ich es MIT htonl() gelernt hab , in letzter Zeit aber öffters mal codebsp gesehen hab , welche kein htonl verwendeten.
-
alex89ru schrieb:
Ich zu Faul? Sorry , aber ich hab selebr ne Zeit lang alles mögliche ausprobiert und ich komme einfach net weiter.
Ja, eindeutig zu faul. Sonst hättest Du zB auch die Netcat-Sourcen sofort gefunden.
zu "fehler eingrenzen": Lies den anfang vom thread durch...
Hab ich. Du beschreibst Deine Probleme und knallst uns dann 327 Zeilen Code hin. Auf sowas antwortet Dir garantiert niemand, dem nicht gerade extrem langweilig ist.
-
nman schrieb:
alex89ru schrieb:
Ich zu Faul? Sorry , aber ich hab selebr ne Zeit lang alles mögliche ausprobiert und ich komme einfach net weiter.
Ja, eindeutig zu faul. Sonst hättest Du zB auch die Netcat-Sourcen sofort gefunden.
zu "fehler eingrenzen": Lies den anfang vom thread durch...
Hab ich. Du beschreibst Deine Probleme und knallst uns dann 327 Zeilen Code hin. Auf sowas antwortet Dir garantiert niemand, dem nicht gerade extrem langweilig ist.
Sorry.
-
alex89ru schrieb:
@moe szyslak:
Danke erstmal. Ähm , ich hab da ne Frage zu deinem code:
D hast folgendes geschrieben:server_address.sin_addr.s_addr = INADDR_ANY;
Muss das nicht so heißen?
server_address.sin_addr.s_addr = htonl(INADDR_ANY);
Oder ist es egal?
INADDR_ANY
bzwin.h schrieb:
typedef uint32_t in_addr_t;
#define INADDR_ANY ((in_addr_t) 0x00000000)und zu htonl:
<a href= schrieb:
<arpa/inet.h>">The htonl() and htons() functions return the argument value converted from host to network byte order.
bzw
uint32_t htonl(uint32_t hostlong);
-
@moe szyslak:
thx...jetzt funktioniert mein prog einwandfrei.
-
hallo,
ich habe in der firma die wundervolle aufgabe bekommen ein windows-programm das zyklisch istwert-daten über udp von einer sps abholt auf linux umzusetzen. und nach 3 tagen googeln ist dass das erste brauchbare beispiel das mich auf anhieb sehr viel weiter gebracht hat. echt klasse!
nun hätte ich aber da ein paar fragen:
bei select() kann ich ja 3 fd-sets übergeben, nur wenn ich eins für lesen und eins für schreiben übergebe greift mein timeout nicht mehr:
. . . FD_ZERO(&writefd); FD_SET(sock, &writefd); FD_SET(STDIN_FILENO, &writefd); FD_ZERO(&readfd); FD_SET(sock, &readfd); FD_SET(STDIN_FILENO, &readfd); timeout.tv_sec = 1; timeout.tv_usec = 0; sel_result = select(max +1, &readfd, &writefd, NULL, &timeout); if(FD_ISSET(sock, &writefd)) { printf("daten senden\n"); } if(FD_ISSET(sock, &readfd)) { printf("daten empfangen\n"); } . . .
dann habe ich das so umgebaut:
. . . FD_ZERO(&writefd); FD_SET(sock, &writefd); FD_SET(STDIN_FILENO, &writefd); timeout.tv_sec = 1; timeout.tv_usec = 0; sel_result = select(max +1, NULL, &writefd, NULL, &timeout); if(FD_ISSET(sock, &writefd)) { printf("daten senden\n"); } FD_ZERO(&readfd); FD_SET(sock, &readfd); FD_SET(STDIN_FILENO, &readfd); timeout.tv_sec = 1; timeout.tv_usec = 0; sel_result = select(max +1, &readfd, NULL, NULL, &timeout); if(FD_ISSET(sock, &readfd)) { printf("daten empfangen\n"); } . . .
dann funktioniert auch jedesmal mein timeout, nur: welches ist jetzt die "richtige" lösung? oder macht man das überhaupt so? oder einfach nur stur senden und dann den timeout bzw. die rückmeldung von sendto() verarbeiten um zu sehen ob meine sps überhaupt übers netzwerk erreichbar ist?
gruss, marco
p.s. ja, tcp/ip illustrated vom stevens hab ich bestellt, ist leider noch unterwegs *gnarf*
p.p.s. der code-schnipsel sollte in die faq eingetragen werden