zoukankan      html  css  js  c++  java
  • 利用select单线程点对点聊天

    select的优点与使用方法

    select用单线程的方法遍历所有待读写的I/O接口, 当有接口可用时就会返回. select可设置电脑阻塞或非阻塞.
    特别注意: 每次select前都要重新初始化集合和相关的时间结构

    使用的基本过程:

    //创建要读写的集合,所有的读接口放一个集合,所有的写接口放另一个集合
    fd_set fileset1;
    fd_set fileset2;
     
    //初始化该集合
    FD_ZERO(&fileset1);
    FD_ZERO(&fileset2);
     
    //向集合中添加要监听的接口
    FD_SET(fd1,&fileset1);
    FD_SET(fd2,&fileset1);
    ...
     
    //开始监听
    int ret=select(maxfd+1,&fileset1,&fileset2,NULL,NULL);
     
    //返回后开始处理
    switch(ret){
         case -1:
             if(errno == EINTR)
                 continue;
             err_quit("select");
         case 0:
             printf("time out
    ");
             continue;
         default:
             if(FD_ISSET(fd1,&fileset))
                 do_service1();
             if(FD_ISSET(fd2,&fileset))
                 do_service2();
              if(FD_ISSET(...)
             break;
    }
    

    实例

    只写了server端的,client端差不多

    #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);
    }
     
    void handler(int signo){
        printf("program terminated
    ");
        exit(0);
    }
     
    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;
    }
     
     
    void recv_service(int fd){
        char buf[1024]={0};
        int ret=readline(fd,buf,sizeof(buf));
        if(ret == -1)
            err_quit("read");
        else if(ret == 0){
            printf("peer closed
    ");
            exit(0);
        }
     
        fputs(buf,stdout);
    }
     
    void send_service(int fd){
        char buf[1024];
        if(fgets(buf,sizeof(buf),stdin) != NULL){
            writen(fd,buf,strlen(buf));
        }
    }
    int main(int argc,char *argv[]){
        int sockfd,connfd;
        socklen_t len;
        struct sockaddr_in addr,client;
     
        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");
     
        len=sizeof(client);
        connfd=accept(sockfd,(struct sockaddr *)&client,&len);
        if(connfd < 0)
            err_quit("accept");
     
        struct sockaddr_in peeraddr;
        socklen_t lenth=sizeof(peeraddr);
        if(getpeername(connfd,(struct sockaddr *)&peeraddr,&lenth) < 0)
            err_quit("getpeername");
        printf("peer addr=%s,peer port=%d
    ",inet_ntoa(peeraddr.sin_addr),ntohs(peeraddr.sin_port));
     
        char buf[1024];
        bzero(buf,sizeof(buf));
     
        fd_set fileset;
        while(1){
            FD_ZERO(&fileset);
            FD_SET(STDIN_FILENO,&fileset);
            FD_SET(connfd,&fileset);
     
            int maxfd=MAX(STDIN_FILENO,connfd);
            int ret=select(maxfd+1,&fileset,NULL,NULL,NULL);
            switch(ret){
                case -1:
                    if(errno == EINTR)
                        continue;
                    err_quit("select");
                case 0:
                    printf("time out
    ");
                    continue;
                default:
                    if(FD_ISSET(connfd,&fileset))
                        recv_service(connfd);
                    if(FD_ISSET(STDIN_FILENO,&fileset))
                        send_service(connfd);
                    break;
            }
        }
        exit(0);
    }
    
  • 相关阅读:
    看别人的代码学习的css
    Font Awesome
    响应式网站设计
    css兼容性的问题
    英语
    我的bootstrap使用的历程
    jquery的常用的容易忘记的东西
    jquery基本方法
    js与jquery的区别
    134123
  • 原文地址:https://www.cnblogs.com/cfans1993/p/6131898.html
Copyright © 2011-2022 走看看