Algo de programación en Linux, hilos, sockets y semáforos.

El objetivo del siguiente post es acercar a la comunidad de programadores un código fuente de un programa que he realizado para un trabajo de la universidad.
Básicamente el programa consta de un servidor de batalla naval, y los clientes correspondientes que se conectan para jugar. El programa está hecho en C para Linux y es un programa en modo consola.

El programa se compone de un servidor que se ejecuta y se queda esperando a clientes locales o remotos que se quieran conectar para jugar a la batalla naval. Cada vez que un cliente se conecta, el servidor lanza un hilo que se encarga de atender al cliente.
Me pareció interesante poder mostrar este código, ya que se manejan conceptos como semáforos para sincronizar el uso de variables, sockets e hilos. Estimo que les puede resultar útil a todos aquellos que quieran aprender sobre el tema.
También aporto unas diapositivas que explican un poco todo el tema en general.
Más adelante explicaré detalladamente cada una de las partes más importantes sobre el código. Por lo pronto, espero que les sea útil.
Aquí les muestro el código del servidor, pero en el archivo que pueden descargar al final, están todos los archivos correspondientes al programa y el código compilado, que son los archivos que no poseen extención. Desde la consola se le deben asignar permisos de ejecución y luego con «./[NOMBRE_DEL_ARCHIVO]» comienza a correr el programa.

Diapositivas: computacion-ii-presentacion-final

Archivos:archivos_batalla_naval

Código del servidor:

/*
* Geronimo Manso
*
* Programa Servidor de batalla naval.
*/
#include ;
#include ;
#include ;
#include ;
#include ;
#include ;
#include ;
#include ;
int ON_LINE =0; //Variable que almacena la cantidad de usuarios ON_LINE
sem_t semaforo; //Declaro el semaforo que voy a utlizar para sincronizar los hilos

void *hilo1(void *args){
	/*
	* Descriptores de socket servidor y de socket con el cliente
	*/

	int Socket_Cliente = (int)args;
	char Cadena[6], coord_x[10], coord_y[10];
	int k,y,x,error;
	int puntos_ganados=0; //Barcos hundidos
	int puntos_perdidos=0;//Barcos perdidos
	char tablero[10][10];
	char tablero_disparos[10][10]; //Anota los disparos hechos por el server
	//Utilizo el semaforo e incremento la variable ON_LINE
	printf("\nDecremento el semaforo y aumento ON_LINE");
	sem_wait (&semaforo);
	ON_LINE++;
	printf("\nNuevo valor de ON_LINE: %d", ON_LINE);
	printf("\nIncremento el semaforo");
	sem_post (&semaforo);

	//Genero el tablero de la pc
	iniciar_tablero(tablero);
	iniciar_tablero(tablero_disparos);
	cargar_tablero_pc(tablero);
	mostrar_tablero(tablero);

	/*
	* Se lee la informacion del cliente, suponiendo que va a enviar
	* 5 caracteres.
	*/
	Lee_Socket (Socket_Cliente, Cadena, 6);

	/*
	* Se escribe en pantalla la informacion que se ha recibido del
	* cliente
	*/
	printf ("\nSoy Servior, he recibido : %s\n", Cadena);
	printf("\nComienza el juego.");

	/*
	* Se prepara una cadena de texto para enviar al cliente. La longitud
	* de la cadena es 5 letras + \0 al final de la cadena = 6 caracteres
	*/
	do{
	printf("\nTurno Servidor");
		//Genero una coordenada de disparo hasta llegar a una no utilizada
		do{
		x = generar_numeros();
		y = generar_numeros();
		}while(poner_barco(tablero_disparos,x,y)!=0); //Verifico y escribo que no haya disparado a ese casillero
	sleep(2);
	//Genero, muestro y envio la coordenada de disparo X
	//strcpy (Cadena,"1"); //Genero un número y realizo un cast
switch(x)
	{
		case 1:
			strcpy (Cadena,"1");
			break;
		case 2:
			strcpy (Cadena,"2");
			break;
		case 3:
			strcpy (Cadena,"3");
			break;
		case 4:
			strcpy (Cadena,"4");
			break;
		case 5:
			strcpy (Cadena,"5");
			break;
		case 6:
			strcpy (Cadena,"6");
			break;
		case 7:
			strcpy (Cadena,"7");
			break;
		case 8:
			strcpy (Cadena,"8");
			break;
		case 9:
			strcpy (Cadena,"9");
			break;
		case 10:
			strcpy (Cadena,"10");
			break;

	}
	printf("\nCoordenada de disparo x: %s\n", Cadena);
	if (Escribe_Socket (Socket_Cliente, Cadena, 2)==-1 && puntos_ganados<5)
	{

		puntos_ganados=5;
		pthread_exit(0);

	}
	sleep(2);
	//Genero, muestro y envio la coordenada de disparo Y

	switch(y)
	{
		case 1:
			strcpy (Cadena,"1");
			break;
		case 2:
			strcpy (Cadena,"2");
			break;
		case 3:
			strcpy (Cadena,"3");
			break;
		case 4:
			strcpy (Cadena,"4");
			break;
		case 5:
			strcpy (Cadena,"5");
			break;
		case 6:
			strcpy (Cadena,"6");
			break;
		case 7:
			strcpy (Cadena,"7");
			break;
		case 8:
			strcpy (Cadena,"8");
			break;
		case 9:
			strcpy (Cadena,"9");
			break;
		case 10:
			strcpy (Cadena,"10");
			break;

	}
	printf("\nCoordenada de disparo y: %s\n", Cadena);
	if (Escribe_Socket (Socket_Cliente, Cadena, 2)==-1 && puntos_ganados<5)
	{
		puntos_ganados=5;
		pthread_exit(0);

	}

	printf("\n\n");
	if (Lee_Socket (Socket_Cliente, Cadena, 2)==-1 && puntos_ganados<5)
	{
		puntos_ganados=5;
		strcpy (Cadena,"1");

	}
	k = atoi (Cadena);
	if (puntos_ganados <5)
	{
		puntos_ganados = puntos_ganados + k; //Registro si he hundido un barco o no
	}
	printf("\nDISPARO: ");
	disparo_desc(k);//Muestro la descripción si fue hundido o agua

	//SECCION ESPERANDO EL DISPARO DEL CLIENTE
	printf("\nEsperando disparo del cliente...\n");

	if (Lee_Socket (Socket_Cliente, coord_x, 2)==-1 && puntos_ganados<5)
	{
		printf("\nCliente Desconectado");
		pthread_exit(0);
		puntos_ganados=5;
		coord_x[1]="1";
		strcpy (Cadena,"1");

	}

	printf ("\nSoy Servior, Coordenada X  recibida : %d\n", x = atoi(coord_x));

	if (Lee_Socket (Socket_Cliente, coord_y, 2)==-1 && puntos_ganados<5)
	{
		coord_y[1]="1";
		puntos_ganados=5;
		strcpy (Cadena,"1");

	}

	printf ("\nSoy Servior, Coordenada Y  recibida : %d\n", y = atoi(coord_y));
	k = disparar(tablero,x,y); //Guardo en K el numero recibido
	puntos_perdidos = puntos_perdidos + k; //Registro si he perdido un barco o no
		if (k==1)
		strcpy (Cadena,"1");
		else
		strcpy (Cadena,"0");
		if (Escribe_Socket (Socket_Cliente, Cadena, 2)==-1)
		{
			puntos_ganados=5;
			strcpy (Cadena,"1");

		} //Se asigna una logintud de 2, ya que se contempla el caracter de fin de cadena
	//Muestro si me han hundido un barco
	printf("\nDisparo del cliente:");
	disparo_desc(k);
	printf("\nTus barcos perdidos son: %d",puntos_perdidos);
	printf("\nLos barcos que has hundidos son: %d", puntos_ganados);
	}while (puntos_perdidos <5 && puntos_ganados<5);
	/*
	* Se cierran los sockets
	*/
	close (Socket_Cliente);
	/*
	 * Utilizo el semaforo para decrementar ON_LINE
	*/
	printf("\nDecremento el semaforo y disminuyo ON_LINE");
	sem_wait (&semaforo);
	ON_LINE--;
	printf("\nNuevo valor de ON_LINE: %d", ON_LINE);
	sem_post(&semaforo);

return NULL;
}

main ()
{
	int Socket_Servidor;
	int Cliente;

	srand (time(NULL));//Incio la semilla del generador aleatorio
	/*
	 * Inicio el semaforo
	*/

	sem_init(&semaforo,0,1); //-->Inicializo un semaforo

	/*
	* Se abre el socket servidor, con el servicio "batalla" dado de
	* alta en /etc/services.
	*/
	signal(SIGPIPE,SIG_IGN);
	Socket_Servidor = Abre_Socket_Inet ("batalla");
	if (Socket_Servidor == -1)
	{
		printf ("No se puede abrir socket servidor\n");
		exit (-1);
	}
	else
	{ printf("\nServidor Iniciado");
	  printf("\n-----------------\n");
	}

	/*
	* Se espera un cliente que quiera conectarse
	*/

	while (Cliente = Acepta_Conexion_Cliente (Socket_Servidor))
	{
		if (Cliente == -1)
		{
			printf ("No se puede abrir socket de cliente\n");
			exit (-1);
		}
		else
		{
			printf("\n-->Nuevo Cliente conectado\n");
		}

		/* Estructura necesaria para crear un hilo */
		pthread_t mihilo1;
		/* Creamos los hilos */
		pthread_create(&mihilo1, NULL, &hilo1, Cliente);
		pthread_detach(&mihilo1);

	};

//Cierro socket Servidor
close (Socket_Servidor);
//Destruyo el semafoto
sem_destroy(&semaforo);
}

Espero que les sea de utilidad.
Saludos!

8 comentarios sobre “Algo de programación en Linux, hilos, sockets y semáforos.

  1. ngatox

    Gero, me quiero cortar el pit…. estoy preparando esto mismo para rendir compu2… buscando un algoritmo que me resuelva lo de generar el tablero valido di con tu blog.. me doy cuenta que sos vos.. y luego ensima veo que ya lo has presentado!!!!!
    Me quiero morir hace casi un mes vengo con esto!!!
    aJAJaJAJAJAjAAJ
    Igual nada que ver el codigo por suerte.. asi que seguire.. y el cliente va en java en mi caso.. lo que si espero dotar de buena inteligencia al playerCPU con estrategias y demas.
    Pero basicamente tenemos lo mismo.. sockets.. hilos… semaforos.. q culea!!!

  2. ruzca

    Pana muchas gracias por tu generosidad en verdad yo tambien estoy haciendo una tesis sobre semaforos socket e Hilos en el area de inteligencia artificial..espero que me sirva esta informacion….Saludos

  3. gari

    Ola tengo una pequeña duda al compliar el servidor.c me dice que falta o o no se encuentra el socket_servidor.h,el cliente me lo compila bien y funciona pero el servidor no y no se como se soluciona te estaria muy agradecido si me pudieses responder lo antes posible muchas gracias

  4. gari

    si no seria mucha molestia si pudieras poner paso a paso por siacaso me e comido algun paso y por eso me da error

  5. Adrian

    hola gero, te hago una consulta, pero no sé si verás el comentario, ya que pasó mucho tiempo. mi duda es la siguiente: intente compilar el código, tanto el cliente como el servidor (en ubuntu con gcc) y en un momento me dice que no encuentra una librería que declaraste nueva, por ejemplo: socket_servidor.h. como tendría que hacer para compilarla? porque yo compilo como: gcc servidor.c -o servidor.

  6. Felipe Herrera

    no funciona la compilación en el servidor :/

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *