Comunicação entre processos com notificação assíncrona

Comunicação entre processos com notificação assíncrona

Estou tentando configurar dois daemons, um cliente e um servidor, o servidor traça o perfil de algumas estatísticas do sistema e aguarda de forma não bloqueadora o recebimento de um SIGIO, após o qual irá ler os dados enviados a ele, enviar algo de volta para o cliente e continuar com o que quer que estivesse fazendo.

No entanto, o cliente emite bloqueio de funções de envio e recebimento em seu soquete. Eu fiz bastante codificação e li bastante, mas parece que há muitos paradigmas diferentes que as pessoas usam quando tentam alcançar esse tipo de comportamento. Eu realmente apreciaria alguma ajuda, aqui está meu código até agora:

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

Os dois processos conseguem se conectar pelo soquete, mas nenhum SIGIO é gerado quando o cliente envia dados ao servidor. Além disso, a função recv() continua bloqueando, como se nada do que eu tenha feito afetasse o soquete s2 para tornar as leituras sem bloqueio.

Responder1

if(s2 = accept(s,  (struct sockaddr *) &from, &from_len ) < 0 ) 

está incorreto, deve ser lido

if( (s2 = accept(s,  (struct sockaddr *) &from, &from_len )) < 0 )

Os parênteses faltantes fizeram a primeira declaração ser lidas2 = < 0, que definiu s2 como 0;

informação relacionada