inetd bind() Problem

dsNDesign

Erfahrenes Mitglied
Hei,
zu aller erst: Das folgende läuft unter Linux.

ich bin gerade dabei einen kleinen Webserver in C zu schreiben. Dieser soll mit inetd verwaltet werden.
Hierzu habe ich in der etc/services einen Service hinzugefügt:
Code:
ibs-test	65000/tcp			#Webserver

Dazu habe ich folgende Zeile in der inetd.conf: (NAME ersetzt durch meinem Benutzernamen)
Code:
ibs-test	stream	tcp	nowait	root	/home/NAME/Dokumente/IBS/ibs-test	ibs-test

Wenn ich den inetd nun starte und meinen Client aufrufe, erhalte ich folgende Ausgabe:
Code:
Client Socket gestartet
Socket angelegt
Verbindung hergestellt - verbunden mit Server
Bitte Nachricht zum Versenden eingeben:
Test
Nachricht gesendet
Received: bind() failed: Address already in use
Socket erstellt!

Nach "Received" sollte normalerweise wieder "Test" stehen.

Wenn ich das ganze ohne den inetd teste (mit einem anderen Port), funktioniert das ganze auch.
Und wenn ich inetd beende und den Client starte, wird auch "Verbinden fehlgeschlagen" ausgegeben. -> Die Verbindung zum Server scheint ja zu funktionieren.

netstat -nap | grep 65000 gibt folgendes aus:
Code:
tcp        0      0 0.0.0.0:65000           0.0.0.0:*               LISTEN      -               
tcp        7      0 127.0.0.1:65000         127.0.0.1:40166         CLOSE_WAIT  3580/ibs-test   
tcp        7      0 127.0.0.1:65000         127.0.0.1:40169         CLOSE_WAIT  3593/ibs-test

und hier dann noch mein Server und der Client:

Server:
Code:
#include <stdio.h>      /* for printf() and fprintf() */
#include <sys/socket.h> /* for socket(), bind(), and connect() */
#include <arpa/inet.h>  /* for sockaddr_in and inet_ntoa() */
#include <stdlib.h>     /* for atoi() and exit() */
#include <string.h>     /* for memset() */
#include <unistd.h>     /* for close() */

#define BUF_SIZE 4096
#define PORT 65000

int main(int argc, char *argv) {
	int s, c, size = 0, recvMsgSize;
	struct sockaddr_in addr;
	struct sockaddr_in cli;
	socklen_t cli_size;
	char buffer[BUF_SIZE];
	
	memset(&addr, 0, sizeof(addr));
	
	s = socket(PF_INET, SOCK_STREAM, 0);
	if (s == -1) {
		perror("Socket anlegen fehlgeschalgen!");
		return 1;
	} else {
		printf("Socket erstellt!\n");
	}
	
	addr.sin_addr.s_addr = inet_addr("127.0.0.1");
	addr.sin_port = htons(PORT);
	addr.sin_family = AF_INET;
	
	if (bind(s, (struct sockaddr*) &addr, sizeof(addr)) == -1) {
		perror("bind() failed");
		return 2;
	} else {
		printf("Binden erfolgreich\n");
	}
	
	if (listen(s, 3) == -1) {
		perror("listen () failed");
		return 3;
	} else {
		printf("Listen ...\n");
	}
	
	/* Alternative */
	for (;;) {
		/* Set the size of the in-out parameter */
		cli_size = sizeof(cli);
		
		/* Wait for a client to connect */
		if ((c = accept(s, (struct sockaddr *) &cli, &cli_size)) < 0) {
			perror("accept() failed");
			return 4;
		}
		
		/* clntSock is connected to a client! */
		printf("Handling client %s\n", inet_ntoa(cli.sin_addr));
		
		
		if ((recvMsgSize = recv(c, buffer, BUF_SIZE, 0)) < 0)
			perror("recv() failed");
			
		buffer[recvMsgSize] = '\0';
		printf("Nachricht emfangen: %s\n", buffer);
		
		/* Send received string and receive again until end of transmission */
		while (recvMsgSize > 0) {
			/* Echo message back to client */
			if (send(c, buffer, recvMsgSize, 0) != recvMsgSize)
				perror("send() failed");
			
			/* See if there is more data to receive */
			recvMsgSize = recv(c, buffer, BUF_SIZE, 0);
			if (recvMsgSize < 0)
				perror("recv() failed");
		}
		close(c);    /* Close client socket */
	}
}

Client:
Code:
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define BUF_SIZE 4096
#define PORT 65000

int main(int argc, char *argv) {
	int s, c, size = 0;
	int bytesRcvd, totalBytesRcvd;
	struct sockaddr_in addr;
	
	char buffer[BUF_SIZE];
	
	
	/*Socket anlegen*/
	printf("\nClient Socket gestartet\n");
	s = socket(PF_INET, SOCK_STREAM, 0);
	if (s == -1)
		printf("Socket Anlegen fehlgeschlagen\n");
	else
		printf("Socket angelegt\n");
		
	/*Connect*/
	/*Zieladresse festlegen*/
	addr.sin_addr.s_addr = inet_addr("127.0.0.1");
	addr.sin_family = AF_INET;
	addr.sin_port = htons(PORT);
	
	/*"Connect"*/
	c = connect(s, (struct sockaddr*) &addr, sizeof(addr));
	if (c == -1)
		printf("Verbinden fehlgeschlagen\n");
	else
		printf("Verbindung hergestellt - verbunden mit Server\n");
		
	/*Send*/
	
	printf("Bitte Nachricht zum Versenden eingeben:\n");
	fgets(buffer, BUF_SIZE, stdin);
	size = send(s, buffer, strlen(buffer), 0);
	if (size == -1)
		printf("Senden felgeschlagen\n");
	else
		printf("Nachricht gesendet\n");
	
	totalBytesRcvd = 0;
	printf("Received: "); 
	while (totalBytesRcvd < strlen(buffer)) {
		if ((bytesRcvd = recv(s, buffer, BUF_SIZE - 1, 0)) <= 0)
			perror("recv() failed or connection closed prematurely");
		totalBytesRcvd += bytesRcvd;   /* Keep tally of total bytes */
		buffer[bytesRcvd] = '\0';  /* Terminate the string! */
		printf("%s", buffer);      /* Print the echo buffer */
	}
	
	printf("\n");
	
	close(s);
	return EXIT_SUCCESS;
}

Wo könnte der Fehler liegen? Und was haben die beiden "CLOSE_WAIT" zu bedeuten?

Gruß

UPDATE:
Die Prozesse 3580 und 3593 mit Status CLOSE_WAIT habe ich inzwischen gekillt. netstat gibt dann jetzt folgendes aus:
Code:
tcp        0      0 0.0.0.0:65000           0.0.0.0:*               LISTEN      -

UPDATE2:
Wenn ich den Server direkt starte, also ohne inetd, habe ich folgendes bei netsat (Port abgeändert):
Code:
tcp        0      0 127.0.0.1:65008         0.0.0.0:*               LISTEN      11593/server

Sieht also deutlich besser aus. Funktioniert ja auch.
 
Zuletzt bearbeitet:

dsNDesign

Erfahrenes Mitglied
Ok, ich habe das Problem inzwischen lösen können.
Beim Server werden keine Sockets benötigt, da der inetd das ganze bereits übernimmt.

Habe jetzt nur noch ein kleines C Problem.

Hier der Server:
Code:
#define BUF_SIZE 4096
#define PORT 65000

#define OK "HTTP/1.0 200 OK\r\nServer: localhost\r\nContent-Type: text/xml\r\n\r\n"
#define NF "HTTP/1.1 404 Not Found\r\nServer: localhost\r\n"

int main(int argc, char *argv) {
	int c, size, recSize;
	int OKlen = strlen(OK);
	char buffer[BUF_SIZE];
	char text[BUF_SIZE-OKlen];
	char pfad[200];
	FILE *datei;
	
	if (recv(c, buffer, BUF_SIZE, 0) < 0)
		perror("recv() failed");
	
	/* Send received string and receive again until end of transmission */
	while (1) {
		sprintf(pfad, "/home/*/Dokumente/%s.xml", buffer);
		datei = fopen(pfad,"r");
		if(datei == NULL) {
			sprintf(buffer, NF);
		} else {
			fscanf(datei, "%4096c", text);
			sprintf(buffer, "%s%s", OK, text);
			fclose(datei);
		}
		size = strlen(buffer);
		/* Echo message back to client */
		if (send(c, buffer, size, 0) != size)
			perror("send() failed");
		
		/* See if there is more data to receive */
		size = recv(c, buffer, BUF_SIZE, 0);
		if (size < 0)
			perror("recv() failed");
	}
	close(c);    /* Close client socket */
}

Ich möchte den Inhalt der Datei, die ich beim Client eingebe, zurückgeben.
Wenn ich im Server den kompletten Pfad+Namen der Datei angebe, funktioniert es auch.
Wenn ich allerdings den gesendeten Namen einfügen will (siehe sprintf), geht es nicht.

Jemand ne Idee, wo der Fehler liegen könnte?
 

sheel

I love Asm
Was bedeutet "funktioniert nicht" genau?
Fehlermeldungen, Verhalten...?

Hast du dir pfad vor dem fopen mal ausgeben lassen,
ob auch das Richtige drinsteht?

Zwei weitere Sachen:
a) Es ist nicht garantiert, mit einem recv genau den Dateinamen zu bekommen,
nur weil er vllt. mit einem send gesendet wurde.
Es kann eine beliebige Byteanzahl zwischen 1 und dem Maximalen kommen.
Ggf. muss man also was wegschneiden
oder in einer Schleife mehrere recv machen, um genug Daten zu haben
(der Returnwert, wenn positiv, ist die Byteanzahl).
Dafür muss man dann aber auch erst mal wissen, wie viel Byte der Dateiname hat
bzw. ob es am Schluss irgendein eindeutiges Trennzeichen gibt (\n ...)

b) Du hast einige mögliche Überlaufe im Programm
(wo ein Array also zu klein für den Inhalt sein könnte
und du es nicht prüfst bzw. das Beschreiben nicht verhinderst).
Sowas macht beim Auftreten lustige Fehler, von der Kategorie "gibts doch gar nicht".
 

dsNDesign

Erfahrenes Mitglied
Das Problem war, dass er die Datei nicht gefunden hat. Hat mir also "HTTP/1.1 404 Not Found\r\nServer: localhost\r\n" zurückgegeben.
Habs aber jetzt hinbekommen:
Code:
wort = strtok(buffer, "\r\n");
strcpy(datein, wort);
sprintf(pfad, "/home/*/Dokumente/%s.xml", datein);

Das mit der Größe der chars und dass ich evt nicht alles empfange, ist mir klar. Will das später noch abändern, indem ich unter anderem prüfe, ob noch weitere Bytes kommen.