• 【linux高级程序设计】(第十五章)UDP网络编程应用 4


    socket信号驱动

    为了使一个套接字能够使用信号驱动I/O,至少需要以下3步操作。

    • 1.安装SIGIO信号
    • 2.套接字的拥有者设定为当前进程。因为SIGIO信号只会送到socket拥有者进程. 通过fcntl的F_SETOWN
    • 3.套接字必须被允许使用异步I/O。 通过fcntl的F_SETFL,设置为O_ASYNC

    在UDP通信中,下面情况会产生SIGIO信号

    在TCP通信中,下面情况会产生SIGIO信号

    例子:

    下面的代码好奇怪,说是UDP的,但是发送接收用的是send, recv 而且客户端还跟服务器连接了;说是TCP,但是socket建立的时候用的是SOCK_DGRAM.

    而且代码是可以跑通的。

    服务器:

    #include<stdio.h>
    #include<stdlib.h>
    #include<errno.h>
    #include<string.h>
    #include<sys/types.h>
    #include<netinet/in.h>
    #include<netinet/tcp.h>
    #include<sys/socket.h>
    #include<sys/wait.h>
    #include<unistd.h>
    #include<arpa/inet.h>
    #include<sys/time.h>
    #include<netdb.h>
    #include<fcntl.h>
    #include<signal.h>
    #include<sys/ioctl.h>
    #define MAX_LENTH 1500
    
    //针对SIGIO信号处理
    static int nqueue = 0; 
    void sigio_handler(int signum)
    {
        if(signum == SIGIO)
            nqueue++;
        printf("signum = %d, nqueue = %d
    ", signum, nqueue); //打印信号值
        return;
    }
    static recv_buf[MAX_LENTH];
    
    int main(int argc, char *argv[])
    {
        int sockfd, on = 1;
        struct sigaction action;
        sigset_t newmask, oldmask;
        struct sockaddr_in ser_addr;
        if(argc != 3)
        {
            printf("use: %s ip_add port
    ", argv[0]);
            exit(EXIT_FAILURE);
        }
        
        memset(&ser_addr, 0, sizeof(ser_addr));
        ser_addr.sin_family = AF_INET;  //使用IPv4
        ser_addr.sin_port = htons(atoi(argv[2]));
        if(inet_aton(argv[1], (struct in_addr *)&ser_addr.sin_addr.s_addr) == 0)
        {
            perror(argv[1]);
            exit(EXIT_FAILURE);
        }
        //创建socket
        if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
        {
            perror("socket");
            exit(EXIT_FAILURE);
        }
        //绑定IP地址
        if(bind(sockfd, (struct sockaddr *)&ser_addr, sizeof(ser_addr)) == -1)
        {
            perror("bind");
            exit(EXIT_FAILURE);
        }
        memset(&action, 0, sizeof(action));
        action.sa_handler = sigio_handler;
        action.sa_flags = 0;
        //安装信号
        sigaction(SIGIO, &action, NULL);
        //设置socket拥有者
        if(fcntl(sockfd, F_SETOWN, getpid()) == -1)
        {
            perror("fcntl F_SETOWN");
            exit(EXIT_FAILURE);
        }
        //设置socket为信号驱动型
        if(ioctl(sockfd, FIOASYNC, &on) == -1)
        {
            perror("ioctl FIOASYNC");
            exit(EXIT_FAILURE);
        }
        sigemptyset(&oldmask);
        sigemptyset(&newmask);
        sigaddset(&newmask, SIGIO);
        printf("get ready
    ");
        while(1)
        {
            int len;
            //设置当前阻塞的信号
            sigprocmask(SIG_BLOCK, &newmask, &oldmask);
            //等待信号
            while(nqueue == 0)
                sigsuspend(&oldmask);
            memset(recv_buf, '', MAX_LENTH);
            //非阻塞接收数据
            len = recv(sockfd, recv_buf, MAX_LENTH, MSG_DONTWAIT);
            if(len == -1 && errno == EAGAIN)
                nqueue = 0;
            //修改进程阻塞的信号
            sigprocmask(SIG_SETMASK, &oldmask, NULL);
            if(len >= 0)
                printf("recv %d byte, msg is %s
    ", len, recv_buf);
        }
        
    }

    客户端

    #include<stdio.h>
    #include<stdlib.h>
    #include<errno.h>
    #include<string.h>
    #include<sys/types.h>
    #include<netinet/in.h>
    #include<netinet/tcp.h>
    #include<sys/socket.h>
    #include<sys/wait.h>
    #include<unistd.h>
    #include<arpa/inet.h>
    #include<sys/time.h>
    #include<netdb.h>
    #include<fcntl.h>
    #include<signal.h>
    #include<sys/ioctl.h>
    #define MAX_LENTH 1500
    
    int main(int argc, char *argv[])
    {
        struct sockaddr_in addr;
        int sock_fd, ret;
        char snd_buf[MAX_LENTH];
        if(argc != 3)  //参数需要服务器的IP和端口
        {
            printf("use: %s ip_add port
    ", argv[0]);
            exit(EXIT_FAILURE);
        }
        memset(&addr, 0, sizeof(addr));
        addr.sin_family = AF_INET;
        if(inet_aton(argv[1], (struct in_addr *)&addr.sin_addr.s_addr) == 0)
        {
            perror(argv[1]);
            exit(EXIT_FAILURE);
        }
        addr.sin_port = htons(atoi(argv[2]));
        //创建socket
        if((sock_fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
        {
            perror("socket");
            exit(EXIT_FAILURE);
        }
        //向服务器发起连接 ??这不是TCP的么
        if(ret = connect(sock_fd, (struct sockaddr *)&addr, sizeof(addr)) == -1)
        {
            perror("connect");
            exit(EXIT_FAILURE);
        }
        while(1)
        {
            printf("input msg to send:");
            memset(snd_buf, '', MAX_LENTH);
            fgets(snd_buf, MAX_LENTH - 1, stdin);
            write(sock_fd, snd_buf, MAX_LENTH - 1);
        }
    }

  • 相关阅读:
    [Docker]一键部署gitlab中文版
    [Docker]python 2.7.5 docker-compose安装
    [CentOS7]pip安装
    快速傅里叶变换FFT
    HDU 4734 f(x)
    DP
    HDU 3555 Bomb
    HDU 5898 odd-even number
    将文本拷贝到剪贴板
    数论分块
  • 原文地址:https://www.cnblogs.com/dplearning/p/4708853.html
Copyright © 2020-2023  润新知