zoukankan      html  css  js  c++  java
  • 用select实现多客户端连接

    server.c

    把accept也看成是一个read类型的函数, 于是我们可以把sockfd也放入到select中
    maxi标记当前客户端连接数组的最大下标
    select返回值为当前已经准备就绪的fd总数

    #include <unistd.h>
    #include <netdb.h>
    #include <errno.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include <signal.h>
    #include <sys/wait.h>
    #include <sys/select.h>
    #include <sys/socket.h>
    #include <arpa/inet.h>
    #include <netinet/in.h>
     
    #define MAX(a,b) a>b?a:b;
     
    void err_quit(const char *s){
        perror(s);
        exit(1);
    }
     
    ssize_t readn(int fd,void *buff,size_t count){
        char *buffp;
        ssize_t nread;
        size_t nleft;
     
        buffp=(char *)buff;
        nleft=count;
        while(nleft > 0){
            if((nread = read(fd,buffp,nleft)) < 0){
                if(errno == EINTR)
                    continue;
                else
                    return -1;
            }else if(nread == 0)
                break;
            nleft -= nread;
            buffp += nread;
        }
        return count-nleft;
    }
     
    ssize_t writen(int fd,const void *buff,size_t n){
        size_t nleft;
        ssize_t nwritten;
        const char *ptr;
     
        ptr=buff;
        nleft=n;
        while(nleft > 0){
            if((nwritten=write(fd,ptr,nleft)) < 0){
                if(nwritten < 0 && errno == EINTR)
                    continue;
                else
                    return -1;
            }else if(nwritten == 0)
                break;
            nleft -= nwritten;
            ptr += nwritten;
        }
        return n-nleft;
    }
     
    ssize_t recv_peek(int fd,void *buf,size_t len){
        ssize_t ret;
        while(1){
            ret=recv(fd,buf,len,MSG_PEEK);
            if(ret == -1 && errno == EINTR)
                continue;
            return ret;
        }
    }
     
    ssize_t readline(int fd,void *buf,size_t maxline){
        ssize_t ret;
        size_t nread;
        size_t nleft;
        char *bufp;
     
        bufp=buf;
        nleft=maxline;
        while(1){
            ret=recv_peek(fd,buf,nleft);
            if(ret < 0)
                return ret;
            else if(ret == 0)
                return ret;
     
            nread=ret;
            int i;
            for(i=0;i<nread;i++){
                if(bufp[i] == '
    '){
                    ret=readn(fd,bufp,i+1);
                    if(ret != i+1)
                        err_quit("readn");
     
                    return ret;
                }
            }
     
            if(nread > nleft)
                err_quit("readn");
     
            nleft -= nread;
            ret=readn(fd,bufp,nread);
            if(ret != nread)
                err_quit("readn");
     
            bufp += nread;
        }
     
        return -1;
    }
     
    int main(int argc,char *argv[]){
        int i,maxi,maxfd,tmpfd,sockfd,connfd;
        socklen_t len;
        struct sockaddr_in addr,client;
        fd_set rset,allset;
        int nready,clientfd[FD_SETSIZE];
        ssize_t n;
        char buf[1024];
     
        if((sockfd=socket(PF_INET,SOCK_STREAM,0)) < 0)
            err_quit("sockfd");
     
        bzero(&addr,sizeof(addr));
        addr.sin_family=AF_INET;
        addr.sin_addr.s_addr=htonl(INADDR_ANY);
        addr.sin_port=htons(5566);
     
        int on=1;
        if(setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)) <0)
            err_quit("setsockopt");
     
        if(bind(sockfd,(struct sockaddr *)&addr,sizeof(addr))<0)
            err_quit("bind");
     
        if(listen(sockfd,10)<0)
            err_quit("listen");
     
        maxfd=sockfd;
        maxi=-1;
        for(i=0;i<FD_SETSIZE;i++)
            clientfd[i]=-1;
        FD_ZERO(&allset);
        FD_SET(sockfd,&allset);
        while(1){
            rset=allset;
            nready=select(maxfd+1,&rset,NULL,NULL,NULL);
     
            if(nready == -1){
                if(errno == EINTR)
                    continue;
                else
                    err_quit("select");
            }
     
            if(FD_ISSET(sockfd,&rset)){
                len=sizeof(client);
                connfd=accept(sockfd,(struct sockaddr *)&client,&len);
                if(connfd < 0)
                    err_quit("accept");
     
                for(i=0;i<FD_SETSIZE;i++){
                    if(clientfd[i] < 0){
                        clientfd[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((tmpfd=clientfd[i]) < 0)
                    continue;
                if(FD_ISSET(tmpfd,&rset)){
                    bzero(buf,sizeof(buf));
                    if((n=readline(tmpfd,buf,sizeof(buf))) == 0){
                        close(tmpfd);
                        FD_CLR(tmpfd,&allset);
                        clientfd[i]=-1;
                    }
                    write(STDOUT_FILENO,buf,n);
                    writen(tmpfd,buf,n);
     
                    if(--nready <= 0)
                        break;
                }
            }
        }
    }
    

    client.c

    fileno函数的作用把FILE *型转换电脑int fd型
    此实例用了shutdown方法

    #include <unistd.h>
    #include <signal.h>
    #include <errno.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include <sys/socket.h>
    #include <sys/types.h>
    #include <arpa/inet.h>
    #include <netinet/in.h>
     
    #define MAX(a,b) a>b?a:b;
     
    void err_quit(const char *s){
        perror(s);
        exit(1);
    }
     
    ssize_t readn(int fd,void *buff,size_t count){
        size_t nleft;
        ssize_t nread;
        char *ptr;
     
        nleft=count;
        ptr=(char *)buff;
        while(nleft > 0){
            if((nread=read(fd,ptr,nleft)) < 0){
                if(errno == EINTR)
                    continue;
                else
                    return -1;
            }else if(nread == 0)
                break;
     
            ptr += nread;
            nleft -= nread;
        }
     
        return count - nleft;
    }
     
    ssize_t writen(int fd,const void *buff,size_t n){
        size_t nleft;
        ssize_t nwritten;
        const char *ptr;
     
        nleft=n;
        while(n > 0){
            if((nwritten=write(fd,buff,nleft)) < 0){
                if(errno == EINTR)
                    continue;
                else
                    return -1;
            }else if(nwritten == 0)
                break;
     
            nleft -= nwritten;
            ptr += nwritten;
        }
     
        return n-nleft;
    }
    /* if have any data then return */
    ssize_t recv_peek(int fd,void *buf,size_t len){
        ssize_t ret;
        while(1){
            ret=recv(fd,buf,len,MSG_PEEK);
            if(ret == -1 && errno == EINTR)
                continue;
            return ret;
        }
    }
     
    ssize_t readline(int fd,void *buf,size_t maxline){
        ssize_t ret;
        size_t nread;
        size_t nleft;
        char *bufp;
     
        bufp=buf;
        nleft=maxline;
        while(1){
            ret=recv_peek(fd,buf,nleft);
            if(ret < 0)
                return ret;
            else if(ret == 0)
                return ret;
     
            nread=ret;
            int i;
            for(i=0;i<nread;i++){
                if(bufp[i] == '
    '){
                    ret=readn(fd,bufp,i+1);
                    if(ret != i+1)
                        err_quit("readn");
     
                    return ret;
                }
            }
     
            if(nread > nleft)
                err_quit("nread");
     
            nleft -= nread;
            ret=readn(fd,bufp,nread);
            if(ret != nread)
                err_quit("readn");
     
            bufp += nread;
        }
     
        return -1;
    }
     
    int main(int argc,char *argv[]){
        int sockfd,maxfd;
        int nready;
        struct sockaddr_in servaddr;
        fd_set fileset;
        char buf[1024];
        int stdineof;
     
        if((sockfd=socket(PF_INET,SOCK_STREAM,0)) < 0)
            err_quit("socket");
     
        bzero(&servaddr,sizeof(servaddr));
        servaddr.sin_family=AF_INET;
        servaddr.sin_addr.s_addr=inet_addr("127.0.0.1");
        servaddr.sin_port=htons(5566);
     
        if(connect(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr)) <0)
            err_quit("connect");
     
        bzero(buf,sizeof(buf));
     
        FD_ZERO(&fileset);
        stdineof=0;
        while(1){
            if(stdineof == 0)
                FD_SET(fileno(stdin),&fileset);
            FD_SET(sockfd,&fileset);
     
            maxfd=MAX(fileno(stdin),sockfd);
            nready=select(maxfd+1,&fileset,NULL,NULL,NULL);
     
            if(nready == -1){
                if(errno == EINTR)
                    continue;
                else
                    err_quit("select");
            }
     
            if(FD_ISSET(fileno(stdin),&fileset)){
                if(fgets(buf,sizeof(buf),stdin) == NULL){
                    stdineof=1;
                    shutdown(sockfd,SHUT_WR);
                    FD_CLR(fileno(stdin),&fileset);
                    continue;
                }else{
                    writen(sockfd,buf,strlen(buf));
                    bzero(buf,sizeof(buf));
                }
            }
     
            if(FD_ISSET(sockfd,&fileset)){
                int ret=readline(sockfd,buf,sizeof(buf));
                if(ret == -1)
                    err_quit("read");
                if(ret == 0){
                    if(stdineof == 1)
                        exit(0);
                    else
                        err_quit("readline");
                }
                fputs(buf,stdout);
                bzero(buf,sizeof(buf));
            }
        }
    }
    
  • 相关阅读:
    mysql 基础学习2
    mysql 基础学习1
    awk 截取某段时间的日志
    Kinaba 简单画图
    ELK系统分析Nginx日志并对数据进行可视化展示
    ELK日志分析平台搭建全过程
    python linecache模块读取文件的方法
    python windows 远程执行bat
    PHP常用函数封装
    OneinStack 安装
  • 原文地址:https://www.cnblogs.com/cfans1993/p/6131896.html
Copyright © 2011-2022 走看看