C Programm beendet sich einfach

Krik

Fleet Admiral Pro
Registriert
Juni 2005
Beiträge
16.978
Moin

Vorne weg: Ja, es ist eine Hausaufgabe für mich. Meine Aufgabe ist es, einen Client und einen Server zu basteln.
Das habe ich auch getan.

Allerdings habe ich ein Problem, dass ich nicht ergründen kann. Der Server beendet sich einfach unvermittelt und ich kann die Fehlerursache nicht finden.

client.c
Funktioniert einwandfrei mit dem Echo-Server, den die Hochschule zum Testen bereit hält.
Code:
#include <netdb.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <errno.h>
#define PROTO_TCP "tcp"
#define SERVICE "echo"
#define MAXLINE 512
int main( int argc, char *argv[], char *envp)
{
    struct hostent *hostInfo;
    struct servent *serviceInfo;
    struct protoent *protoInfo;
    struct sockaddr_in connection;
    char sendline[] = { "Hallo Welt!" };
    char recvline[MAXLINE + 1];
    int lauf;
    int sock;
    
    // 2. Argument ist der Hostname
    if ( argc == 2 )
    {
        // Hostinformationen abrufen.
        {
            if ( (hostInfo = gethostbyname(argv[1])) == NULL )
            {
                // Konnte keine Informationen über den Host bekommen.
                fprintf(stderr, "IP-Adresse von %s konnte nicht ermittelt werden !\n", *argv);
                return 1;
            }
            printf("Hostname: %s\n", hostInfo -> h_name);
        }
        // IP-Adresse des Hosts ermitteln.
        {
            printf("IP: ");
            for(lauf = 0; lauf < hostInfo -> h_length; lauf++)
            {
                if( lauf> 0) printf(".");
                printf("%i", (unsigned char) hostInfo -> h_addr[lauf]);
            }
            printf("\n");
        }
        // Echo-Service ansprechen.
        {
            // Socket anlegen.
            {
                protoInfo = getprotobyname(PROTO_TCP);
                sock = socket(AF_INET, SOCK_STREAM, protoInfo -> p_proto);
                // Fehlerbehandlung
		        if ( sock < 0 )
                {
                    fprintf(stderr, "Socketfehler");
                    return 1;
                }
                printf("Socket geöffnet\n");
            }
            // Verbindung herstellen, etwas senden und empfangen, Verbindung schließen.
            {
               // Verbindung herstellen.
               {
                    if ( (serviceInfo = getservbyname(SERVICE, PROTO_TCP)) == NULL )
                    {
                        fprintf(stderr, "Servicefehler.");
                        return 1;
                    }
                    memset(&connection, 0, sizeof(connection));
                    connection.sin_family = AF_INET;
                    connection.sin_addr = *(struct in_addr *)*hostInfo -> h_addr_list;
                    connection.sin_port = htons(serviceInfo -> s_port);
                    if ( connect(sock, (struct sockaddr *) &connection, sizeof(connection)) < 0 )
                    {
                        perror("Verbindungsfehler");
                        close(sock);
                        return 1;
                    }
                    printf("Verbindung hergestellt.\n");
                    fflush(stdout);
                }
                // Etwas übertragen.
                {
                    if ( send(sock, sendline, sizeof(sendline), 0) < 0 )
                    {
                        fprintf(stderr, "Sendefehler");
                        close(sock);
                        return 0;
                    }
                    printf("\"%s\" an den Server gesendet.\n", sendline);
                }
                // Etwas empfangen.
                {
                    if ( recv(sock, recvline, MAXLINE, 0) < 0 )
                    {
                        fprintf(stderr, "Empfangsfehler");
                        close(sock);
                        return 0;
                    }
                    printf("Vom Server empfangen: \"%s\"\n", recvline);
                }
                // Verbindung schließen.
                {
                    close(sock);
                }
            }
        }
        return 0;
    }
    else
    {
        printf("Syntax: ./client Hostname\n\n");
        printf("Hostname - Host- oder Domainname eines Computers,\nbei Leerzeichen in Anführungsstriche setzen.\n");
        return 0;
    }
}

server.c
Funktioniert bis zum "debug 1" (sehr weit hinten im Quelltext).
Code:
#include <netdb.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>

#define PROTO_TCP "tcp"
#define SERVICE "echo"
#define MAXLINE 512

int main( int argc, char *argv[], char *envp)
{
	struct protoent *protoInfo;
	struct sockaddr_in server, client;
	struct servent *serviceInfo;
	int sock, sock_client;
	socklen_t len;
	char recvline[MAXLINE + 1];	
	int quit = 0;
    
	// Echo-Service ansprechen.
	{
		printf("\nServer startet...\n");
		
		
		// Socket anlegen.
		{
			protoInfo = getprotobyname(PROTO_TCP);
			sock = socket(AF_INET, SOCK_STREAM, protoInfo -> p_proto);

			// Fehlerbehandlung
			if ( sock < 0 )
			{
				fprintf(stderr, "Socketfehler");
				return 1;
			}
			
			printf("Socket angelegt.\n");
		}
			
		// Socket binden
		{
			if ( (serviceInfo = getservbyname(SERVICE, PROTO_TCP)) == NULL )
			{
				fprintf(stderr, "Servicefehler.");
				return 1;
			}
				
			memset(&server, 0, sizeof(server));
			server.sin_family = AF_INET;
			server.sin_addr.s_addr = htonl(INADDR_ANY);
			server.sin_port = htons(serviceInfo -> s_port);
				
			if ( bind(sock, (struct sockaddr*) &server, sizeof(server)) < 0 )
			{
				// Fehlerbehandlung
				fprintf(stderr, "Bind-Fehler");
				return 1;
			}
			
			printf("Socket-Bind ausgefuehrt.\n");
		}
			
		// Warteschlange einrichten
		{
			if ( listen(sock, 5) == -1 )
			{
				// Fehlerbehandlung
				fprintf(stderr, "Listen-Fehler");
				return 1;
			}
			
			printf("Warteschlange eingerichtet.\n");
		}
		
		printf("Server bereit.\n\n");
	}
	
	// Socket abhoehren
	{
		while ( quit == 0 )
		{
			// Eingehende Verbindung akzeptieren
			len = sizeof(client);
			sock_client = accept(sock, (struct sockaddr*) &client, &len);
			
			if (sock_client <= 0)
			{
				// Fehlerbehandlung
				fprintf(stderr, "Clientverbindung fehlgeschlagen. Server laeuft weiter.");
			}
			else
			{
				// Daten vom Clienten empfangen.
				{
					if ( recv(sock_client, recvline, MAXLINE, 0) < 0 )
					{
						fprintf(stderr, "Empfangsfehler.");
						quit = 1;
					}
				
					printf("Vom Clienten empfangen: \"%s\"\n", recvline);
				}
				[COLOR="Red"]printf("debug 1\n");[/COLOR]
				
				// Antwort an den Clienten schicken.
				{ printf("debug 2");
					if ( send(sock, recvline, sizeof(recvline), 0) < 0 )
					{
						fprintf(stderr, "Sendefehler.");
						quit = 1;
					}
					
					printf("Antwort an den Clienten gesendet.\n");
				}
				printf("debug 3\n");
				// Verbindung zum Clienten unterbrechen.
				{
					close(sock_client);
					printf("Verbindung zum Clienten getrennt.\n\n");
				}
			}
		}
	}
	
	// Server beenden.
	{
		printf("Server wird beendet...\n");
	
		if ( sock_client >= 0 )
			close(sock_client);
		
		if ( sock >= 0 )
			close(sock);
			
		printf("Server beendet.\n\n");
	}
}
Ausgabe des Clienten:
$ ./client localhost
Hostname: localhost.localdomain
IP: 127.0.0.1
Socket geöffnet
Verbindung hergestellt.
"Hallo Welt!" an den Server gesendet.
Vom Server empfangen: ""
An der roten Stelle sollte eigentlich "Vom Server empfangen: Hallo Welt!" stehen. Der Server sendet aber offenbar keine Antwort, weswegen der String leer bleibt.


Ausgabe des Servers:
$ ./server

Server startet...
Socket angelegt.
Socket-Bind ausgefuehrt.
Warteschlange eingerichtet.
Server bereit.

Vom Clienten empfangen: "Hallo Welt!"
debug 1
Das ist mir völlig unverständlich. Hier müsste mehr ausgegeben werden, aber das Programm ist da einfach zuende.


Ich muss wohl blind sein. Erkennt jemand, warum er an dieser Stelle das Programm einfach ohne Fehlermeldung abbricht?

Gruß, Laurin
 
Ähm, ich würde einfach an der Stelle mit dem String einen Breakpoint setzen und mal schaun, ob überall das drin steht, was drin stehen soll?
 
Also, printf("Debug 2"); funktioniert nicht mehr?

Mich wundert als allererstes die geschweifte Klammer davor. Kann es sein, dass die da nicht hin gehört und deswegen nichts funktioniert?

edit: Blödsinn. Ich seh grad, ihr macht das anders als wir und setzt auch ganze Blöcke in Klammern. Sorry :)
 
Was mir auf den ersten Blick auffält, ist der send() call in server.c. Im speziellen:
if ( send(sock, recvline, sizeof(recvline), 0) < 0 )

Wieso der send() auf den eigenen fd? Du willst doch die Message an den Client schicken. Von daher solltest du in dem send() als erstes Argument sock_client verwenden.
 
@MicahelV8
Stimmt, da habe ich was falsches geschrieben. Das muss vom Copy'n'Paste übrig geblieben sein.

@DrToxic
Ich tue sehr gerne alles, was zusammen gehört, in einen Block. Ich finde das übersichtlicher so.
Das "debug 2" gibt er nicht aus. Auch das "debug 3" kommt nicht. Aber da ist gar nichts dazwischen, was das Programm in irgendeiner Form zum Abbrechen zwingen könnte. Ich raff' das nicht.

@Wehrwolf
Ich programmiere auf der Kommandozeile mit nano und dem gcc. Den Luxus eines Breakpoints habe ich nicht. ^^
 
Zuletzt bearbeitet:
Das die folgenden printfS nicht ausgeegeben werden, kann durchaus damit zusammenhängen, dass du zwischenzeitlich den send auf den eigenen filedescriptor ausgeführt hast. Teste das mal, ob es mit dem korrigierten Code funktioniert.

Ich programmiere auf der Kommandozeile mit nano und dem gcc. Den Luxus eines Breakpoints habe ich nicht. ^^

Den Luxus hast du durchaus. Das geht sehr einfach mit GDB ;-)
 
Du hattest Recht. Es lag an dem send. Oh Mann...

Danke für eure Hilfe. :)
 
e-Laurin schrieb:
@DrToxic
Ich tue sehr gerne alles, was zusammen gehört, in einen Block. Ich finde das übersichtlicher so.

Keine schlechte Angewohnheit. :) Würde auch später enorm dabei helfen, bestimmte Teile in separate Funktionen auszulagern.
 
C ist eine der wenigen Sprachen, die so was erlauben. Also wird's angewendet. ;)
 
e-Laurin schrieb:
C ist eine der wenigen Sprachen, die so was erlauben. Also wird's angewendet. ;)

Da irrst du.. in C ist es syntaktisch erlaubt, da jedes Statement auch ein Block sein kann.
Das heißt aber noch lange nicht, dass es ein guter Programmierstil ist.

edit//in Java ist es übrigens auch erlaubt. Ebenso wie in vielen anderen Sprachen.
 
Zuletzt bearbeitet:
Wertlose Aussage, weil du kein Argument und kein Beispiel bringst.
 
IceMatrix schrieb:
Ich programmiere seit 15 Jahren C und C++. Ich kann dir sagen, dass solche Blockkonstruktionen dort nicht üblich sind. Punkt.

Was 'üblich' oder nicht üblich ist, ist hier erst mal nicht von Belang, denn das würde ja heißen, daß überall üblicherweise, sauberer, guter Code geschrieben wird, und dem ist ja wohl mal bei Weitem nicht so.

Ich selbst verwende in C++ ebenfalls sehr häufig separate Blöcke; manchmal einfach, um die verschiedenen logischen Teile einer Funktion besser zu veranschaulichen (obwohl ich noch häufiger solche Teile einfach in eine eigene Funktion packe); manchmal auch, weil es einfach nötig ist, um einer bestimmen lokalen Variable ein begrenzteres Scope zu geben als die umgebende Funktion (z.B. wenn man scoped locks zum Locken / Freigeben von Mutexes verwendet).

Im übrigen wird in C++ explizit dazu geraten, lokalen Variablen den kleinstmöglichen Gültigkeitsbereich zu verpassen ... also so nahe wie möglich bei ihrer ersten Verwendung zu deklarieren / initialisieren und sie auch so bald wie möglich wieder aus ihrem Gültigkeitsbereich fallen zu lassen. Das beste Mittel dafür ist eine eigene Funktion ... das zweitbeste sind Blöcke.
Ich bin zwar selber nur in C++ tätig ... C ist eher nicht so mein Ding, aber ich sehe keinen Grund, warum man das in C nicht genauso tun könnte. Schlechter Stil ist das keineswegs ... im Gegenteil, Blöcke NICHT zu verwenden, würde ich als schlechten Stil betiteln.


EDIT: Zum Nachlesen für Leute, die mir das nicht glauben wollen. ;)

http://htmlcoderhelper.com/what-is-the-purpose-of-anonymous-blocks-in-c-style-languages/
 
Zuletzt bearbeitet:
Problem schon gelöst? Falls nicht, vielleicht tuts ein system("pause") am Ende? Habe irgendwo gesehen das du es debugst und beispielsweise VS2010 macht da keine Automatischen stops mehr.
 
Das Problem ist schon gelöst. Es hat sich jetzt allerdings eine Diskussion aufgetan, ob die Block-Programmierung jetzt gut oder schlecht ist.
 
Zurück
Oben