利用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);
}
原文地址:https://www.cnblogs.com/cfans1993/p/6131898.html