Interprozesskommunikation mit asynchroner Benachrichtigung

Interprozesskommunikation mit asynchroner Benachrichtigung

Ich versuche, zwei Daemons einzurichten, einen Client und einen Server. Der Server erstellt ein Profil einiger Systemstatistiken und wartet ohne Blockierung auf den Empfang eines SIGIO. Daraufhin liest er die an ihn gesendeten Daten, sendet etwas an den Client zurück und fährt mit dem fort, was er gerade getan hat.

Der Client hat jedoch Probleme mit der Blockierung von Sende- und Empfangsfunktionen auf seinem Socket. Ich habe ziemlich viel Code geschrieben und viel gelesen, aber es scheint, dass es viele verschiedene Paradigmen gibt, die Leute verwenden, um dieses Verhalten zu erreichen. Ich wäre wirklich für Hilfe dankbar. Hier ist mein bisheriger Code:

SERVER:

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

            }

KLIENT:

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

Die beiden Prozesse können über den Socket eine Verbindung herstellen, aber es wird kein SIGIO ausgelöst, wenn der Client Daten an den Server sendet. Außerdem blockiert die Funktion recv() weiterhin, als ob nichts, was ich getan habe, den Socket s2 beeinflusst hätte, um Lesevorgänge nicht zu blockieren.

Antwort1

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

ist falsch, es müsste heißen

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

Die fehlenden Klammern ließen die erste Aussage lautens2 = < 0, wodurch s2 auf 0 gesetzt wird;

verwandte Informationen