/
Inicio :: Foros

 F.A.Q.F.A.Q.                  Conéctese para revisar sus mensajesConéctese para revisar sus mensajes   

Chat Servidor-Cliente !! Ayuda en algunas partes del codigo!
Ir a página 1, 2  Siguiente
 
      Índice del Foro elrincondelc.com -> Programación en Servidores
Ver tema anterior :: Ver siguiente tema  
AutorMensaje
Diabliyo



Registrado: 14 Abr 2004
Mensajes: 317
Ubicación: En la Luna

MensajePublicado: 05/03/2007 10:39 pm
Título: Chat Servidor-Cliente !! Ayuda en algunas partes del codigo!

Hola:

Estoy realizando un chat a nivel Consola, utilizo la plataforma Linux (distro Slackware) y esto haciendo un solo ejecutable para poder utilizarlo o iniciarlo ya sea como Servidor o como Cliente.

Ya tengo lista la parte logica del servidor, utilizando la funcion SELECT() chequeo si existen datos por leer en algun socket de los clientes conectados, y posteriormente envio la informacion del socket que envia, hacia los demas Sockets Clientes.

El unico problema es la logica cuando quiero inciar el programa como Cliente, estoy batallando un poco para saber como hacer que el Cliene haga 2 tareas, ejemplo:

1- Si existen datos en el socket por leer, pues que los lea y muestre en ventana (oviamente SELECT() soluciona el problema).

2- En caso que NO existan datos por leer, que monitoree o bien cheque que el usuario este escribiendo algo para ser enviado al chat (el mensaje).

He aqui mi problema....

Intente utilizar la funcion alarm(segundos), pero esta no respeta que el usuario este escribiendo algo (fgets()), simplamente al sobre pasar el tiempo en segundos, este envia una senal y finaliza la aplicacion.

La unica que se me ocurre es que fgets() NO se bloquee, osea que fgets() no se quede esperando datos del usuario, en caso que NO existan datos, que este continue con sus operaciones.

Pero mi pregunta seria: Como Hago a fgets() no bloqueante ???...

byee
_________________

Volver arriba
rir3760



Registrado: 01 Oct 2004
Mensajes: 3841
Ubicación: Mexico

MensajePublicado: 06/03/2007 7:36 am
Título:

No es posible ya que conceptos como multiples hilos de ejecucion y funciones re-entrantes no existen en el lenguaje C y su biblioteca estandar.

Tienes que utilizar extensiones provistas por el compilador y/o SO.

Un saludo
_________________
The capacity to learn is a gift;
The ability to learn is a skill;
The willingness to learn is a choice.
--
Rebec of Ginaz
Volver arriba
tonilope



Registrado: 16 Oct 2005
Mensajes: 249

MensajePublicado: 06/03/2007 7:37 am
Título:

Yo usaría HILOS. De hecho, aquí así lo hice y funcionó muy bien.

Tuto de hilos -> http://www.chuidiang.com/clinux/procesos/procesoshilos.php

Salu2 Wink
_________________
Be (void *) my friend
Volver arriba
Diabliyo



Registrado: 14 Abr 2004
Mensajes: 317
Ubicación: En la Luna

MensajePublicado: 08/03/2007 11:02 pm
Título:

tonilope escribió:
Yo usaría HILOS. De hecho, aquí así lo hice y funcionó muy bien.

Tuto de hilos -> http://www.chuidiang.com/clinux/procesos/procesoshilos.php

Salu2 Wink


Hola:

Oyes esta muy chido el programa que hiciste de cateaitor, es justamente lo que pretendo hacer yo, pero como veo, por mas que analizo el code, aun no logro entenderlo :S, ya que no tiene mucha explicacion al parecer y bueno... como kiera me imprimie el code e ire analizandolo poco a poco !!...

Ya hasta me siento Embarassed al mostrarte mi code Razz jijiji, apenas empeze hace 3 dias mi chat (tipo el tuyo), pero me interesaria aprender como le haces para eso que hiciste con chateitor.... Acaso usaste hilos ???... porke aun no leo todo el code, ya que apenas HOY lo baje !!!...

En cuestion pues mis unica dos preguntas son:

1- usaste solo hilos ??
2- utilizaste la funcion select() ??

byee
_________________

Volver arriba
tonilope



Registrado: 16 Oct 2005
Mensajes: 249

MensajePublicado: 09/03/2007 7:03 am
Título:

Hola. Pues yo uso 2 hilos. Uno para enviar y otro para recibir. Así de simple. En mi caso, no uso select() ya que el chat sólo admite una conexión al mismo tiempo entre servidor y cliente. Si tienes dudas concisas, pregúntalas.

Salu2 Wink
_________________
Be (void *) my friend
Volver arriba
Diabliyo



Registrado: 14 Abr 2004
Mensajes: 317
Ubicación: En la Luna

MensajePublicado: 09/03/2007 4:09 pm
Título:

tonilope escribió:
Hola. Pues yo uso 2 hilos. Uno para enviar y otro para recibir. Así de simple. En mi caso, no uso select() ya que el chat sólo admite una conexión al mismo tiempo entre servidor y cliente. Si tienes dudas concisas, pregúntalas.

Salu2 Wink


Ok, estre leyendo el codigo y entendiendolo para preguntar de una forma mas solida, solo tengo una ultima duda antes de empezar a imprimirme el code jojojo !!!..

Me imagino que utilizaste un socket no-bloqueado, osease para no tener que estar esperando por un recv ??? cierto ????

byee
_________________

Volver arriba
tonilope



Registrado: 16 Oct 2005
Mensajes: 249

MensajePublicado: 09/03/2007 4:25 pm
Título:

Cita:
Me imagino que utilizaste un socket no-bloqueado, osease para no tener que estar esperando por un recv ??? cierto ????


Justo al "verrés" Smile Un hilo está continuamente esperando con recv(), mientras que el otro está a la espera de que el usuario teclee algo y lo envíe son send().

Me piro a dormir que mañana madrugo.

Salu2 Wink
_________________
Be (void *) my friend
Volver arriba
Diabliyo



Registrado: 14 Abr 2004
Mensajes: 317
Ubicación: En la Luna

MensajePublicado: 19/03/2007 10:06 am
Título:

Bueno... He realizado un programaita de ejemplo muy simple para ver si asi va el uso de Hilos en Sockets sobre Linux !!!.... Aki dejo las 3 funciones para que chequen el poke de mi error al intentar realizar el objeto despues de haber compilado:

Error:
Código:
shell# gcc -c 007_2.c
shell# gcc -o 007_2 007_2.o
007_2.c(.text+0x3ef):In function 'inicia_servidor'
: undefined reference to 'pthread_create'
007_2.c(.text+0x438):In function 'inicia_servidor'
: undefined reference to 'pthread_create'


- inicia_servidor :: funcion que inicia el servidor y crea 2 hilos, donde 1 hilo estara reciviendo datos (recv) y el 2do hilo estara tomando datos del teclado y enviandolos al cliente de forma directa.

- recivir_datos :: funcion que invoca a recv() e imprime datos.

- enviar_datos :: funcion que espera datos del teclado para despues enviarlos (send()).

Funcion inicia_servidor:
Código:
void inicia_servidor( void )
   {
   int sockds, clientds, bytes_r=0;
   struct sockaddr_in servidor;
   struct sockaddr_in cliente;
   int size_c=0, aux=1;
   pthread_t hilo_s, hilo_r;

   servidor.sin_family= AF_INET;
   servidor.sin_port= htons(PUERTO);
   inet_aton( "127.0.0.1", &servidor.sin_addr );
   memset( &servidor.sin_zero, '\0', 8 );

   if( (sockds=socket( AF_INET, SOCK_STREAM, 0 ))==-1 )
      fprintf( stderr, "\nProblemas para Crear Socket :: %s", strerror(errno) );
   else
      {
      if( setsockopt( sockds, SOL_SOCKET, SO_REUSEADDR, &aux, sizeof(int) )==-1 )
         fprintf( stderr, "\nProblemas para Reutilizar Direccion :: %s", strerror(errno) );

      if( bind( sockds, (struct sockaddr *)&servidor, sizeof(struct sockaddr) )==-1 )
         fprintf( stderr, "\nProblemas para Asociar Socket :: %s", strerror(errno) );
      else
         {
         printf( "\n\nEsperando Cliente.....\n" );
         if( listen( sockds, LIMITE )==-1 )
            fprintf( stderr, "\nProblemas para Escuchar en el Socket :: %s", strerror(errno) );
         else
            {
            size_c= sizeof(struct sockaddr);
            if( (clientds= accept( sockds, (struct sockaddr *)&cliente, &size_c ))==-1 )
               fprintf( stderr, "\nProblemas para Aceptar Cliente :: %s", strerror(errno) );
            else
               {
               if( pthread_create( &hilo_r, NULL, recivir_datos, (void *)clientds )!=0 )
                  fprintf( stderr, "\nProblemas para crear Hilo de Recepcion :: %s", strerror(errno) );
               if( pthread_create( &hilo_s, NULL, enviar_datos, (void *)clientds )!=0 )
                  fprintf( stderr, "\nProblemas para crear Hilo de Teclado :: %s", strerror(errno) );
               }
            pthread_exit( &hilo_r );
            pthread_exit( &hilo_s );
            close(clientds);
            }
         }
      close(sockds);
      }
   }


Funcion enviar_datos:
Código:
void *enviar_datos( void *sock )
   {
   char buf[N];
   int clientds;

   clientds= *(int *)sock;

   memset( &buf, '\0', N );

   printf( "\nDato a Enviar: " );
   fgets( buf, N, stdin );
   buf[strlen(buf)-1]='\0';

   if( send( clientds, buf, strlen(buf), 0 )==-1 )
      fprintf( stderr, "\nProblema al Enviar Datos :: %s", strerror(errno) );
   else
      {
      printf( "\n---> Mensaje Enviado con exito...\n" );
      memset( &buf, '\0', N );
      }
   }


Funcion recive_datos:
Código:
void *recivir_datos( void *sock )
   {
   char buf[N];
   int clientds, bytes_r=0;

   clientds= *(int *)sock;
   memset( &buf, '\0', N );

   if( (bytes_r=recv( clientds, buf, N, 0 ))==-1 )
      fprintf( stderr, "\nProblemas para Recivir Datos :: %s", strerror(errno) );
   else
      {
      printf( "\nMensaje Recivido: %s", buf );
      printf( "\nDimension: %i", strlen(buf) );
      printf( "\nBytes: %i", bytes_r );
      }
   }


Y las includes que uso son:
Código:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define N 1024


byee
_________________

Volver arriba
Diabliyo



Registrado: 14 Abr 2004
Mensajes: 317
Ubicación: En la Luna

MensajePublicado: 20/03/2007 4:21 pm
Título:

Hola:

Listo, solo era cuestion de compilar linkeando pthread, asi:

Código:
shell# gcc -c codico.c
shell# gcc -o codigo codigo.0 -lpthread
shell#./codigo


Pero me marca este error:
Código:
Segmnetation fault


El error esta en la parte del codigo del servidor, bueno, NO es un error de CODIGO, es de ejecucion al momento de crear los hilos, pero no encuentro la logica del error :S, alguien me podria ayudar ???

Esto es un poco del code donde hago los hilos:
Código:
void inicia_servidor( void )
   {
   int sockds, clientds, bytes_r=0;
   struct sockaddr_in servidor;
   struct sockaddr_in cliente;
   int size_c=0, aux=1;
   pthread_t hilo_s, hilo_r;

   servidor.sin_family= AF_INET;
   servidor.sin_port= htons(PUERTO);
   inet_aton( "127.0.0.1", &servidor.sin_addr );
   memset( &servidor.sin_zero, '\0', 8 );

   if( (sockds=socket( AF_INET, SOCK_STREAM, 0 ))==-1 )
      fprintf( stderr, "\nProblemas para Crear Socket :: %s", strerror(errno) );
   else
      {
      if( setsockopt( sockds, SOL_SOCKET, SO_REUSEADDR, &aux, sizeof(int) )==-1 )
         fprintf( stderr, "\nProblemas para Reutilizar Direccion :: %s", strerror(errno) );

      if( bind( sockds, (struct sockaddr *)&servidor, sizeof(struct sockaddr) )==-1 )
         fprintf( stderr, "\nProblemas para Asociar Socket :: %s", strerror(errno) );
      else
         {
         printf( "\n\nEsperando Cliente.....\n" );
         if( listen( sockds, LIMITE )==-1 )
            fprintf( stderr, "\nProblemas para Escuchar en el Socket :: %s", strerror(errno) );
         else
            {
            size_c= sizeof(struct sockaddr);
            if( (clientds= accept( sockds, (struct sockaddr *)&cliente, &size_c ))==-1 )
               fprintf( stderr, "\nProblemas para Aceptar Cliente :: %s", strerror(errno) );
            else
               {
               if( pthread_create( &hilo_r, NULL, recivir_datos, (void *)clientds )!=0 )
                  fprintf( stderr, "\nProblemas para crear Hilo de Recepcion :: %s", strerror(errno) );
               if( pthread_create( &hilo_s, NULL, enviar_datos, (void *)clientds )!=0 )
                  fprintf( stderr, "\nProblemas para crear Hilo de Teclado :: %s", strerror(errno) );
               }
            //pthread_join( &hilo_r );
            //pthread_join( &hilo_s );
            pthread_exit( &hilo_r );
            pthread_exit( &hilo_s );
            close(clientds);
            }
         }
      close(sockds);
      }
   }

void *recivir_datos( void *sock )
   {
   char buf[N];
   int clientds, bytes_r=0;

   clientds= *(int *)sock;
   memset( &buf, '\0', N );

   if( (bytes_r=recv( clientds, buf, N, 0 ))==-1 )
      fprintf( stderr, "\nProblemas para Recivir Datos :: %s", strerror(errno) );
   else
      {
      printf( "\nMensaje Recivido: %s", buf );
      printf( "\nDimension: %i", strlen(buf) );
      printf( "\nBytes: %i", bytes_r );
      }
   }

void *enviar_datos( void *sock )
   {
   char buf[N];
   int clientds;

   clientds= *(int *)sock;

   memset( &buf, '\0', N );

   printf( "\nDato a Enviar: " );
   fgets( buf, N, stdin );
   buf[strlen(buf)-1]='\0';

   if( send( clientds, buf, strlen(buf), 0 )==-1 )
      fprintf( stderr, "\nProblema al Enviar Datos :: %s", strerror(errno) );
   else
      {
      printf( "\n---> Mensaje Enviado con exito...\n" );
      memset( &buf, '\0', N );
      }
   }


byee
_________________

Volver arriba
quique



Registrado: 30 Mar 2004
Mensajes: 720
Ubicación: Por ahí

MensajePublicado: 22/03/2007 8:24 am
Título:

Un par de comentarios:

solo le he echado un vistazo por encima, pero a ver si puedo servir de ayuda.

1) pthread_exit () debe ir en la funcion que se ejecuta en la thread. Es decir:

Código:

void *recivir_datos( void *sock )
{
 /* Your code */
   pthread_exit (0);
}


2) en tu loop principal, falta eso, el loop: comienzas una nueva conexion con accept, y sigues para adelante, sin ningun loop infinito ni nada de nada. Ten en cuenta que cuando termina el programa principal, todas tus threads se eliminaran, ademas, estas cerrando un socket por ahí....

3) por qué usas threads y no fork () ? (curiosidad, normalmente los daemons usan fork)

En fin, que a ver si esto ayuda

Salu2
_________________
/* no comment */
Volver arriba
Diabliyo



Registrado: 14 Abr 2004
Mensajes: 317
Ubicación: En la Luna

MensajePublicado: 22/03/2007 8:34 am
Título:

Hola:

Problema resuelto, solo se necesitaba corregir asi, dentro de las funciones de enviar_datos() y recivir_datos():

Código:
clientds= *(int *)sock;  //esta es incorrecta
clientds= (int)sock;  //correcta xD


-- quique
Sobre tu comentario del pthread_exit(), esta funcion tiene 2 operaciones dependiendo desde donde se invoque, en este caso al ser invocada desde el hilo (dentro de la funcion) nos sirve como un: return. Si pthread_exit() es invocado con un valor NULL o con el ID del Hilo, este retorna y finaliza el HILO, encambio si es invocado con un valor cualquiera, nos sirve para posteriormente fuera del hilo o su funcion que invoca, utilizar la funcion pthread_join() para esperara un hilo o recepcionar el valor del hilo. Posteriormente si se invoca a pthread_exit() desde fuera del hilo, esto solo nos servira para finalizar el hilo.

Sobre lo del fork(), pues porke es mas costoso hacerlo con fork(), ya que fork() hace una copia identica de todo el programa lo cual seria un gasto inutil de recursos, en cambio el hilo es mas rapido y con menos gasto de recursos !!

byee byee
_________________

Volver arriba
quique



Registrado: 30 Mar 2004
Mensajes: 720
Ubicación: Por ahí

MensajePublicado: 23/03/2007 4:42 am
Título:

Por partes:
Cita:
Sobre tu comentario del pthread_exit(), esta funcion tiene 2 operaciones dependiendo desde donde se invoque, en este caso al ser invocada desde el hilo (dentro de la funcion) nos sirve como un: return. Si pthread_exit() es invocado con un valor NULL o con el ID del Hilo, este retorna y finaliza el HILO, encambio si es invocado con un valor cualquiera, nos sirve para posteriormente fuera del hilo o su funcion que invoca, utilizar la funcion pthread_join() para esperara un hilo o recepcionar el valor del hilo. Posteriormente si se invoca a pthread_exit() desde fuera del hilo, esto solo nos servira para finalizar el hilo.


Podemos intentar leer juntos "man pthread_exit" y "man pthread_join", o mirar otras opiniones, porque no entendemos lo mismo:
http://www.chuidiang.com/clinux/procesos/procesoshilos.php
http://www.chuidiang.com/clinux/procesos/mashilos.php
(vierte opiniones personales, sin indicar nada de kernel, pero para empezar no está mal)

Cita:
Sobre lo del fork(), pues porke es mas costoso hacerlo con fork(), ya que fork() hace una copia identica de todo el programa lo cual seria un gasto inutil de recursos, en cambio el hilo es mas rapido y con menos gasto de recursos !!


qué recursos? a que te refieres, a RAM o memoria virtual? o a tiempo de respuesta? o a tiempo de creacion? a que linux kernel haces referencia? 2.4 o 2.6 u otro? Que entiendes por copia identica?

Estas apreciaciones que haces dependen de tantos factores que hay que tener cuidado, puede que alguien se las crea.

Probablemente estés hablando de un P4 con 1.7 GHz y 512 Mb RAM al menos, y que tengas un kernel 2.6....
_________________
/* no comment */
Volver arriba
Diabliyo



Registrado: 14 Abr 2004
Mensajes: 317
Ubicación: En la Luna

MensajePublicado: 29/03/2007 10:26 pm
Título:

quique escribió:
Por partes:
Cita:
Sobre tu comentario del pthread_exit(), esta funcion tiene 2 operaciones dependiendo desde donde se invoque, en este caso al ser invocada desde el hilo (dentro de la funcion) nos sirve como un: return. Si pthread_exit() es invocado con un valor NULL o con el ID del Hilo, este retorna y finaliza el HILO, encambio si es invocado con un valor cualquiera, nos sirve para posteriormente fuera del hilo o su funcion que invoca, utilizar la funcion pthread_join() para esperara un hilo o recepcionar el valor del hilo. Posteriormente si se invoca a pthread_exit() desde fuera del hilo, esto solo nos servira para finalizar el hilo.


Podemos intentar leer juntos "man pthread_exit" y "man pthread_join", o mirar otras opiniones, porque no entendemos lo mismo:
http://www.chuidiang.com/clinux/procesos/procesoshilos.php
http://www.chuidiang.com/clinux/procesos/mashilos.php
(vierte opiniones personales, sin indicar nada de kernel, pero para empezar no está mal)

Cita:
Sobre lo del fork(), pues porke es mas costoso hacerlo con fork(), ya que fork() hace una copia identica de todo el programa lo cual seria un gasto inutil de recursos, en cambio el hilo es mas rapido y con menos gasto de recursos !!


qué recursos? a que te refieres, a RAM o memoria virtual? o a tiempo de respuesta? o a tiempo de creacion? a que linux kernel haces referencia? 2.4 o 2.6 u otro? Que entiendes por copia identica?

Estas apreciaciones que haces dependen de tantos factores que hay que tener cuidado, puede que alguien se las crea.

Probablemente estés hablando de un P4 con 1.7 GHz y 512 Mb RAM al menos, y que tengas un kernel 2.6....


En fin me refiero en que FORK() me crea una copia completa del programa y por lo cual NO quisiera crear una copia del programa por cada cliente que entra :S... solo kieor crear hilos para hacer tareas !!!...

Por ejemplo:

un hilos para: SELECT()
un hilos para: fgets(), RECV()

...
_________________

Volver arriba
Diabliyo



Registrado: 14 Abr 2004
Mensajes: 317
Ubicación: En la Luna

MensajePublicado: 29/03/2007 10:30 pm
Título:

Hola:

Estoy intentando un ejemplo pero Sad.... no logro hacer el casting al pasarle al hilo una variable de tipo CHAR !! Sad....

Como ejemplo rapido, intente hacer esto:

Código:
#define N 50

void *saludo( void *buf );

void *saludo( void *buf )
   {
   char *x;
   x=buf;

   printf( "Hola %s", x );
   }

int main()
   {
   pthread_t hilo;
   char buf[N];

   printf( "Nombre: " );
   fgets( buf, N, stdin );
   pthread_create( &hilo, saludo, (void *)buf );
   pthread_join( hiloe, NULL );

_________________

Volver arriba
quique



Registrado: 30 Mar 2004
Mensajes: 720
Ubicación: Por ahí

MensajePublicado: 30/03/2007 5:32 am
Título:

Dejemos de lado la discusion de si fork o thread, porque no es cuestion de este hilo: tu te has decidido por threads, así que adelante.

Respecto al ejemplo, si no llamas a la funcion pthread_exit () DENTRO de la thread, puedes tener "memory leaks". Tu mismo.

El código de un programilla sería
Código:

#include <stdio.h>
#include <pthread.h>

void *saludo (void *buf)
{
   char *local_buf = (char *) buf;
   
   printf ("Thread: %s\n", local_buf);
   pthread_exit (0);
}


int main (int argc, char **argv)
{
   pthread_t mythread;
   char stAux [] = "Hello World!";
   
   pthread_create (&mythread, NULL, saludo, stAux);
   pthread_join (mythread, NULL);
   
   return 0;
}



que compila con:
gcc CFILE -o EXECFILE -pthread

Salu2
_________________
/* no comment */
Volver arriba
      Índice del Foro elrincondelc.com -> Programación en Servidores
Página 1 de 2Todas las horas están en GMT - 8 Horas
Ir a página 1, 2  Siguiente

 
No puede crear mensajes
No puede responder temas
No puede editar sus mensajes
No puede borrar sus mensajes
No puede votar en encuestas

(c) ElRincondelC.com

Un proyecto de UrlanHeat.com