Vistas: 1049
Tiempo de lectura:4 Minutos, 36 Segundos

Creando el cliente

El cliente es quien se conectará al servidor, quien enviará mensajes y recibirá mensajes de otros clientes. En principio como debe ser una sala de chat.

Librerías:

Algunas de las librerías que estaremos utilizando seran estas:

#include <stdio.h> – Contiene las definiciones de las macros, las constantes, las declaraciones de funciones de la biblioteca estándar del lenguaje de programación C para hacer operaciones, estándar, de entrada y salida.

#include <stdlib.h> – Biblioteca estándar de propósito general del lenguaje de programación C. Contiene los prototipos de funciones de C para gestión de memoria dinámica, control de procesos y otras.

#include <string.h> – Contiene algunas funciones y tipos y algunas operaciones de manipulación de memoria.

#include <unistd.h> – Define constantes y tipos simbólicos misceláneos, y declara funciones misceláneas.

#include <sys/types.h> – Define algunos tipos adicionales.

#include <sys/socket.h> – Define alguno tipos y macros para establecer una conexión con otro ordenador que nos permitirá intercambiar datos.

#include <netinet/in.h>

#include <arpa/inet.h>

#include <pthread.h> – Define algunas funciones y tipos para manejar procesos hijos o hilos dentro de nuestros programas.

#include “commons.h” – define algunas funciones comunes que utilizaremos en el proyecto.

Funciones:

void emisor(); //maneja los mensajes de entrada 
void receptor(); //maneja los mensajes de entrada 
int main(int argc, char **argv);

Las funciones del codigo del cliente se explican por sí solas, tendremos un proceso central en el main que será el encargado de configurar y establecer inicialmente una conexión con el servidor, mientras que las otras funciones son hilos apartes encargados de manejar los mensajes entrantes y salientes.

Función main

La primera parte, la definición misma de la función y tal vez muchos iniciados en el lenguaje nunca la hayan visto, son esos dos argumentos de la función.

int main(int argc, char **argv)

Y es de saber que la función recibe dos parámetros, un número y un array de punteros a caracteres. Estos argumentos vienen desde cuando se ejecuta el programa desde una consola y se le pasan lo que llamamos argumentos del sistema.

De esta manera al ejecutar la linea “./client 8000” le estariamos mandando los siguientes datos a la función main. 

argc argv
2 [“./client”,”8000”]

Una vez aclaramos esto, utilizamos esta función, para pasarle directamente el puerto de la máquina al que queremos que se conecte.

if (argc != 2)
    {
        printf("Uso: %s \n", argv[0]);
        return EXIT_FAILURE;
    }
 
    char *ip = "127.0.0.1";
    int port = atoi(argv[1]); //Convierte string a int

Se define la ip del servidor, que como estamos en la misma máquina, es la ip local y procedemos a configurar la conexión del socket.

struct sockaddr_in server_addr;
 
// Configuracion del Socket 
sockfd = socket(AF_INET, SOCK_STREAM, 0);
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr(ip);
server_addr.sin_port = htons(port);

Todas estas son configuraciones necesarias a la hora de conectarnos a la red ya sea local, entre varias máquinas o a la internet. Entonces estaría listo para conectarse:

int err = connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
if (err == -1)
{
   printf("ERROR: conectando\n");
   return EXIT_FAILURE;
}

Connect es una librería de socket que intenta establecer una conexión a la dirección ip y el puerto que se le designaron, si la conexión es fallida, devuelve un -1. Una vez exitosa la conexión se lleva a cabo el primer mensaje al servidor, que es el nombre de usuario que se pidió anteriormente. Se crean 2 hilos para manejar tanto las comunicaciones entrantes y salientes.

send(sockfd, name, 32, 0);
 
printf("=== Bienvenido a la sala de chat ===\n");
pthread_t hilo_emisor; //Creacion del hilo emisor
 
if (pthread_create(&hilo_emisor, NULL, (void *)emisor, NULL) != 0)
{
    printf("ERROR: pthread  - Hilo del emisor\n");
    return EXIT_FAILURE;
}
 
pthread_t hilo_receptor; //Creacion del hilo receptor
if (pthread_create(&hilo_receptor, NULL, (void *)receptor, NULL) != 0)
{
    printf("ERROR: pthread - Hilo del receptor\n");
    return EXIT_FAILURE;
}

Ya al final este proceso quedará en un bucle infinito y para desconectarse del chat será con Ctrl+C.

Función Emisor

Una vez establecida la conexión con el servidor el hilo emisor llama a la función emisor y esperará hasta que el usuario realice una entrada en el teclado.

void emisor()
{
    char message[LENGTH] = {};
    char buffer[LENGTH + 32] = {};
 
 
    while (1)
    {
        memset(message, 0, LENGTH); //resetea el buffer de mensajes
        memset(buffer, 0, LENGTH+32); //resetea el buffer de mensajes
        reset_stdout();  // Vacía el búfer de salida.
 
        fgets(message, LENGTH, stdin); //captura el mensaje del usuario
        
        message[strcspn(message, "\n")] = '\0'; //elimina los saltos de linea
        
        sprintf(buffer, "%s-> %s\n", name, message);
        
        send(sockfd, buffer, strlen(buffer), 0); //envia el mensaje all servidor
    }
}

Función Receptor

Este hilo constantemente está comprobando los mensajes recibidos por el socket desde el servidor y se encarga de imprimirlos en pantalla.

void receptor()
{
    char message[LENGTH] = {};
    while (1)
    {
        int receive = recv(sockfd, message, LENGTH, 0); //recibe los mensajes del servidor
        if (receive > 0)
        {
            printf("%s", message); //Imprime los mensajes del servidor
            reset_stdout();  // Vacía el búfer de salida.
        }
        else if (receive == 0)
        {
            break;
        }
        else
        {
            // -1
        }
        memset(message, 0, sizeof(message)); //resetea el buffer de mensajes
    }
}

Y así cada vez que realice una nueva entrada, esté while infinito, enviará los mensajes, ya formateados con el nombre del emisor al servidor.

A continuación en la siguiente parte del tutorial, empezaremos con el código del servidor.