• [国嵌攻略][181][线程池技术优化]


    服务器单发模式

    初始化->等待连接->处理请求->关闭连接->再次等待连接

    服务器并发模式

    初始化->等待连接->交给子进程处理请求->再次等待连接

    单发服务器不能同时处理多个客户端请求,并发服务器则可以同时处理多个客户端请求。并发服务器一般通过创建线程来处理多个客户端请求。当处理的客户端到达上万个时,不断的创建和销毁线程对服务器是一笔很大的开销。通过线程池技术,预先创建大量线程。在使用时直接从线程池中取出,用完后放回线程池。这样就可以大大减少对线程的创建和销毁开销。

    线程池工作原理

    线程池就是有一堆已经创建好了的线程,当有新的任务需要处理的时候,就从这个池子里面取出一个空闲等待的线程来处理该任务,当处理完成了就再次把该线程放回池中,以供后面的任务再次使用,当池子里面的线程全都处理忙碌状态时,这时新到来的任务需要稍作等待。

    线程的创建和销毁比之进程的创建和销毁是轻量级的,但是当我们的任务需要大量进行大量线程的创建和销毁操作时,这个消耗就会变的相当大。线程池的好处就在于线程复用,当一个任务处理完成后,当前线程可以继续处理下一个任务,而不是销毁后再创建,非常适用于连续产生大量并发任务的场合。

    优化服务器端程序

    编译程序

    gcc -lssl -lpthread server.c -o server

    server.c

    /********************************************************************
    *名称:server.c
    *作者:D
    *时间:2016.04.06
    *功能:网络安全传输系统服务端
    *********************************************************************/
    
    /********************************************************************
    *头文件
    *********************************************************************/
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #include <fcntl.h>
    #include <sys/stat.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    
    #include <openssl/ssl.h>
    #include <openssl/err.h>
    
    #include <pthread.h>
    
    /********************************************************************
    *宏定义
    *********************************************************************/
    #define SERVER_PORT 3333          //网络端口
    
    /********************************************************************
    *类型定义
    *********************************************************************/
    //线程任务
    typedef struct cthread_task{
        void *(*process)(int arg);    //任务函数
        int arg;                      //任务参数
        struct cthread_task *next;    //任务指针
    }Cthread_task;
    
    //线程池子
    typedef struct cthread_poll{
        pthread_mutex_t queue_lock;   //互斥变量
        pthread_cond_t queue_ready;   //条件变量
        Cthread_task *queue_head;     //等待队列
        
        pthread_t *threadId;          //线程编号
        int max_thread_num;           //线程数量
        int cur_task_size;            //等待数量
        int shutdown;                 //销毁标志
    }Cthread_pool;
    
    /********************************************************************
    *全局变量
    *********************************************************************/
    SSL_CTX *ctx;               //会话环境
    Cthread_pool *threadPool;   //线程池子
    
    /********************************************************************
    *函数原型
    *********************************************************************/
    int main(int argc, char **argv);
    void *process(int arg);
    void upload(SSL *ssl);
    void download(SSL *ssl);
    
    void pool_init(int max_thread_num);
    void *thread_routine(void *arg);
    int pool_destroy();
    int pool_add_task(void *(process)(int arg), int arg);
    
    /********************************************************************
    *名称:main
    *参数:
    *    argc   参数数量
    *    argv   参数列表
    *返回:
    *    stat   0 成功
    *          -1 失败
    *功能:主函数
    *********************************************************************/
    int main(int argc, char **argv){
        //初始会话
        SSL_library_init();                          //初始化加密库
        OpenSSL_add_all_algorithms();                //载入加密算法
        SSL_load_error_strings();                    //载入错误输出
        
        ctx = SSL_CTX_new(SSLv23_server_method());   //服务器为模式
        
        //设置会话
        int isCert, isPriv;
        
        isCert = SSL_CTX_use_certificate_file(ctx, "./certkey.pem", SSL_FILETYPE_PEM);   //载入数字证书
        if(isCert == -1){
            ERR_print_errors_fp(stdout);
            return -1;
        }
        
        isPriv = SSL_CTX_use_PrivateKey_file(ctx, "./privkey.pem", SSL_FILETYPE_PEM);    //载入用户私钥
        if(isPriv == -1){
            ERR_print_errors_fp(stdout);
            return -1;
        }
        
        //检测会话
        int isCheck;
        
        isCheck = SSL_CTX_check_private_key(ctx);
        if(isCheck == 0){
            ERR_print_errors_fp(stdout);
            return -1;
        }
        
        //初始标志
        int serverfd;
        
        serverfd = socket(AF_INET, SOCK_STREAM, 0);
        if(serverfd == -1){
            printf("Can not create socket!
    ");
            return -1;
        }
        
        //绑定地址
        struct sockaddr_in serverAddr;
        int isBand;
        
        serverAddr.sin_family = AF_INET;                   //设置协议
        serverAddr.sin_port = htons(SERVER_PORT);          //设置端口
        serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);    //设置地址
        bzero(serverAddr.sin_zero, 8);                     //设置为零
        
        isBand = bind(serverfd, (struct sockaddr *)&serverAddr, sizeof(struct sockaddr));
        if(isBand == -1){
            printf("Can not bind!
    ");
            return -1;
        }
        
        //监听端口
        int isListen;
        
        isListen = listen(serverfd, 5);
        if(isListen == -1){
            printf("Can not listen!
    ");
            return -1;
        }
        
        //初始线程
        pool_init(5);
        
        //处理连接
        while(1){
            //等待连接
            socklen_t clientAddrLen;
            struct sockaddr_in clientAddr;
            int clientfd;
    
            clientAddrLen = sizeof(struct sockaddr);
            clientfd = accept(serverfd, (struct sockaddr *)&clientAddr, &clientAddrLen);
            if(clientfd == -1){
                printf("Can not accept!
    ");
                return -1;
            }
            
            //添加任务
            pool_add_task(process, clientfd);
        }
        
        //销毁线程
        pool_destroy();
        
        //关闭连接
        close(serverfd);
        
        //销毁会话
        SSL_CTX_free(ctx);
    }
    
    /********************************************************************
    *名称:process
    *参数:
    *    arg   任务参数
    *返回:
    *    none
    *功能:处理线程任务
    *********************************************************************/
    void *process(int arg){
        //连接 SSL
        SSL *ssl;
        int isAccept;
        
        ssl = SSL_new(ctx);          //构造 SSL
        SSL_set_fd(ssl, arg);        //绑定 SSL
        
        isAccept = SSL_accept(ssl);  //连接 SSL
        if(isAccept == -1){
            ERR_print_errors_fp(stdout);
            exit(-1);
        }
        
        //处理菜单
        while(1){
            //读取命令
            char cmd;
        
            SSL_read(ssl, (void *)&cmd, sizeof(cmd));
            
            //处理命令
            switch(cmd){
                //上传文件
                case 'U':
                    upload(ssl);
                    break;
                
                //下载文件
                case 'D':
                    download(ssl);
                    break;
                    
                //退出程序
                case 'Q':
                    break;
                    
                //其他命令
                default:
                    break;
            }
            
            //是否退出
            if(cmd == 'Q'){
                break;
            }
        }
        
        //关闭 SSL
        SSL_shutdown(ssl);  //关闭 SSL
        SSL_free(ssl);      //释放 SSL
        
        //关闭连接
        close(arg);
    }
    
    /********************************************************************
    *名称:upload
    *参数:
    *    ssl   客户端标志
    *返回:
    *    none
    *功能:上传文件
    *********************************************************************/
    void upload(SSL *ssl){
        //接收文件名称
        int namesize;
        char filename[20];
        
        SSL_read(ssl, (void *)&namesize, sizeof(namesize));
        SSL_read(ssl, (void *)&filename, namesize);
        
        //创建上传文件
        int fd;
        
        fd = open(filename, O_RDWR | O_CREAT, 0777);
        if(fd == -1){
            printf("Can not create file!
    ");
            return ;
        }
        
        //接收文件长度
        int fileszie;
        
        SSL_read(ssl, &fileszie, sizeof(fileszie));
        
        //接收文件内容
        char buf[1024];
        int  num;
        
        num = SSL_read(ssl, (void *)buf, sizeof(buf));
        while(num > 0){
            //写入接收内容
            write(fd, (void *)&buf, num);
            
            //是否接收结束
            fileszie = fileszie - num;
            if(fileszie == 0){
                break;
            }
            
            //接收文件内容
            num = SSL_read(ssl, (void *)buf, sizeof(buf));
        }
        
        //关闭上传文件
        close(fd);
    }
    
    /********************************************************************
    *名称:download
    *参数:
    *    ssl   客户端标志
    *返回:
    *    none
    *功能:下载文件
    *********************************************************************/
    void download(SSL *ssl){
        //接收文件名称
        int namesize;
        char filename[20];
        
        SSL_read(ssl, (void *)&namesize, sizeof(namesize));
        SSL_read(ssl, (void *)&filename, namesize);
        
        //打开下载文件
        int fd;
        
        fd = open(filename, O_RDONLY);
        if(fd == -1){
            printf("Can not open file!
    ");
            return ;
        }
        
        //发送文件长度
        struct stat fstat;
        int isState;
        
        isState = stat(filename, &fstat);
        if(isState == -1){
            printf("Can not get file state!
    ");
            return ;
        }
        
        SSL_write(ssl, (void *)&(fstat.st_size), sizeof(fstat.st_size));
        
        //发送文件内容
        char buf[1024];
        int  num;
        
        num = read(fd, (void *)buf, sizeof(buf));
        while(num > 0){
            //发送文件内容
            SSL_write(ssl, (void *)&buf, num);
            
            //读取文件内容
            num = read(fd, (void *)buf, sizeof(buf));
        }
        
        //关闭下载文件
        close(fd);
    }
    
    /*----------------------------------------分割线----------------------------------------*/
    
    /********************************************************************
    *名称:pool_init
    *参数:
    *    max_thread_num   线程数量
    *返回:
    *    none
    *功能:初始线程池子
    *********************************************************************/
    void pool_init(int max_thread_num){
        //初始线程池子
        threadPool = (Cthread_pool *)malloc(sizeof(Cthread_pool));                        //构造线程池子
        
        pthread_mutex_init(&(threadPool->queue_lock), NULL);                              //设置互斥变量
        pthread_cond_init(&(threadPool->queue_ready), NULL);                              //设置条件变量
        threadPool->queue_head = NULL;                                                    //设置等待队列
        
        threadPool->threadId = (pthread_t *)malloc(max_thread_num * sizeof(pthread_t));   //分配线程编号
        threadPool->max_thread_num = max_thread_num;                                      //设置线程数量
        threadPool->cur_task_size = 0;                                                    //设置等待数量
        threadPool->shutdown = 0;                                                         //设置销毁标志
        
        //添加线程池子
        int i;
        
        for(i = 0; i < max_thread_num; i++){
            pthread_create(&(threadPool->threadId[i]), NULL, thread_routine, NULL);
        }
    }
    
    /********************************************************************
    *名称:thread_routine
    *参数:
    *    arg   参数
    *返回:
    *    none
    *功能:处理线程池子
    *********************************************************************/
    void *thread_routine(void *arg){
        //处理线程池子
        while(1){
            //上锁线程池子
            pthread_mutex_lock(&(threadPool->queue_lock));
            
            //是否等待池子
            while( (threadPool->cur_task_size == 0) && (!threadPool->shutdown) ){
                printf("Thread 0x%x is waiting!
    ", pthread_self());
                pthread_cond_wait(&(threadPool->queue_ready), &(threadPool->queue_lock));
            }
            
            //是否销毁池子
            if(threadPool->shutdown){
                //解锁线程池子
                pthread_mutex_unlock(&(threadPool->queue_lock));
                
                //结束线程池子
                printf("Thread 0x%x is eixting!
    ", pthread_self());
                pthread_exit(NULL);
            }
            
            //设置线程池子
            Cthread_task *task;
            
            task = threadPool->queue_head;
            threadPool->queue_head = threadPool->queue_head->next;
            threadPool->cur_task_size--;
            
            //解锁线程池子
            pthread_mutex_unlock(&(threadPool->queue_lock));
            
            //处理线程任务
            printf("Thread 0x%x is working!
    ", pthread_self());
            (*(task->process))(task->arg);
            
            //释放线程任务
            free(task);
            task = NULL;
        }
        
        //结束线程池子
        printf("Thread 0x%x is eixting!
    ", pthread_self());
        pthread_exit(NULL);
    }
    
    /********************************************************************
    *名称:pool_destroy
    *参数:
    *    none
    *返回:
    *    stat   0 成功
    *          -1 失败
    *功能:销毁线程池子
    *********************************************************************/
    int pool_destroy(){
        //是否已经销毁
        if(threadPool->shutdown){
            return -1;                  //防止多次销毁
        }else{
            threadPool->shutdown = 1;   //设置销毁标志
        }
        
        //唤醒所有线程
        pthread_cond_broadcast(&(threadPool->queue_ready));
        
        //阻塞线程任务
        int i;
        
        for(i = 0; i < threadPool->max_thread_num; i++){
            pthread_join(threadPool->threadId[i], NULL);
        }
        
        //释放线程编号
        free(threadPool->threadId);
        
        //销毁等待队列
        Cthread_task *task = NULL;
        
        while(threadPool->queue_head != NULL){
            //取出任务
            task = threadPool->queue_head;
            threadPool->queue_head = threadPool->queue_head->next;
            
            //释放任务
            free(task);
        }
        
        //销毁相关变量
        pthread_mutex_destroy(&(threadPool->queue_lock));
        pthread_cond_destroy(&(threadPool->queue_ready));
        
        //释放线程池子
        free(threadPool);
        threadPool = NULL;
        
        return 0;
    }
    
    /********************************************************************
    *名称:pool_add_task
    *参数:
    *    process   任务函数
    *    arg       任务参数
    *返回:
    *    stat   0 成功
    *          -1 失败
    *功能:添加线程任务
    *********************************************************************/
    int pool_add_task(void *(process)(int arg), int arg){
        //初始线程任务
        Cthread_task *task;
        
        task = (Cthread_task *)malloc(sizeof(Cthread_task));   //构造线程任务
        
        task->process = process;                               //设置任务函数
        task->arg = arg;                                       //设置任务参数
        task->next = NULL;                                     //设置任务指针
        
        //上锁等待队列
        pthread_mutex_lock(&(threadPool->queue_lock));
        
        //添加线程任务
        Cthread_task *node;
    
        node = threadPool->queue_head;
        if(node != NULL){
            //定位队列尾部
            while(node->next != NULL){
                node = node->next;
            }
            
            //添加线程任务
            node->next = task;
        }else{
            //添加线程任务
            threadPool->queue_head = task;
        }
        
        //设置线程池子
        threadPool->cur_task_size++;
        
        //解锁等待队列
        pthread_mutex_unlock(&(threadPool->queue_lock));
        
        //唤醒等待队列
        pthread_cond_signal(&(threadPool->queue_ready));
        
        return 0;
    }
  • 相关阅读:
    Java IO编程中的几个概念
    java强转与继承关系的加深理解:object[]的数组无法强转为String[]的数组
    java反射机制获取对象中父类属性对象
    intealij idea中报错:Error during artifact deployment. See server log for details
    自定义数据属性
    字符集属性
    HTMLDocument的变化
    动态添加对象子对象,防止命名冲突
    焦点管理
    HTML5与相关类的扩充
  • 原文地址:https://www.cnblogs.com/d442130165/p/5359752.html
Copyright © 2020-2023  润新知