duda socket

Iniciado por Maik33, 15 Enero 2012, 16:23 PM

0 Miembros y 1 Visitante están viendo este tema.

Maik33

Hola, tengo una duda de como hacer un "mini chat" en C para linux.

Se manejar los sockets, como hacer para que cliente y servidor se manden mensajes entre ellos.
Pero, lo que yo quiero hacer es que en el servidor se conecten varios clientes, y que los clientes se manden mensajes entre ellos.

Para hacer esto se puede hacer que los clientes se conecten al mismo puerto?
Cada vez que se conecte un cliente habría que hacer un proceso/hilo para atenderle?
Gracias.

Maik33

Hola, siento auto-responderme, pero ya he conseguido hacer un servidor que acepte n clientes. Os dejo el codigo:
Codigo del servidor:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#define MYPORT 3490    /*Numero de puerto donde se conectaran los clientes*/
#define BACKLOG 10     /* Tamaño de la cola de conexiones recibidas */
#define MAX 150

main(){
  int sockfd;                 /* El servidor escuchara por sockfd */
  int newfd;                    /*  las transferencias de datos se realizar mediante newfd */
  struct sockaddr_in my_addr;                       /* contendra la direccion IP y el numero de puerto local */
  struct sockaddr_in their_addr;                     /* Contendra la direccion IP y numero de puerto del cliente */
  int sin_size;                                                         /* Contendra el tamanio de la escructura sockaddr_in */
  char texto[MAX];
  int nbytes;
 
  if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) /*Crea un socket y verifica si hubo algun error*/
  {
    perror("socket");
    exit(1);
  }
  /* Asignamos valores a la estructura my_addr para luego poder llamar a la funcion bind() */
  my_addr.sin_family = AF_INET; /*no debe convertirse a  network byte order, es solo utilizado por el kernel*/
  my_addr.sin_port = htons(MYPORT); /*debe convertirse a network byte order porque es enviado por la red*/
  my_addr.sin_addr.s_addr = INADDR_ANY;    /* automaticamente usa la IP local */
  bzero(&(my_addr.sin_zero), 8);        /* rellena con ceros el resto de la estructura */
  /* Le asignamos un nombre al socket */
  if ( bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1){
    perror("bind");
    exit(1);
  }
  /* Habilitamos el socket para recibir conexiones, con una cola de 5 conexiones en espera como maximo */
  if (listen(sockfd, BACKLOG) == -1){
    perror("listen");
    exit(1);
  }
 
  while(1)                          /* loop que llama a accept() */
  {
    sin_size = sizeof(struct sockaddr_in);
    /*Se espera por conexiones ,*/
    if ((newfd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size)) == -1){
      perror("accept");
      continue;                /* Si se produce un error se finaliza el programa */
    }
    printf("server:  conexion desde:  %s\n", inet_ntoa(their_addr.sin_addr));
    /* Llamamos a fork() para crear un proceso hijo que atendera a la conexion recien establecida
    El proceso hijo sera igual que el padre, hereda los descriptores de sockets, lo unico que los diferencia
    es el valor devuelto por fork(), al padre le devuelve el PID del hijo , y al hijo le devuelve un
    valor cero .  Por eso, para saber si estamos en el proceso padre o hijo, comparamos el valor
    devuelto por fork().  Si fork devuelve cero, entonces estamos en el proceso hijo.  Ver la pagina
    del manual de fork. */
     if (!fork()){
       /* Aca comienza el proceso hijo, enviamos los datos mediante newfd */
       if(send(newfd,"Bienvenido al servidor\n",23,0)==-1)
perror("send");
       if((nbytes=recv(newfd,texto,MAX,0))==-1){
perror("recv");
exit(-1);
       }
       texto[nbytes]='\0';
       while(strcmp(texto,"salir\0")!=0){
printf("%s:%s\n",inet_ntoa(their_addr.sin_addr),texto);
if((nbytes=recv(newfd,texto,MAX,0))==-1){
   perror("recv");
   exit(-1);
}
texto[nbytes]='\0';
       }
       close(newfd);
       printf("Desconexion\n");
       exit(0);
     }
    /* El proceso padre no necesita este descriptor, solo lo utiliza el proceso hijo, en la proxima llamada a
    accept(), retornara con un nuevo descriptor de socket */
    close(newfd);
    /* Se suspende la ejecucion del proceso padre hasta que finalice el proceso hijo */
    while(waitpid(-1,NULL,WNOHANG) > 0);
    /* Una vez finalizado el proceso hijo, se vuelve a llamar a accept() */
  }
}


Codigo cliente(s):
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#define PORT 3490                            /* El puerto donde se conectara */
#define MAXDATASIZE 150     /* maxima cant. De bytes que se pueden recibir en una llamada a recv */

int main(int argc, char *argv[]){
  int sockfd, numbytes;                /* Contendra el numero de bytes recibidos despues de llamar a recv() */
  char buf[MAXDATASIZE];            /* Buffer donde se reciben los datos */
  struct hostent *he;                               /* Se utiliza para convertir el nombre del host a su direccion IP */
  struct sockaddr_in their_addr;         /* direccion del server donde se conectara */
  /* Tratamiento de la linea de comandos. */
  if (argc != 2){
    fprintf(stderr,"usage: client hostname\n");
    exit(1);
  }
  /* Convertimos el nombre del host a su direccion IP */
  if ((he=gethostbyname(argv[1])) == NULL){
    error("gethostbyname");
    exit(1);
  }
  /* Creamos el socket */
  if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){
    perror("socket");
    exit(1);
  }
  /* Establecemos their_addr con la direccion del server */
  their_addr.sin_family = AF_INET;
  their_addr.sin_port = htons(PORT);
  their_addr.sin_addr = *((struct in_addr *)he->h_addr);
  bzero(&(their_addr.sin_zero), 8);
  /* Intentamos conectarnos con el servidor */
  if (connect(sockfd, (struct sockaddr *)&their_addr, sizeof(struct sockaddr)) == -1){
    perror("connect");
    exit(1);
  }
  /* Recibimos los datos del servidor */
  if ((numbytes=recv(sockfd, buf, MAXDATASIZE, 0)) == -1){
    perror("recv");
    exit(1);
  }
  /* Visualizamos lo recibido */
  buf[numbytes] = '\0';
  printf("Recivido: %s\n",buf);
  /* Devolvemos recursos al sistema */
  do{
    printf("> ");
    scanf("%[^\n]",buf);
    getchar();
    if(send(sockfd,buf,strlen(buf),0)==-1){
      printf("Error\n");
      perror("send");
    }
  }while(strcmp(buf,"salir\0")!=0);
  close(sockfd);
  return 0;
}


De momento lo unico que hacen los clientes mandar mensajes al servidor y el servidor imprime en pantalla en mensaje de cada uno. Ahora mi duda es la siguiente:
cuando llegue un nuevo mensaje al servidor este mande ese mensaje a todos los conectados al servidor. Como puedo saber quienes estan conectados al servidor?
Gracias