现在的位置: 首页 > 综合 > 正文

基于信号驱动式IO的监听套接字(O_ASYNC,O_NONBLOCK)

2018年09月21日 ⁄ 综合 ⁄ 共 2211字 ⁄ 字号 评论关闭

背景

Source: http://blog.csdn.net/ordeder/article/details/22733077

(Unix网络编程卷1说明如下)

设置套接字信号驱动式io(SIGIO)需要三个步骤:
1.建立SIGIO信号的处理函数
2.设置套接字的属主,即fcntl:F_SETOWN
3.开启套接字的信号驱动是IO,即:fcntl:O_ASYNC

引起套接字产生SIGIO信号的情况有:
1监听套接字上有连接请求已完成
-----------------------
2断连请求已发起
3断连请求已完成
4连接的一半已经关闭
----------------------
5数据到达套接字
6数据从套接字发出
7发生异步错误

小结

由1可得,监听套接字适合异步信号IO;

2-7可得异步IO不适合TCP连接套接字;

5-7可得,UDP适合异步信号IO

监听套接字的异步信号IO

server.c
#include<fcntl.h>
#include<signal.h>
...

int listenfd,connfd;

void sig_iohander(int signo)
{
    int rn; 
    char buff[128];
    puts("get sigio...");
    connfd = accept(listenfd,NULL,0);
    if(connfd == -1){perror("accept");return;}
    rn = recv(connfd,buff,127,0);
    if(rn == -1) {perror("recv");return;}
    buff[rn]='\0';
    printf("recv #%s#\n",buff);

    close(connfd);
}

int main(int argc,char*argv[])
{
    struct sockaddr_in cliaddr,servaddr;
    int queuelen=5,i,flag;
    pid_t cpid[WORKERSIZE];

    listenfd = socket(AF_INET,SOCK_STREAM,0);

    signal(SIGIO,sig_iohander);

    flag = fcntl(listenfd,F_GETFL,0);
    flag |= O_NONBLOCK | O_ASYNC;
    fcntl(listenfd,F_SETFL,flag);//将监听套接字设置为非阻塞(非阻塞是因为listenfd发生的连接可能在调用accept的时候,对方已近关闭连接了,这时候如果监听套接字为阻塞,那么进程将长期阻塞直到有新连接完成),异步IO(O_ASYNC)

    fcntl(listenfd,F_SETOWN,getpid()); //设定listenfd上接收到的中断

信号的处理进程ID

    bzero(&servaddr,sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(2989);

    bind(listenfd,(struct sockaddr*)&servaddr,sizeof(servaddr));
    listen(listenfd,queuelen);

    while(scanf("%d",&i))//故意让程序阻塞于命令行io,实则等待SIGIO

的骚扰~
        puts("jump out of scanf block...");
	
    return 0;
}

client.c

...
    sockfd = socket(AF_INET,SOCK_STREAM,0);
    rc = connect(sockfd,(struct sockaddr*)&servaddr,sizeof

(servaddr));
    if(rc == -1) 
    {   
        perror("connect error");
        exit(0);
    }   
    printf("pid#%d connected...\n",getpid());
    char content[128];
    sprintf(content,"client pid=%d say hello...",getpid());
    send(sockfd,content,strlen(content),0);
    shutdown(sockfd,SHUT_WR);
    int rn; 
    while((rn == recv(sockfd,content,127,0)))//rn == 0 : 表示服务端

关闭了写(FIN),即解释为EOF
    {   
        content[rn] = '\0';
        puts(content);
    }   
    printf("pid#%d done...\n",getpid());
...

测试结果:

服务端如下显示:
get sigio...
recv #client pid=2236 say hello...#
get sigio...
recv #client pid=2237 say hello...#
get sigio...
recv #client pid=2238 say hello...#
get sigio...
recv #client pid=2239 say hello...#
get sigio...
recv #client pid=2240 say hello...#
get sigio...
recv #client pid=2241 say hello...#
get sigio...
recv #client pid=2242 say hello...#

抱歉!评论已关闭.