非阻塞IO

相关网络编程函数:http://blog.csdn.net/somehow1002/article/details/72648743

以前各个版本套接字的默认状态是阻塞的,这样带来的时间消耗是巨大的。我们可以修改其为非阻塞版本。

非阻塞式IO方式重写str_cli函数

void str_cli(FILE *fp,int sockfd){
     int maxfdp1,val,stdineof;
     ssize_t n,nwritten;
     fd_set rset,wset;
     char to[MAXLINE],fr[MAXLINE];
     char *toiptr,*tooptr,*friptr,*froptr;
     
     val=Fcntl(sockfd,F_GETFL,0);
     Fcntl(sockfd,F_SETFL,val|O_NONBLOCK);
     
     val=Fcntl(STDIN_FILENO,F_GETFL,0);
     Fcntl(STDIN_FILENO,F_SETFL,val|O_NONBLOCK);
     
     val=Fcntl(STDOUT_FILENO,F_GETFL,0);
     Fcntl(STDOUT_FILENO,F_SETFL,val|O_NONBLOCK);
     
     toiptr=tooptr=to;
     friptr=froptr=fr;
     stdineof=0;
     
     maxfdp1=max(max(STDIN_FILENO,STDOUT_FILENO),sockfd)+1;
     for(;;){
         FD_ZERO(&rset);
         FD_ZERO($wset);
         if(stdineof==0&&toiptr<&to[MAXLINE])
             FD_SET(STDIN_FILENO,&rset);
         if(friptr<&fr[MAXLINE])
             FD_SET(sockfd,&rset);
         if(tooptr!=toiptr)
             FD_SET(sockfd,&wset);
         if(froptr!=friptr)
             FD_SET(STDOUT_FILENO,&wset);
         select(maxfdp1,&rset,&wset,NULL,NULL);
         
        if(FD_ISSET(STDIN_FILENO,&rset)){
            if((n=read(STDIN_FILENO,toiptr,&to[MAXLINE]-toiptr))<0){
                if(errno!=EWOULDBLOCK)
                    err_sys("read error on stdin");
            }else if(n==0){
                fprintf(stderr,"EOF on stdin\n");
                stdineof=1; //all done with stdin
                if(tooptr==toiptr)
                    shutdown(sockfd,SHUT_WR);   //send FIN
            }else{
                fprintf(stderr,"read %d bytes from stdin\n",n);
                toiptr+=n;  //just read
                FD_SET(sockfd,&wset);
            }
        }
        
        if(FD_ISSET(sockfd,&rset)){
            if((n=read(sockfd,friptr,&fr[MAXLINE]-friptr))<0){
                if(errno!=EWOULDBLOCK)
                    err_sys("read error on socket");
            }else if(n==0){
                fprintf(stderr,"EOF on socket");
                if(stdineof)
                    return ;    //normal termination
                else
                    err_quit("str_cli:server terminated prematurely");
            }else{
                fprintf(stderr,"read %d bytes from socket\n",n);
                friptr+=n;
                FD_SET(STDOUT_FILENO,&wset);
            }
        }
        
        if(FD_ISSET(STDOUT_FILENO,&wset)&&((n=friptr-froptr)>0)){
            if((nwritten=write(STDOUT_FILENO,froptr,n))<0){
                if(errno!=EWOULDBLOCK)
                    err_sys("write error to stdout");
            }else{
                fprintf(stderr,"wrote %d bytes to stdout\n",nwritten);
                froptr+=nwritten;
                if(froptr==friptr)
                    froptr=friptr=fr;
            }
        }
        
        if(FD_ISSET(sockfd,&wset)&&((n=toiptr-tooptr)>0)){
            if((nwritten=write(sockfd,tooptr,n))<0){
                if(errno!=EWOULDBLOCK)
                    err_sys("write error to socket");
            }else{
                fprintf(stderr,"wrote %d bytes to socket\n",nwritten);
                tooptr+=nwritten;
                if(tooptr==toiptr){
                    toiptr=tooptr=to;
                    if(stdineof)
                        shutdown(sockfd,SHUT_WR);   //send FIN
                }
            }
        }
    }
}
Fcntl函数如下

int Fcntl(int fd, int cmd, int arg)
{
	int	n;
	if ( (n = fcntl(fd, cmd, arg)) == -1)
		perror("fcntl error");
	return(n);
}

一个更精简版本的非阻塞的str_cli
这也是第一个超越单进程单线程设计范畴的程序。
父进程处理从客户端到服务器的数据,子进程处理从服务器到客户端的数据

void str_cli(FILE *fp,int sockfd)
{
    pid_t pid;
    char sendline[MAXLINE],recvline[MAXLINE];
    
    //child:server -> stdout
    if((pid=fork())==0){    
        while(readline(sockfd,recvline,MAXLINE)>0)
            fputs(recvline,stdout);
        kill(getppid(),SIGTREM);    //in case parent still running when server terminated
        exit(0);
    }
    
    //parent:stdin -> server
    while(fgets(sendline,MAXLINE,fp)!=NULL)
        Writen(sockfd,sendline,strlen(sendline));
    shutdown(sockfd,SHUT_WR);   //EOF on stdin, send FIN
    pause();
    return ;
}
关于执行时间
unix网络编程作者测试str_cli得出时间如下:
最初的停-等版本:354.0s
select+阻塞式IO版本:12.3s
非阻塞式IO版本:6.9s
非阻塞fork版本:8.7s
线程化版本:8.5s(http://)
从结果上看,非阻塞IO版本时间更快,但是鉴于其过高的复杂性,使用非阻塞fork版本是值得的


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hober.z

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值