SIGIO永远不会开火

时间:2016-10-30 23:13:42

标签: c sockets networking io signals

ioctl()将套接字更改为异步模式。通过手册页上的定义,内核在套接字上可以进行i / o时发送SIGIO。我用测试客户端运行它并且i / o很好(数据包到达源和目标),为什么内核不会调用sigpoll?

澄清一下,问题在于尽管已经建立了SIGIO信号并占用了套接字来发送信号SIGIO,但没有信号发出或没有迹象表明sigpoll()被调用。 < / p>

我上传了代码,我发现了这个问题,最终会有一些淡化版本的谈话。

talkish.c

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <netdb.h>
#include <signal.h>
#include <setjmp.h>
#include <string.h>

#include <sys/socket.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/param.h>
#include <sys/signal.h>
#include <sys/stat.h>
#include <sys/time.h>

#include <netinet/tcp.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <netinet/in.h>

#define MAX_BUF 1000
#define CHAR_BUF 50
#define BASEPORT "10000"

void error(const char *msg){
    perror(msg);
    exit(1);
}

typedef struct tuple{
        char HN [MAX_BUF];
        char PN [MAX_BUF];
}tuple;

tuple storeCMD( char input[]){
        tuple ret;
    char* token = strtok(input, " ");
    if (token != NULL) strcpy( ret.HN, token);
    else ret.HN[0] = 0;
        token = strtok(NULL, " ");
    if (token != NULL) strcpy( ret.PN, token);
    else ret.PN[0] = 0;
        return ret;
}

void sigpoll(int sig){
    printf("Signal fired!\n");

    //eventual rcvfrom and other things...
}

int main(int argc, char * argv[]){

    if (argc != 2){
        printf("Proper usage requires 2 arguments: $talkish port-number\n");
        exit(1);
    }
    int sd;
    struct sockaddr_storage client;
    socklen_t clientLen;    

    struct addrinfo server, *res;
    struct addrinfo *serverinfo;
    char buffer [MAX_BUF];

    memset(&server, 0, sizeof(server));
    bzero((char *) &server, sizeof(server));

    server.ai_family = AF_INET;
    server.ai_socktype = SOCK_DGRAM;
    server.ai_flags = AI_PASSIVE;

     //initially we'll use information from user, but move to partner and partnerl
    //once solid connection is established.
    struct sockaddr_storage partner;
    socklen_t partnerl;
    //Bind to argv[1]
    tuple execute;

    getaddrinfo(NULL, argv[1], &server, &res);

    sd = socket(res -> ai_family ,res -> ai_socktype, res -> ai_protocol);
    if (sd < 0) error("ERROR on socket!");

    int n = bind(sd, res -> ai_addr, res -> ai_addrlen);
    if (n < 0) error("ERROR on Bind!");

    int flag;
    flag= 1;
    fcntl(sd, F_SETOWN, getpid());
    signal(SIGPOLL, sigpoll); //establish sigpoll to get udp packets
    ioctl(sd, FIOASYNC, &flag);

    //establish timer to allow wait and see
    struct timeval timer;
    timer.tv_sec = 7;

    //while connecting

    char message[CHAR_BUF];
    bzero((char *) message, CHAR_BUF);
    int connecting = 1;
    while(connecting){
        printf ("? ");
        scanf(" %[^\n]", message);

        if (strlen(message) == 0); 
        else if ( 0 == strcmp( message, "q")){
            exit (0);
        }
        else {
            execute = storeCMD(message);
            if (execute.HN[0] == 0 || execute.PN[0] == 0) printf("| Input should match \"Hostname Portname\" to connect and \"q\" to quit \n");
            else {

                struct sockaddr_storage dest_server;
                socklen_t dest_serverl;
                struct addrinfo dest_hints, *dest_res;
                struct in_addr dest_addr;

                memset(&dest_hints, 0, sizeof(dest_hints));
                dest_hints.ai_family = AF_INET;
                dest_hints.ai_socktype = SOCK_DGRAM;
                dest_hints.ai_flags = AI_PASSIVE;

                if (getaddrinfo( execute.HN, execute.PN, &dest_hints, &dest_res) < 0) printf("| Input should match \"Hostname Portname\" to connect and \"q\" to quit \n");
                else {

                    bzero((char *) buffer, MAX_BUF);
                    sprintf(buffer, "wannachat");

                    sendto(sd, buffer, MAX_BUF, 0, (struct sockaddr *) dest_res -> ai_addr, dest_res -> ai_addrlen );       

                    if (setsockopt(sd, SOL_SOCKET, SO_RCVTIMEO, &timer, sizeof(timer)) < 0) error("ERROR on setsockopt");

                    partnerl = sizeof(partner); 
                    bzero((char *) &partner, partnerl);
                    bzero((char *) buffer, MAX_BUF);

                    if (recvfrom(sd, buffer, MAX_BUF, 0, (struct sockaddr *)&partner, &partnerl ) < 0) printf("| No response received from %s. \n", execute.HN);
                    else{
                        if ( 0 == strcmp( buffer, "OK")){
                            printf("| Connected to %s. \n", execute.HN);
                            //chat();
                        }else   printf("| %s does not want to talk. \n", execute.HN);
                    }
                }   
            }
        }
    }

    close(sd);
    return 0;
}

1 个答案:

答案 0 :(得分:0)

要接收SIGIO通知(对于套接字也是SIGURG,例如:接收TCP URG数据时),您需要使用fcntl(fd, F_SETOWN, pid)告诉内核通知谁。像往常一样,正pid值指的是一个过程,而负pid指的是一个过程组。

在Linux上,如果要将信号发送到特定线程,则需要使用F_SETOWN_EX。在其他系统上,您必须阻止其他线程上的信号。使用pthread_sigmask()