[第三版]单线程多路复用

第二版的问题

第二版中存在一个问题, 当服务端进程意外终止, 如果客户端正阻塞在输入时, 那么无法接收到通知, 直到按下回车发送时报错才得知服务端已经关闭

client

#include "unp.h"
 
void str_cli(FILE *fp,int sockfd);
 
int main(int argc,char *argv[]){
    int sockfd,i;
    struct sockaddr_in servaddr;
 
    if(argc != 2)
        err_quit("usage: client <ip address>");
 
    sockfd=Socket(AF_INET,SOCK_STREAM,0);
    bzero(&servaddr,sizeof(servaddr));
    servaddr.sin_family=AF_INET;
    servaddr.sin_port=htons(13);
    inet_pton(AF_INET,argv[1],&servaddr.sin_addr);
 
    Connect(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr));
 
    str_cli(stdin,sockfd);
 
    exit(0);
}
 
void str_cli(FILE *fp,int sockfd){
    char buff[MAXLINE];
    fd_set rset;
    int maxfdp1,stdineof;
    int n;
 
    stdineof=0;
    FD_ZERO(&rset);
    for(;;){
        if(stdineof == 0)
            FD_SET(fileno(fp),&rset);
        FD_SET(sockfd,&rset);
        maxfdp1=max(fileno(fp),sockfd)+1;
        Select(maxfdp1,&rset,NULL,NULL,NULL);
 
        if(FD_ISSET(sockfd,&rset)){
            if((n=Read(sockfd,buff,MAXLINE)) == 0){
                if(stdineof == 1)
                    return;
                else
                    err_quit("str_cli: server terminated prematurely");
            }
            Write(fileno(stdout),buff,n);
        }
 
        if(FD_ISSET(fileno(fp),&rset)){
            if((n=Read(fileno(fp),buff,MAXLINE)) == 0){
                stdineof = 1;
                shutdown(sockfd,SHUT_WR);
                FD_CLR(fileno(fp),&rset);
                continue;
            }
            writen(sockfd,buff,n);
        }
    }
}

serv

几点说明:
变量i,sockfd功能相近, 遍历时用
client[FD_SETSIZE]用来保存所有需要读取的fd
maxfd与client中最大的fd相同, maxi是这个最大fd在client中的下标
nready保存当前已经准备就绪的fd数量

#include "unp.h"
 
int main(int argc, char *argv[]){
    int i,maxi,maxfd,listenfd,connfd,sockfd;
    int nready,client[FD_SETSIZE];
    ssize_t n;
    fd_set rset,allset;
    char buf[MAXLINE];
    socklen_t clilen;
    struct sockaddr_in servaddr,cliaddr;
 
    listenfd=Socket(AF_INET,SOCK_STREAM,0);
 
    bzero(&servaddr,sizeof(servaddr));
    servaddr.sin_family=AF_INET;
    servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
    servaddr.sin_port=htons(13);
 
    Bind(listenfd,(struct sockaddr *)&servaddr,sizeof(servaddr));
 
    Listen(listenfd,1024);
 
    maxfd=listenfd;
    maxi=-1;
    for(i=0;i<FD_SETSIZE;i++)
        client[i]=-1;
    FD_ZERO(&allset);
    FD_SET(listenfd,&allset);
 
    for(;;){
        rset=allset;
        nready=Select(maxfd+1,&rset,NULL,NULL,NULL);
 
        if(FD_ISSET(listenfd,&rset)){
            clilen=sizeof(cliaddr);
            connfd=Accept(listenfd,(struct sockaddr *)&cliaddr,&clilen);
 
            for(i=0;i<FD_SETSIZE;i++)
                if(client[i] < 0){
                    client[i]=connfd;
                    break;
                }
            if(i == FD_SETSIZE)
                err_quit("too many clients");
 
            FD_SET(connfd,&allset);
            if(connfd > maxfd)
                maxfd=connfd;
            if(i > maxi)
                maxi=i;
            if(--nready <= 0)
                continue;
        }
 
        for(i=0;i<=maxi;i++){
            if((sockfd=client[i]) < 0)
                continue;
            if(FD_ISSET(sockfd,&rset)){
                if((n=Read(sockfd,buf,MAXLINE)) == 0){
                    Close(sockfd);
                    FD_CLR(sockfd,&allset);
                    client[i]=-1;
                }else
                    writen(sockfd,buf,n);
                if(--nready <= 0)
                    break;
            }
        }
    }
}
posted @ 2016-09-18 22:48  cfans1993  阅读(372)  评论(0编辑  收藏  举报