filedescriptor - wie waehlen



  • Hallo,
    ich schreibe gerade an einem kleinen UDP-Chat Programm.
    Und zwar soll das ein einfaches Konsolen-programm werden. Wenn der User etwas eingibt wird es gesendet und wenn etwas ankommt wird das eben ausgegeben.
    Bisher bin ich soweit:

    #include <arpa/inet.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    
    #define MSG_SIZE 1024
    
    int 
    main( argc, argv )
    int argc;
    char **argv;
    {
    	int l_port = 1501;
    	int in_sockets;
    	// int r_port = 1501;
    	// char *r_addr = "127.0.0.1";
    	struct sockaddr_in server_address;
    	fd_set socks; /* typedef - Filedescriptor */
    
    	int SERVER_SOCKET;
    	// int client_socket;
    
    	/* Initalisierung des Servers */
    	if ( ( SERVER_SOCKET = socket( AF_INET, SOCK_DGRAM, 0) ) == -1 ) 
    	{
    		fprintf( stderr, "%s: socket() failure!\n", argv[0] );
    		exit( EXIT_FAILURE );
    	}
    
    	server_address.sin_family = AF_INET;
    	server_address.sin_addr.s_addr = htonl( INADDR_ANY );
    	server_address.sin_port = 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 );
    	}
    
    	int i;
    	for ( i = 0 ; ; i++ )
    	{
    		/* setz den file descriptor zusammen */
    		FD_ZERO( &socks ); /* leert den file descriptor socks, so dass er keine Elemente mehr enthaelt */
    		FD_SET( SERVER_SOCKET, &socks ); /* Fuege den server_socket zum file descriptor */
    		FD_SET( STDIN_FILENO, &socks ); /* Fuege den standard input zum file descriptor hinzu */
    
    		in_sockets = select( 50000, &socks, (fd_set *)0, (fd_set *)0, NULL );
    	}
    
    	return 0;
    }
    

    Nun zu meinen fragen:
    Wie krieg ich raus, welcher File Descriptor jetzt bereit ist zu lesen. Der Rueckgabewert von select ist meines Wissens nach ja die Anzahl der Fildedescriptoren.
    Ich hab mir dann noch nen Client zusammengepastelt. Wenn ich dann zum Test an den Server etwas schicke dann dreht der vollkommen durch. Das select wird einfach uebersprungen, immer wieder.
    Hab schon versucht mit dem Timeout zu loesen, aber ich geh die sache anscheinend falsch an, bitte um Hilfestellung! 🙂

    Vielen dank schon mal im voraus
    mfg



  • Dei Problem ist sicherlich, dass an stdin ein Ereigniss vorliegt. Nimm es doch mal raus, dann sollte select warten.

    Select arbeitet mit Mengen, das heißt du übergibst ihm alle Deskriptoren die er überwachen soll und select schmeißt alle raus, für die keine Ereignisse vorliegen.
    Mit FD_ISSET() testest du, ob ein Deskriptor in der Menge ist.
    Bsp.: if (FD_ISSET( STDIN_FILENO, &socks )) //stdin ist noch drin
    Nicht vergessen, die Deskriptoren vor dem erneuten Aufrufen von select in die Menge wieder füllen.



  • Das mit dem weglassen von stdin hab ich schon probiert, funkt nicht.
    Aber ich mach mal ein flush, vielleicht bringt das was!

    Auf jeden Fall mal danke fuer deine Erklaerungen! 👍



  • Also es will immer noch nicht so richtig.
    Hab das Programm ein wenig veraendert und eigentlich ist es ja schon fast fertig. Hier nur noch die for-Schleife, an der ja eigentlich alles haengt:

    for ( ; ; )
    			{
    				fflush( STDIN_FILENO );
    
    				/* setz den file descriptor zusammen */
    				FD_ZERO( &socks ); /* leert den file descriptor socks, so dass er keine Elemente mehr enthaelt */
    				FD_SET( SERVER_SOCKET, &socks ); /* Fuege den server_socket zum file descriptor */
    				FD_SET( STDIN_FILENO, &socks ); /* Fuege den standard input zum file descriptor hinzu */
    
    				in_sockets = select( max, &socks, (fd_set *)0, (fd_set *)0, NULL );
    
    				if ( FD_ISSET( SERVER_SOCKET, &socks ) )
    				{
    					fprintf( stdout, "\tsocket handler is active!\n" );
    
    					if( ( bytes = recvfrom( SERVER_SOCKET, buffer, strlen( buffer ), 0, NULL, NULL ) ) == -1 ) 
    					{
    						fprintf( stderr, "%s: recvfrom() failure!\n", argv[0] );
    						close( SERVER_SOCKET );
    						exit( EXIT_FAILURE );
    					}
    					buffer[bytes] = '\0';
    
    					fprintf( stdout, "%s\n", buffer );
    				}
    				else if ( FD_ISSET( STDIN_FILENO, &socks ) )
    				{
    					fprintf( stdout, "\tinput handler is active!\n" );
    					if ( (bytes = read( STDIN_FILENO, buffer, strlen( buffer ) ) ) == -1 )
    					{
    						fprintf( stderr, "%s: read() failure!\n", argv[0] );
    						close( SERVER_SOCKET );
    						exit( EXIT_FAILURE );
    					}
    
    					buffer[bytes] = '\0';
    
    					client_address.sin_family = AF_INET;
    					client_address.sin_addr.s_addr = inet_addr( r_addr );
    					client_address.sin_port = htons( r_port ); 
    
    					if( sendto( SERVER_SOCKET, buffer, strlen(buffer), 0, (struct sockaddr *)&client_address, sizeof(client_address) ) == -1)
    					{
    						fprintf( stderr, "%s: sendto() failure!\n", argv[0] );
    						close( SERVER_SOCKET );
    						exit( EXIT_FAILURE );
    					}
    				}
    				else
    				{
    					fprintf( stderr, "select() FD_ISSET failure!\n" );
    				}
    			}
    

    Ich lande immer noch, nachdem ich etwas erhalten oder gesendet habe in einer Endlosschleife - das Select wird einfach uebersprungen. Die Handler setz ich wie du siehst bei jedem Schleifendurchlauf neu.
    fflush hat auch nichts gebracht.
    Die Variablen, die neu Hinzugekommen sind sind alle korrekt. Das Programm uebersetzt auch ohne murren
    [code]gcc -Wall -Werror -ansi chat.c -o chat[/cpp]
    Trotzdem funkt es nicht.
    Vielleicht noch ne Idee?

    mfg



  • moe szyslak schrieb:

    gcc -Wall -Werror -ansi chat.c -o chat
    

    Warum machst du das denn alles? select selbst braucht keine Complier-Flags.

    kann doch sein, dass fflush auch als Schreiboperation interpretiert wird und darum select anschlägt.
    Du willst einen Server bauen, der horcht aber auch reagiert, wenn einer was aintippt, wieso machst du nicht was mit fork und pipe-Kommunikation zwischen der Prozess, der am Server lauscht und dem Eingabe-Prozess, dann könntest du den Pipe-Deskriptor zu deiner select-Menge hinzufügen.



  • gcc -Wall -Werror -ansi chat.c -o chat
    Das sind alles Compilerflags die mir
    -Wall (Alle Warnungen anzeigen)
    -Werror (Warungen und Fehler speziell angezeigt werden)
    -ansi (Verstoesse gegen den ANSI C Standard anzeigen)

    Einen Fehler hab ich glaub ich schon gefunden, im Select muss das max um eins erhoeht werden, also max+1, sonst funktioniert es nicht.
    Nur haeng ich immer noch in der Schleife fest - mal schaun, die Nacht ist noch Jung *g*.

    [edit] Musste gerade ein sehr seltsames Phanomen beobachten. Wenn ich meinen Server starte (die for-Schleife sieht jetzt so aus: )

    for ( ; ; )
    	{
    		FD_ZERO( &filedesc );
    		FD_SET( server_socket, &filedesc );
    		FD_SET( STDIN_FILENO, &filedesc );
    
    		sel_result = select( max+1, &filedesc, NULL, NULL, NULL );
    
    		if ( FD_ISSET( server_socket, &filedesc ) )
    		{
    			if( ( bytes = recvfrom( server_socket, buffer, sizeof(buffer), 0, NULL, NULL ) ) == -1 )
    			{
    				fprintf( stderr, "%s: recvfrom() failure!\n", argv[0] );
    				close( server_socket );
    				exit( EXIT_FAILURE );
    			}
    			if ( buffer[bytes-1] != '\0' )
    				buffer[bytes] = '\0';
    
    			fprintf( stdout, "[Client]: %s\n", buffer );
    			/* break; */
    		}
    		else if ( FD_ISSET( STDIN_FILENO, &filedesc ) )
    		{
    			if ( (bytes = read( STDIN_FILENO, buffer, strlen( buffer ) ) ) == -1 )
    			{
    				fprintf( stderr, "%s: read() failure!\n", argv[0] );
    				close( server_socket );
    				exit( EXIT_FAILURE );
    			}
    
    			if ( buffer[bytes-1] != '\0' )
    				buffer[bytes] = '\0';
    
    			client_address.sin_family = AF_INET;
    			client_address.sin_addr.s_addr = inet_addr( r_addr );
    			client_address.sin_port = htons( r_port );
    
    			if( sendto( server_socket, buffer, strlen(buffer), 0, (struct sockaddr *)&client_address, sizeof(client_address) ) == -1)
    			{
    				fprintf( stderr, "%s: sendto() failure!\n", argv[0] );
    				close( server_socket );
    				exit( EXIT_FAILURE );
    			}
    		}
    		FD_CLR( server_socket, &filedesc );
    		FD_CLR( STDIN_FILENO,  &filedesc );
    	}
    

    und mir mit nc eine UDP-Nachricht zuschicke kann ich mich dann getrost alleine ueber das Programm mit der Gegenstelle unterhalten.
    Wenn ich das mit nc aber vergesse, dann gerate ich wieder in die Endlosschleife ...

    🙄 🙄 😡 😮



  • spontan wuerd ich den timeoutparameter von select() ueberpruefen. ich weiss nicht genau, ob es unendlich bei NULL oder 0.0sekunden wartet.



  • c.rackwitz schrieb:

    spontan wuerd ich den timeoutparameter von select() ueberpruefen. ich weiss nicht genau, ob es unendlich bei NULL oder 0.0sekunden wartet.

    Bringt nichts, schon probiert!

    [Edit] Ok, bringt doch was, aber noch nicht das richtige Ergebnis.
    Wenn ich jetzt was eingebe kommt es auf der Gegenseite nicht kommplett wie z.B.
    hallo
    an, sonern in der art:
    h
    a
    l
    l
    o

    Mal, schaun, vielleicht verwende ich statt strlen sizeof, muss erst kontrollieren!



  • ein/ausgabe ist nicht zeilengepuffert!



  • Och Gott, manchmal ist es schon schlimm, danke fuer den Hinweis, schon geloest. Jetzt funktionierts!



  • c.rackwitz schrieb:

    spontan wuerd ich den timeoutparameter von select() ueberpruefen. ich weiss nicht genau, ob es unendlich bei NULL oder 0.0sekunden wartet.

    Bei NULL ist die Funktion blockiert bis was passiert.



  • Im Moment macht der Timeout-Parameter keinen Unterschied!
    Es funktioniert einfach nicht mehr!
    😞
    Und zwar liegt das Problem hier:

    if( ( bytes = recvfrom( SERVER_SOCKET, buffer, strlen( buffer ), 0, NULL, NULL ) ) == -1 )
    

    Wenn ich versuche ne Struktur statt NULL, NULL mitzugeben dann kann ich nicht mehr empfangen und senden, ist mir unverstaendlich!


Anmelden zum Antworten