Normas del foro

Curso Hacker
Bienvenido(a), Visitante. Favor de ingresar o registrarse.
¿Perdiste tu email de activación? - Noviembre 19, 2008, 03:13:40
Inicio Ayuda Ingresar Registrarse
Visita: Articulos - Juegos Gratis - Da Foros

Comunidad Underground Hispana  |  Programacion  |  Programación  |  Carbide C/C#/C++  |  Tema: Chat Servidor-Cliente !! Ayuda en algunas partes del codigo! 0 Usuarios y 1 Visitante están viendo este tema. « anterior próximo »
Páginas: [1] Ir Abajo Imprimir
Autor Tema: Chat Servidor-Cliente !! Ayuda en algunas partes del codigo!  (Leído 515 veces)
darkdiabliyo
Miembro
*****
Desconectado Desconectado

Mensajes: 40


darkdiabliyo@hotmail.com
Ver Perfil WWW Email
« en: Marzo 06, 2007, 12:34:55 »

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 Huh...

byee
En línea

Micki Qwerty
Visitante
« Respuesta #1 en: Marzo 06, 2007, 12:38:05 »

Con otro thread.
« Última modificación: Marzo 06, 2007, 12:38:20 por /Migue » En línea
darkdiabliyo
Miembro
*****
Desconectado Desconectado

Mensajes: 40


darkdiabliyo@hotmail.com
Ver Perfil WWW Email
« Respuesta #2 en: Marzo 19, 2007, 12:18:52 »

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
« Última modificación: Marzo 19, 2007, 12:23:04 por darkdiabliyo » En línea

DarkIker
Habitual
*****
Desconectado Desconectado

Mensajes: 269


Colombia Underground Team

dark_iker_reign@hotmail.com
Ver Perfil WWW Email
« Respuesta #3 en: Marzo 19, 2007, 01:28:00 »

gcc 007_2.c -o 007 -lpthread

Hay que linkear la libreria "pthread", compilao de ese modo y seguro te rula Wink.

Att: DarkIker
En línea


Necesitas ser usuario para ver los enlaces Crear Usuario  Hacer Sesion --> Colombia Underground Team

Necesitas ser usuario para ver los enlaces Crear Usuario  Hacer Sesion --> My Blog
darkdiabliyo
Miembro
*****
Desconectado Desconectado

Mensajes: 40


darkdiabliyo@hotmail.com
Ver Perfil WWW Email
« Respuesta #4 en: Marzo 19, 2007, 02:03:30 »

gcc 007_2.c -o 007 -lpthread

Hay que linkear la libreria "pthread", compilao de ese modo y seguro te rula Wink.

Att: DarkIker

como seria ?
En línea

DarkIker
Habitual
*****
Desconectado Desconectado

Mensajes: 269


Colombia Underground Team

dark_iker_reign@hotmail.com
Ver Perfil WWW Email
« Respuesta #5 en: Marzo 19, 2007, 03:05:34 »

te lo estoy diciendo tio

Código:
shell#gcc 007_2.c -o 007 -lpthread
shell#./007

Eso te resolvera el problema de compilar, pero despues seguro te va a hacer falt averiguar algo sobre "pthread_join". cualquier duda posteala.

Att: DarkIker
En línea


Necesitas ser usuario para ver los enlaces Crear Usuario  Hacer Sesion --> Colombia Underground Team

Necesitas ser usuario para ver los enlaces Crear Usuario  Hacer Sesion --> My Blog
darkdiabliyo
Miembro
*****
Desconectado Desconectado

Mensajes: 40


darkdiabliyo@hotmail.com
Ver Perfil WWW Email
« Respuesta #6 en: Marzo 19, 2007, 03:52:44 »

te lo estoy diciendo tio

Código:
shell#gcc 007_2.c -o 007 -lpthread
shell#./007

Eso te resolvera el problema de compilar, pero despues seguro te va a hacer falt averiguar algo sobre "pthread_join". cualquier duda posteala.

Att: DarkIker

Hola:

Segun mi libro, pthread_join() espera a ke un hilo termine y posteriormente obtiene su valor retornado, si es ke la funcion invocada dentro de pthread_create() retornace un valor. Aqui tambien entra pthread_exit(), si esta funcion es invocada con el ID del Hilo, el hilo es terminado, de lo contrario esta debe ser invicada dentro de la funcion que enivamos con pthread_create(), asi conjugada con pthread_join obtenemos el valor que nos envio pthread_exit().

Estoy entendiendo mal ?? o si voy bien con esto de los hilos Huh

Código:
funcion *x( void *a )
{
*a=5;
pthread_exit(a);
}

int main()
{
int a=0;
int *b;

//crea hilo
pthread_create( id, NULL, x, (void *);

//*b tiene el valor devuelto por la funcion 'x'
pthread_join( id, (void **)b );

bye bye
« Última modificación: Marzo 19, 2007, 04:01:00 por darkdiabliyo » En línea

DarkIker
Habitual
*****
Desconectado Desconectado

Mensajes: 269


Colombia Underground Team

dark_iker_reign@hotmail.com
Ver Perfil WWW Email
« Respuesta #7 en: Marzo 19, 2007, 03:58:04 »

estas entendiendo bien, y debes esperar por la terminacion del hilo y no cancelarlo ya que esto t impide liberar memoria.
En línea


Necesitas ser usuario para ver los enlaces Crear Usuario  Hacer Sesion --> Colombia Underground Team

Necesitas ser usuario para ver los enlaces Crear Usuario  Hacer Sesion --> My Blog
darkdiabliyo
Miembro
*****
Desconectado Desconectado

Mensajes: 40


darkdiabliyo@hotmail.com
Ver Perfil WWW Email
« Respuesta #8 en: Marzo 19, 2007, 04:05:01 »

estas entendiendo bien, y debes esperar por la terminacion del hilo y no cancelarlo ya que esto t impide liberar memoria.

Entonces segun el mini-codigo de hilos que puse arriba tiene la deficiencia de que el hilo se queda colgado... La forma correcta para que se libere la memoria utilizada por el hilo seria asi  Huh??:

Código:
funcion *x( void *a )
          {
          *a=5;
          pthread_exit(a);
          }

int main()
          {
          int a=0;
          int *b;
          pthread_t id;

          //crea hilo
          pthread_create( &id, NULL, x, (void *);

          //*b tiene el valor devuelto por la funcion 'x'
          pthread_join( &id, (void **)b );

          //finalizamos hilo
          pthread_exit(&id);

          return 0;
          }

byee
En línea

DarkIker
Habitual
*****
Desconectado Desconectado

Mensajes: 269


Colombia Underground Team

dark_iker_reign@hotmail.com
Ver Perfil WWW Email
« Respuesta #9 en: Marzo 19, 2007, 04:13:21 »

no hay necesidad de finalizar el hilo:

Código:
//finalizamos hilo
          pthread_exit(&id);

por que este ya a retornado, solo verifica el valor de retorno de "pthread_join" que no estoy seguro de que retorna Tongue.

Att: DarkIker
En línea


Necesitas ser usuario para ver los enlaces Crear Usuario  Hacer Sesion --> Colombia Underground Team

Necesitas ser usuario para ver los enlaces Crear Usuario  Hacer Sesion --> My Blog
darkdiabliyo
Miembro
*****
Desconectado Desconectado

Mensajes: 40


darkdiabliyo@hotmail.com
Ver Perfil WWW Email
« Respuesta #10 en: Marzo 20, 2007, 06:13:31 »

Hola:

Ya compile y todo bien.... el problema es ke sigue sin funcionar el programa Sad, me marca:

Código:
Segmentation default

El el Servidor Sad, ya que en este es donde hice los hilos... chequen la funcion:

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);
}
}

byee
En línea

DarkIker
Habitual
*****
Desconectado Desconectado

Mensajes: 269


Colombia Underground Team

dark_iker_reign@hotmail.com
Ver Perfil WWW Email
« Respuesta #11 en: Marzo 20, 2007, 06:38:41 »

Tio ahora ando un tanto liado con algunas cosas y no puedo compilar tu codigo ya que tendria que reiniciar Tongue, pero por lo ue vo todo deberia funcionar bien, de todas formas postea el codigo de la fuincoion de recivir y la de enviar datos tal vez sea en el hilo y no en el server.

Att: DarkIker
En línea


Necesitas ser usuario para ver los enlaces Crear Usuario  Hacer Sesion --> Colombia Underground Team

Necesitas ser usuario para ver los enlaces Crear Usuario  Hacer Sesion --> My Blog
darkdiabliyo
Miembro
*****
Desconectado Desconectado

Mensajes: 40


darkdiabliyo@hotmail.com
Ver Perfil WWW Email
« Respuesta #12 en: Marzo 21, 2007, 09:07:11 »

Hola:

Aqui estan las 2 funciones para una mejor ayuda xD:

Funcion recivir_datos(), se encargara de recivir datos del sockets y mostrarlos.
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 );
}
}

La funcion enviar_datos() se encarga de esperar datos del usuario por la entrada estandar (teclado) y posteriormente ahi mismo enviarlos al socket.
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 );
}
}

Gracias de antemano por su tiempo !!

byee
En línea

DarkIker
Habitual
*****
Desconectado Desconectado

Mensajes: 269


Colombia Underground Team

dark_iker_reign@hotmail.com
Ver Perfil WWW Email
« Respuesta #13 en: Marzo 21, 2007, 10:05:51 »

lindos casting tio xD

Código:
clientds= *(int *)sock;

Lo mas probable es que eso sea lo que falle, ya que en el server no vi ningun problema, lo que debes hacer es cambiar la forma como tomas el parametro ya que el cast que haces es incorrecto, hazlo de esta forma:

Código:
int clientds=(int)sock;

Salu2.

Att: DarkIker

En línea


Necesitas ser usuario para ver los enlaces Crear Usuario  Hacer Sesion --> Colombia Underground Team

Necesitas ser usuario para ver los enlaces Crear Usuario  Hacer Sesion --> My Blog
darkdiabliyo
Miembro
*****
Desconectado Desconectado

Mensajes: 40


darkdiabliyo@hotmail.com
Ver Perfil WWW Email
« Respuesta #14 en: Marzo 22, 2007, 10:34:48 »

Hola:

Gracias, ya funciono perfectamente xD, solo fue cuestion de cambiar la linea como dijiste DarkIker, en realidad fue un error de conversion de tipo jijiji xD....

Ahora intentare hacerlo un poco mas multi-usuario, posteare el code por si tengo algun problema xD !!

Gracias !!!

bye bye
En línea

darkdiabliyo
Miembro
*****
Desconectado Desconectado

Mensajes: 40


darkdiabliyo@hotmail.com
Ver Perfil WWW Email
« Respuesta #15 en: Marzo 22, 2007, 11:17:33 »

Hola:

Tengo un conflicto sobre pasar parametros en la funcion/rutina de un hilo !!

Miren, quiero pasar una variable tipo char, pero NO consigo como Sad...

Aqui dejo un ejemplo muy sencillo, haber si pueden sacarme de dudas jejeje xD:

Código:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <errno.h>

#define N 100

void saludo( char *cad );

void saludo( char *cad );
{
printf( "Hols %s", cad );
}

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

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

system( "clear" );
printf( "Nombre: " );
fgets( buf, N, stdin );

if( pthread_create( &hilo, NULL, sludo, (void *)&buf )!=0 )
fprintf( stderr, "\nProblemas para crear hilo :: %s", strerror(errno) );
else if( pthread_join( hilo, NULL )!=0 )
fprintf( stderr, "\nProblemas para esperar al hilo :: %s", strerror(errno) );
else
printf( "\nTodo el proceso fallo :(" );

printf( "\nPulsa para salir..." );
getchar();
return 0;
}

byee
« Última modificación: Marzo 22, 2007, 11:19:55 por darkdiabliyo » En línea

DarkIker
Habitual
*****
Desconectado Desconectado

Mensajes: 269


Colombia Underground Team

dark_iker_reign@hotmail.com
Ver Perfil WWW Email
« Respuesta #16 en: Marzo 23, 2007, 10:44:06 »

Por que el prototipo de thread en linux es:

Código:
void* Funcion(void* Param)

Has el casting y veras que lo puedes pasar perfectamente.

Att: DarkIker
En línea


Necesitas ser usuario para ver los enlaces Crear Usuario  Hacer Sesion --> Colombia Underground Team

Necesitas ser usuario para ver los enlaces Crear Usuario  Hacer Sesion --> My Blog
Páginas: [1] Ir Arriba Imprimir 
Comunidad Underground Hispana  |  Programacion  |  Programación  |  Carbide C/C#/C++  |  Tema: Chat Servidor-Cliente !! Ayuda en algunas partes del codigo! « anterior próximo »
Ir a:  


Ranking-Hits
Powered by SMF 1.1.7 | SMF © 2006-2007, Simple Machines LLC