标签:
为了使一个套接字能够使用信号驱动I/O,至少需要以下3步操作。
在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\n", 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\n", 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\n"); while(1) { int len; //设置当前阻塞的信号 sigprocmask(SIG_BLOCK, &newmask, &oldmask); //等待信号 while(nqueue == 0) sigsuspend(&oldmask); memset(recv_buf, ‘\0‘, 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\n", 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\n", 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, ‘\0‘, MAX_LENTH); fgets(snd_buf, MAX_LENTH - 1, stdin); write(sock_fd, snd_buf, MAX_LENTH - 1); } }
【linux高级程序设计】(第十五章)UDP网络编程应用 4
标签:
原文地址:http://www.cnblogs.com/dplearning/p/4708853.html