socket信号驱动
异步信号处理机制流程;
设置为异步处理socket再有数据可操作时将产生SIGIO,因此,为了使一个套接字能够试用信号驱动I/O操作,至少需要3部操作
(1)安装SIGIO信号,在该处理函数中设定处理办法。
(2)套接字的拥有者必须设定为当前进程。因此socket产生的SIGIO信号会被递送给socket的拥有者进程,可以使用icntl函数的F_SETOWN参数来进行设定拥有者。
(3)套接字必须被允许使用异步I/O,即允许产生SIGIO信号。通过调用fictl函数的F_SETFL命令,将即设置为O_ASYNC。
在UDP通信中SIGIO信号会在下列情况下产生:服务器端源代码如下:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<math.h>
#include<fcntl.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<sys/mman.h>
#include<time.h>
#include<dirent.h>
#include<sys/errno.h>
#include<sys/wait.h>
#include<signal.h>
#include<sys/param.h>
#include<sys/syslog.h>
#include<limits.h>
#include<sys/time.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<sys/sem.h>
#include<errno.h>
#include<sys/shm.h>
#include<pthread.h>
#include<sys/syscall.h>
#include<semaphore.h>
#include<bits/pthreadtypes.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<sys/socket.h>
#include<sys/ioctl.h>
#define MAX_LENTH 1500
static int nqueue=0;
void sigio_handler(int signum) //针对SIGIO信号处理
{
if(signumSIGIO)
nqueue++;
printf(“signum=%d,nqueue=%d\n”,signum,nqueue); //打印信号值
return;
}
static char 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) //参数中必须包括服务器IP地址,端口
{
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
if(inet_aton(argv[1],(struct in_addr )&ser_addr.sin_addr.s_addr)0)
{
perror(argv[1]);
exit(EXIT_FAILURE);
}
ser_addr.sin_port=htons(atoi(argv[2])); //从argv[2]中读取端口
if((sockfd=socket(AF_INET,SOCK_DGRAM,0))-1)
{
perror("create socket failed ");
exit(EXIT_FAILURE);
}
if(bind(sockfd,(struct sockaddr)&ser_addr,sizeof(ser_addr))-1)
{
perror(“Bind socket failed”);
exit(EXIT_FAILURE);
}
memset(&action,0,sizeof(action));
action.sa_handler=sigio_handler;
action.sa_flags=0;
sigaction(SIGIO,&action,NULL); //安装信号,
if(fcntl(sockfd,F_SETOWN,getpid())-1) //设置socket拥有者
{
perror(“fcntl F_SETOWN”);
exit(EXIT_FAILURE);
}``
if(ioctl(sockfd,FIOASYNC,&on)-1) //设置socket为信号驱动型
{
perror(“ioctl FIOASYNC”);
exit(EXIT_FAILURE);
}
sigemptyset(&oldmask); //清空信号集
sigemptyset(&newmask);
sigaddset(&newmask,SIGIO); //将SIGIO添加到newmask信号集
printf(“get ready\n”);
while(1)
{
int len;
sigprocmask(SIG_BLOCK,&newmask,&oldmask); //设置当前进程屏蔽的信号集合
while(nqueue0)
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(s),msg is %s\n”,len,recv_buf);
}
}
客户端源代码如下:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<math.h>
#include<fcntl.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<sys/mman.h>
#include<time.h>
#include<dirent.h>
#include<sys/errno.h>
#include<sys/wait.h>
#include<signal.h>
#include<sys/param.h>
#include<sys/syslog.h>
#include<limits.h>
#include<sys/time.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<sys/sem.h>
#include<errno.h>
#include<sys/shm.h>
#include<pthread.h>
#include<sys/syscall.h>
#include<semaphore.h>
#include<bits/pthreadtypes.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<sys/socket.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)
{
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]));
if((sock_fd=socket(AF_INET,SOCK_DGRAM,0))-1)
{
perror(“socket”);
exit(EXIT_FAILURE);
}
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);
}
}
当客户端发起连接,并发送数据到服务端,服务端接收到信息,并打印出来接收到的数据。为了便于测试SIGIO信号,在信号处理中列出了信号值。异步信号处理机制,实质是通过产生信号控制数据。SIGIO的默认动作是终止进程,在设置套接字之前必须将SIGIO信号设置好。
执行结果如下:
客户端开始执行,发送数据。
服务器端做好准备,等待客户端发送数据。客户端开始执行,发送数据。服务端接收到信息,此生产生信号SIGIO,函数sigio_hander(int signum)开始执行,结果打印了信号值,然后打印出接收到的信息:
客户端发送信息,可循环发送。
服务端接收到信息,并打印信号值,之后打印接收到的数据值。