Intento configurar dos demonios, un cliente y un servidor, el servidor perfila algunas estadísticas del sistema y espera sin bloqueo a que se reciba un SIGIO, tras lo cual leerá los datos que se le envían y enviará algo de regreso a el cliente y continuar con lo que sea que estuviera haciendo.
Sin embargo, el cliente bloquea las funciones de envío y recepción en su socket. He codificado bastante y leído mucho, pero parece que hay muchos paradigmas diferentes que las personas usan cuando intentan lograr este tipo de comportamiento. Realmente agradecería un poco de ayuda, aquí está mi código hasta ahora:
SERVIDOR:
int s, s2, flags, n;
struct sockaddr_un addr;
struct sockaddr_un from;
int from_len;
socklen_t len;
void message_received_helper(int sig){
syslog(LOG_NOTICE, "Works! \n");
}
...
int main(int argc, char *argv[]) {
deamonize();
/* Daemon-specific initialization goes here */
setlogmask (LOG_UPTO (LOG_NOTICE));
openlog ("i_aware", LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL1);
syslog (LOG_NOTICE, "Program started by User %d", getuid ());
/*
* This set up is for the non blocking socket that will exist on the server
*/
/* specify the new action for the SIGIO signal */
new_action.sa_handler = message_received_helper;
/* supply the empty set to .sa_mask */
sigemptyset(&new_action.sa_mask);
/* no flags*/
new_action.sa_flags = 0;
/* Associate new_action with the signal SIGIO -
NULL indicates we are not saving any previous action*/
if(sigaction(SIGIO, &new_action, NULL) < 0 ){
syslog(LOG_NOTICE, "Could not associate SIGIO with action...\n");
exit(errno);
}
/*TODO create unix domain socket and listen for a connection*/
if((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0 ){
syslog(LOG_NOTICE, "Could not create socket: %d \n", errno);
perror("socket");
exit(errno);
}
/* bind socket */
addr.sun_family = AF_UNIX;
strcpy(addr.sun_path, "/dev/foo");
unlink(addr.sun_path);
len = (socklen_t) (strlen(addr.sun_path) + sizeof(addr.sun_family));
if( bind(s, (struct sockaddr *) &addr,len ) == -1){
syslog(LOG_NOTICE, "Could not bind socket %d \n", errno);
perror("bind");
exit(errno);
}
/* listen */
if(listen(s, 1) < 0){
syslog(LOG_NOTICE,"Error on listen: %d \n", errno);
perror("listen");
exit(errno);
}
from_len = sizeof(from);
if(s2 = accept(s, (struct sockaddr *) &from, &from_len ) < 0 ){
syslog(LOG_NOTICE,"Error on accept: %d \n", errno);
perror("accept");
exit(errno);
}
syslog(LOG_NOTICE,"success \n");
/* set the ownership of the socket fd to this process */
syslog(LOG_NOTICE, "F_SETOWN: %d \n" ,fcntl(s2, F_SETOWN, getpid()) );
/*get file access mode and file status flag - no args needed for this F_GETFL comand*/
flags = fcntl(s2, F_GETFL);
syslog(LOG_NOTICE, "F_GETFL: %d \n", flags);
/* Enable non blocking */
syslog(LOG_NOTICE, "F_SETFL: %d \n" , fcntl(s2, F_SETFL, flags | FASYNC));
/*
* At this point the socket described by s2, should be a non blocking socket, when a SIGIO
* is raised upon receipt of data waiting on the socket the method message_received_helper
* will be called
*/
n = recv(s2, str, 1, 0);
syslog(LOG_NOTICE, "Works! \n");
if (n <= 0) {
if (n < 0) syslog(LOG_NOTICE, "recv error: %d", errno);
}
syslog(LOG_NOTICE, "n: %d, s2: %d, str: %s \n", n, s2, str );
if (send(s2, str, n, 0) < 0) {
syslog(LOG_NOTICE, "send: %d", errno);
}
CLIENTE:
int s, s2, t, len;
struct sockaddr_un local, remote;
char str[100];
if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(1);
}
local.sun_family = AF_UNIX;
strcpy(local.sun_path, SOCK_PATH);
unlink(local.sun_path);
len = strlen(local.sun_path) + sizeof(local.sun_family);
if (bind(s, (struct sockaddr *)&local, len) == -1) {
perror("bind");
exit(1);
}
if (listen(s, 5) == -1) {
perror("listen");
exit(1);
}
for(;;) {
int done, n;
printf("Waiting for a connection...\n");
t = sizeof(remote);
if ((s2 = accept(s, (struct sockaddr *)&remote, &t)) == -1) {
perror("accept");
exit(1);
}
printf("Connected.\n");
done = 0;
do {
n = recv(s2, str, 100, 0);
if (n <= 0) {
if (n < 0) perror("recv");
done = 1;
}
if (!done)
if (send(s2, str, n, 0) < 0) {
perror("send");
done = 1;
}
} while (!done);
close(s2);
Los dos procesos pueden conectarse a través del socket, pero no se genera ningún SIGIO cuando el cliente envía datos al servidor. Además, la función recv() sigue bloqueándose, como si nada de lo que hice afectara el socket s2 para que las lecturas no bloquearan.
Respuesta1
if(s2 = accept(s, (struct sockaddr *) &from, &from_len ) < 0 )
es incorrecto, debería leerse
if( (s2 = accept(s, (struct sockaddr *) &from, &from_len )) < 0 )
Los paréntesis que faltaban hicieron que se leyera la primera declaración.s2 = < 0, que establece s2 en 0;