[C con Clase] problema con sockets

Programante programante en gmail.com
Jue Ene 31 12:54:41 CET 2008


nree escribió:
> Hola gente!!!
>
> trabajo con eclipse en un ubuntu y estoy haciendo un programilla con sockets. Para empezar lo de siempre, un servidor concurrente y un cliente que pide peticiones. Mi problema viene al crear los procesos hijos, se supone que envian al cliente un saludo y listo, pero... me tira el perror al hacer el send y despues de un rato lo hace. Es decir, me explico, el servidor se queda un rato con "bad file descriptor" y despues aparece en el cliente el mensaje. Y ademas la concurrencia no funciona. 
>
> Os dejo los codigos...
>
> servidor.cpp
>
> int main(void) {
> 	
> 	int sock;
> 	int sock_dialog;
> 	struct sockaddr_in dir_ser; 
> 	struct sockaddr_in dir_cli;
> 	int numbytes;// numbytes2;
> 	int yes=1;// conectado=0;
> 	socklen_t len;
> 	char buf[TAMBUF];
> 	//char buf2[TAMBUF];
> 	
> 	
> 	sock = socket(PF_INET, SOCK_STREAM,0);
> 	if (sock < 0)
> 	{
> 		perror("error de creación de socket");
> 		//exit(1);
>   
Yo compararía con -1. En Linux da igual pero en otros sistemas podría 
haber valores negativos distintos de -1 que sean válidos.
Como tienes comentados todos los exit(), en caso de fallo se ejecutará 
una ruta de código no deseada (probablemente fallando todo).
> 	}
> 	else
> 	{
> 		puts("socket creado...");
> 	}
> 	
> 	dir_ser.sin_family = PF_INET;
> 	dir_ser.sin_addr.s_addr = htonl (INADDR_ANY);
>   
INADDR_ANY no hace falta pasarlo a través de htonl(), pero no pasa nada.
> 	dir_ser.sin_port = htons (PORT);	
> 	memset(dir_ser.sin_zero, '\0', sizeof dir_ser.sin_zero);
> 	
> 	if (setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1)
> 	{
> 		perror("setsockopt");
> 		//exit(1);
> 	}
> 	
> 	if (bind(sock, (struct sockaddr *)&dir_ser,sizeof dir_ser)< 0)
> 	{
> 		perror("error en la asignación de dirección");
> 		//exit(1);
> 	}
> 	else
> 	{
> 		puts("asignando direccion...");
> 	}
> 	
> 	if (listen (sock, NUM_CON) < 0)
> 	{
> 		perror("error en la escucha");
> 		//exit(1);
> 	}else
> 		puts("socket a la escucha...");
> 	
> 	while(1)
> 	{
> 		len = sizeof dir_ser;
> 		sock_dialog = accept(sock, (struct sockaddr *) &dir_cli, &len);
> 		if (!fork())
> 		{
> 			shutdown(sock,2);
> 			strcpy(buf, "respuesta desde servidor...");
> 			numbytes = send (sock_dialog, buf, sizeof(buf), 0);
>   
En vez de sizeof(buf), creo que quieres hacer strlen(buf) o 
strlen(buf)+1 dependiendo de si quieres enviar el caracter nulo o no.
> 			if (numbytes < 0)
> 			{
> 				perror("error en la transmision de datos...");
> 			}
> 			//tramitarChat((struct sockaddr_in *)sock_dialog);
>   
aquí deberías finalizar el proceso hijo, para que no se quede atrapado 
en el bucle diseñado para el padre.
sock_dialog es un socket, de tipo int, no hagas un casting a (struct 
sockaddr_in *), usa dir_cli
> 		}
> 		shutdown(sock_dialog,2);
> 	}
> }
>   
> cliente.cpp
>
> int main (int argc, char *argv[])
> {
> 	int sock, i;
> 	struct sockaddr_in dir_serv;
> 	char buf[TAMBUF];
> 	
> 	sock = socket (PF_INET, SOCK_STREAM, 0);
> 	if (sock < 0)
> 	{
> 		perror("No se ha podido crear el socket");
> 		exit (-1);
> 	}else
> 		puts ("socket creado...");
> 	
> 	dir_serv.sin_family = PF_INET;
> 	dir_serv.sin_port = htons (PORT);
> 	inet_aton(argv[1], &(dir_serv.sin_addr)); 
> 	memset(dir_serv.sin_zero, '\0', sizeof dir_serv.sin_zero);
> 	
> 	if (connect (sock, (struct sockaddr*)&dir_serv, sizeof dir_serv) <0)
> 	{
> 		perror("conexión no aceptada");
> 		exit(-1);
> 	}else
> 		puts("conectando con el servidor...");
> 	
> 	i = recv (sock, buf, sizeof(buf),0);
>   
Esto se bloqueará hasta que se llene el buf. Dado que estamos a un nivel 
básico, puedes probar
while ((recv (sock, buf, 1,0) > 0) && buf[0]) putchar(buf[0]);
> 	puts(buf);
>   
Si decides no enviar el caracter nulo, no pudes usar puts(). Siempre es 
recomendable utilizar el valor de bytes recibidos. write(1, buf, i);
> 	shutdown(sock,2);	
> } 
>
>   
Todos los usos de shutdown() deberían ser close()
> gracias por vuestra colaboracion
>   
De nada :)
> nere





Más información sobre la lista de distribución Cconclase