select 服务器 客户端 缩水版

tcpserver.c

int main(int argc, char**argv)
{
    int listenfd = socket(AF_INET,SOCK_STREAM,0);
    struct sockaddr_in serv_addr, client_addr;
    socklen_t client_len = sizeof(client_addr);
    memset(&serv_addr,0,sizeof(serv_addr));
    memset(&client_addr,0,sizeof(client_addr));
    
    serv_addr.sin_addr.s_addr = INADDR_ANY; //绑定所有ip
    serv_addr.sin_family=AF_INET;
    serv_addr.sin_port = htons(PORT);
    int opt = 1;
    socklen_t  optlen = sizeof(opt);
    
    //设置复用ip
    if(setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,(void*)&opt,optlen) < 0){
        perror("setsockopt");
        return  0;
    }
 
    //设置ip port
    if(bind(listenfd,(SA*)&serv_addr,sizeof(serv_addr)) < 0){
        perror("bind");
        return 0;
    }
    
    //BACKLOG = 10
    if(listen(listenfd,BACKLOG) < 0){
        perror("listen");
        return 0;
    }
    
    //一些变量,下面会用到
    int nready = 0,client[FD_SETSIZE] , maxfd = listenfd , connfd = 0,maxi = -1;
    
    // client 用于存储 客户描述符
    for(int i = 0; i < FD_SETSIZE ; ++i)
        client[i] = -1;
    fd_set rset ,allset;
    FD_ZERO(&allset);
    
    //把监听套接字先置位
    FD_SET(listenfd,&allset);
    int clientfd = -1 , n = 0 , i = 0;
    char buf[BUFSIZ];
    while(1){
        //select 每次将修改rset,需要重置
        rset = allset;
        nready = select(maxfd+1,&rset,NULL,NULL,NULL);
        printf("nread : %d \n" , nready);
        
        //可能被信号打断
        if(nready < 0){
            perror("select");
            continue;
        }
        //客户链接 进来
        if(FD_ISSET(listenfd,&rset)){
            client_len = sizeof(client_addr);
            connfd = accept(listenfd,(SA*)&client_addr,&client_len);
            printf("a client : %d\n" , connfd);
            
            //找个位置放进去
            for(i = 0; i < FD_SETSIZE; ++i){
                if(client[i] < 0) {
                    client[i] = connfd;
                    break;
                }
            }
            //服务器已满
            if(FD_SETSIZE == i){
                close(connfd);
                puts("server is full");
            }
            else {
                
                //把客户fd 放入监听集合中
                FD_SET(connfd,&allset);
                if(connfd > maxfd)
                    maxfd = connfd;
                //client 索引
                if( i > maxi)
                    maxi = i;
                //如果数量为0 则不需要往下继续了
                if(--nready == 0)
                    continue;
            }
        }
        
        for(int i = 0 ; i <= maxi;++i){
            
            if((clientfd = client[i]) <0 )
                continue;
            
            //直到找到一个可读的fd
            if(FD_ISSET(clientfd,&rset)){
                printf("clientfd : %d is ready\n", clientfd);
                
                //如果对断关闭了 
                if((n = read(clientfd,buf,BUFSIZ)) <= 0){
                    printf("clientfd : %d closed\n",clientfd);
                    //清空当前fd 所存在的地方
                    close(clientfd);
                    FD_CLR(clientfd,&allset);
                    client[i] = -1;
                } else{
                    write(clientfd,buf,n);
                }
                if(--nready == 0)
                    break;
            }
        }
    }
 
 
    return 0;
}

tcpclient.c

void str_echo(int sockfd);
int max(int a, int b){
    return a > b ? a : b;
}
int main(int argc, char**argv)
{
    if(argc != 2){
        puts("ip addr");
        return 0;
    }
 
    int sockfd = socket(AF_INET,SOCK_STREAM,0);
    struct sockaddr_in sin;
    memset(&sin,0,sizeof(sin));
    sin.sin_port = htons(PORT);
    sin.sin_family = AF_INET;
 
    //把字符串转成网络字节序
    inet_pton(AF_INET,argv[1],&sin.sin_addr);
 
    connect(sockfd,(SA*)&sin,sizeof(sin));
    str_echo(sockfd);
 
    return 0;
}
 
void str_echo(int sockfd){
    int maxfd = sockfd;
    int eof = 0 , readn = 0 , fd_num = 0, n= 0;
    char buf[BUFSIZ];
    fd_set rset;
    FD_ZERO(&rset);
 
    while(1)
    {
        //EOF ==》 CTRL+D
        if(0 == eof){
            FD_SET(0,&rset);
        }
 
        //select 将修改rset ,每次重置
        FD_SET(sockfd,&rset);
        maxfd = max(0,sockfd);
        fd_num = select(maxfd+1,&rset,NULL,NULL,NULL);
        printf("fd_num : %d\n" , fd_num);
 
        //如果是套接字可读
        if(FD_ISSET(sockfd,&rset)){
            //服务器关闭
            if((n=read(sockfd,buf,BUFSIZ)) <= 0){
                if(eof == 1){
                    puts("server closed");
                    break;
                }
                else {
                    puts("server ter");
                    break;
                }
 
            }
            buf[n] = 0;
            printf("recv from serv:%s\n" , buf);
        }
 
        //如果是输入端可读
        if(FD_ISSET(0,&rset)){
 
            //如果ctrl + d
            if((n = read(0,buf,BUFSIZ)) <= 0){
                printf("client closing\n");
 
                //先发送Fin , 等服务端close
                shutdown(sockfd,SHUT_WR);
                eof = 1;
                FD_CLR(0,&rset);
                continue;
            }
            write(sockfd,buf,n);
        }
    }
}

相关推荐