基于线程池的OpenSSL编程

服务端

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <pthread.h>
#include <semaphore.h>  

SSL_CTX *ctx;
int server_sockfd;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t queue_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t idle_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t *lock_cs;
static long *lock_count;
#define  MAXBUF 1024
#define  MAXTHREAD 20
void *thread_main(void *arg);
typedef struct worker
{
    int socket;
    struct worker *next;
}CThread_worker;

/*线程池结构*/
typedef struct
{
    sem_t pool_sem;
    pthread_t *threadid;
    CThread_worker *queue_head;
    //当前空闲线程数
    int currentIdle;
}CThread_pool;

static CThread_pool *pool = NULL;

void pool_init()
{
    pool = (CThread_pool *)malloc(sizeof(CThread_pool));
    pool->queue_head = NULL;
    sem_init(&(pool->pool_sem), 0, 0);
    pool->threadid = (pthread_t *)malloc(MAXTHREAD * sizeof (pthread_t));
    int i = 0;
    for (i = 0; i < MAXTHREAD; i++)
    {
        pthread_create (&(pool->threadid[i]), NULL, thread_main, NULL);
    }
    pool->currentIdle = MAXTHREAD;
}

pthread_t pthreads_thread_id(void)
{
    pthread_t ret;
    ret = pthread_self();
    return(ret);
}
 
void pthreads_locking_callback(int mode, int type, char *file, int line)
{
    if (mode & CRYPTO_LOCK)
    {
        pthread_mutex_lock(&(lock_cs[type]));
        lock_count[type]++;
    }
    else
    {
        pthread_mutex_unlock(&(lock_cs[type]));
    }
}

void *thread_main(void *arg) 
{
    int  s;
    int  tag;
    int  err;
    SSL  *ssl;
    char buf[1024];
    struct timeval starttime,endtime;
    while(1)
    {
        sem_wait(&pool->pool_sem);
        tag = 0;
        pthread_mutex_lock(&queue_mutex);
        if(pool->queue_head != NULL)
        {
            CThread_worker *tmp = pool->queue_head;
            s = tmp->socket;
            pool->queue_head = tmp->next;
            free(tmp);
            tag = 1;
        }
        pthread_mutex_unlock(&queue_mutex);
        if(tag == 0)
        {
            continue;
        }
        
        ssl = SSL_new (ctx);
        err = SSL_set_fd(ssl, s);

        err = SSL_accept (ssl); 
        if(err < 0)
        {
            perror("sslaccept");
            SSL_free (ssl);
            close(s);
            continue;
        }
        //printf ("SSL connection using %s\n", SSL_get_cipher (ssl));
        memset(buf, 0, 1024);
        err = SSL_read (ssl, buf, sizeof(buf) - 1);
        if(err < 0)
        {
            printf("ssl read err\n");
            SSL_free (ssl);
            close(s);
            continue;
        }
        memset(buf, 0, 1024);
        sprintf(buf, "%s%s%s","HTTP/1.0 200 ok\r\n", "Content-type: text/html\r\n\r\n", "<HTML>Hello World!</HTML>\r\n");
        //发消息给客户端 
        err = SSL_write(ssl, buf, strlen(buf));
        if (err == -1)
        {
            perror("sslwrite");
        }
        SSL_free(ssl);
        close(s);
        pthread_mutex_lock(&idle_mutex);
        pool->currentIdle = pool->currentIdle + 1;
        pthread_mutex_unlock(&idle_mutex);
    }
}

void *thread_main2(void *arg) 
{
    int  s;
    int  tag;
    int  err;
    SSL  *ssl;
    char buf[1024];
    sem_wait(&pool->pool_sem);
    tag = 0;
    pthread_mutex_lock(&queue_mutex);
    if(pool->queue_head != NULL)
    {
        CThread_worker *tmp = pool->queue_head;
        s = tmp->socket;
        pool->queue_head = tmp->next;
        free(tmp);
        tag = 1;
    }
    pthread_mutex_unlock(&queue_mutex);
    if(tag == 0)
    {
        return NULL;
    }
    
    ssl = SSL_new (ctx);
    err = SSL_set_fd(ssl, s);
    
    err = SSL_accept (ssl); 
    if(err < 0)
    {
        perror("sslaccept");
        SSL_free (ssl);
        close(s);
        return ;
    }
    //printf ("SSL connection using %s\n", SSL_get_cipher (ssl));
    memset(buf, 0, 1024);
    err = SSL_read (ssl, buf, sizeof(buf) - 1);
    if(err < 0)
    {
        printf("ssl read err\n");
        SSL_free (ssl);
        close(s);
        return;
    }
    memset(buf, 0, 1024);
    sprintf(buf, "%s%s%s","HTTP/1.0 200 ok\r\n", "Content-type: text/html\r\n\r\n", "<HTML>Hello World!</HTML>\r\n");
    //发消息给客户端 
    err = SSL_write(ssl, buf, strlen(buf));
    if (err == -1)
    {
        perror("sslwrite");
    }
    SSL_free(ssl);
    close(s);
}

int main(int argc,char *argv[])
{
    int server_len;
    struct sockaddr_in server_address;
    int i;
    
    SSL_library_init();
    //载入所有 SSL 算法
    OpenSSL_add_all_algorithms();
    //载入所有 SSL 错误消息
    SSL_load_error_strings();
    //以 SSL V2 和 V3 标准兼容方式产生一个 SSL_CTX ,即 SSL Content Text
    ctx = SSL_CTX_new(SSLv23_server_method());
    //也可以用 SSLv2_server_method() 或 SSLv3_server_method() 单独表示 V2 或 V3标准
    if (ctx == NULL)
    {
        ERR_print_errors_fp(stdout);
        exit(1);
    }
    //载入用户的数字证书, 此证书用来发送给客户端。 证书里包含有公钥
    if (SSL_CTX_use_certificate_file(ctx, "cacert.pem", SSL_FILETYPE_PEM) <= 0)
    {
        ERR_print_errors_fp(stdout);
        exit(1);
    }
    //载入用户私钥
    if (SSL_CTX_use_PrivateKey_file(ctx, "privkey.pem", SSL_FILETYPE_PEM) <= 0)
    {
        ERR_print_errors_fp(stdout);
        exit(1);
    }
    // 检查用户私钥是否正确
    if (!SSL_CTX_check_private_key(ctx)) 
    {
        ERR_print_errors_fp(stdout);
        exit(1);
    }
    
    lock_cs = OPENSSL_malloc(CRYPTO_num_locks() * sizeof(pthread_mutex_t));
    lock_count = OPENSSL_malloc(CRYPTO_num_locks() * sizeof(long));
    
    server_sockfd = socket(AF_INET, SOCK_STREAM, 0);
    for (i=0; i < CRYPTO_num_locks(); i++)
    {
        lock_count[i] = 0;
        pthread_mutex_init(&(lock_cs[i]), NULL);
    }
    
    CRYPTO_set_id_callback((unsigned long (*)())pthreads_thread_id);
    CRYPTO_set_locking_callback((void (*)())pthreads_locking_callback);
    
    server_address.sin_family = AF_INET;
    server_address.sin_addr.s_addr =  htonl(INADDR_ANY);
    server_address.sin_port = htons(8701);
    server_len = sizeof(server_address);

    bind(server_sockfd, (struct sockaddr *)&server_address, server_len);

    if (listen(server_sockfd, 200) == -1)
    {
        perror("listen error");
        exit(1);
    }

    printf("server waiting for connect\n");
    for(i = 0; i < 100; i++)
    {
        int reValue = fork();
        if(reValue == 0)
        {
            break;
        }
    }
    
    pool_init(); 
    
    int err;
    int client_sockfd;
    pthread_t pid;
    SSL *ssl;
    int tag;
    int optval = 1;

    while(1)
    {
        client_sockfd = accept(server_sockfd, NULL, NULL);
        setsockopt(client_sockfd, SOL_SOCKET, SO_REUSEADDR, &optval,sizeof(optval));
        CThread_worker *new_work = (CThread_worker *)malloc(sizeof(CThread_worker));
        new_work->next = NULL;
        new_work->socket = client_sockfd;
        pthread_mutex_lock(&queue_mutex);
        if(pool->queue_head == NULL)
        {
            pool->queue_head = new_work;
        }
        else
        {
            pool->queue_head->next = new_work;
        }
        pthread_mutex_unlock(&queue_mutex);
        
        pthread_mutex_lock(&idle_mutex);
        tag = 0;
        if(pool->currentIdle > 0)
        {
            pool->currentIdle = pool->currentIdle - 1;
            sem_post(&pool->pool_sem);
            tag = 1;
        }
        pthread_mutex_unlock(&idle_mutex);
        if(tag == 1)
        {
            continue;
        }
        printf("create new thread!\n");
        err = pthread_create(&pid, NULL, &thread_main2, NULL);
        pthread_detach(pid);
    }
    SSL_CTX_free(ctx);
    shutdown(server_sockfd, 2);
}

客户端

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <pthread.h>
#include <semaphore.h>  

SSL_CTX *ctx;
int server_sockfd;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t queue_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t idle_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t *lock_cs;
static long *lock_count;
#define  MAXBUF 1024
#define  MAXTHREAD 50
void *thread_main(void *arg);
typedef struct worker
{
    int socket;
    struct worker *next;
}CThread_worker;

/*线程池结构*/
typedef struct
{
    sem_t pool_sem;
    pthread_t *threadid;
    CThread_worker *queue_head;
    //当前空闲线程数
    int currentIdle;
}CThread_pool;

static CThread_pool *pool = NULL;

void pool_init()
{
    pool = (CThread_pool *)malloc(sizeof(CThread_pool));
    pool->queue_head = NULL;
    sem_init(&(pool->pool_sem), 0, 0);
    pool->threadid = (pthread_t *)malloc(MAXTHREAD * sizeof (pthread_t));
    int i = 0;
    for (i = 0; i < MAXTHREAD; i++)
    {
        pthread_create (&(pool->threadid[i]), NULL, thread_main, NULL);
    }
    pool->currentIdle = MAXTHREAD;
}

pthread_t pthreads_thread_id(void)
{
    pthread_t ret;
    ret = pthread_self();
    return(ret);
}
 
void pthreads_locking_callback(int mode, int type, char *file, int line)
{
    if (mode & CRYPTO_LOCK)
    {
        pthread_mutex_lock(&(lock_cs[type]));
        lock_count[type]++;
    }
    else
    {
        pthread_mutex_unlock(&(lock_cs[type]));
    }
}

void *thread_main(void *arg) 
{
    int sockfd;
    SSL  *ssl;
    char buffer[MAXBUF + 1];
    int len;
    int  tag;
    while(1)
    {
        sem_wait(&pool->pool_sem);
        tag = 0;
        pthread_mutex_lock(&queue_mutex);
        if(pool->queue_head != NULL)
        {
            CThread_worker *tmp = pool->queue_head;
            sockfd = tmp->socket;
            pool->queue_head = tmp->next;
            free(tmp);
            tag = 1;
        }
        pthread_mutex_unlock(&queue_mutex);
        
        if(tag == 0)
        {
            continue;
        }
        
        /* 基于 ctx 产生一个新的 SSL */
        ssl = SSL_new(ctx);
        SSL_set_fd(ssl, sockfd);
        /* 建立 SSL 连接 */
        if (SSL_connect(ssl) <= 0)
        {
            perror("SSL connect ");
            //ERR_print_errors_fp(stderr);
            goto finish;
        }
        else
        {
            //printf("Connected with %s encryption\n", SSL_get_cipher(ssl));
        }
        
        bzero(buffer, MAXBUF + 1);
        strcpy(buffer, "from client->server");
        //发消息给服务器
        len = SSL_write(ssl, buffer, strlen(buffer));
        if (len < 0)
        {
            //printf("消息'%s'发送失败!错误代码是%d,错误信息是'%s'\n", buffer, errno, strerror(errno));
            printf("send error\n");
            goto finish;
        }
        else
        {
            //printf("消息'%s'发送成功,共发送了%d个字节!\n", buffer, len);
        }
        
        //接收对方发过来的消息,最多接收 MAXBUF 个字节
        bzero(buffer, MAXBUF + 1);
        // 接收服务器来的消息
        len = SSL_read(ssl, buffer, MAXBUF);
        if (len > 0)
        {
            //printf("接收消息成功:'%s',共%d个字节的数据\n", buffer, len);
        }
        else
        {
            //printf("消息接收失败!错误代码是%d,错误信息是'%s'\n", errno, strerror(errno));
            printf("recvs error\n");
            goto finish;
        }
        
finish:
        //SSL_shutdown(ssl);
        SSL_free(ssl);
        close(sockfd);
        pthread_mutex_lock(&idle_mutex);
        pool->currentIdle = pool->currentIdle + 1;
        pthread_mutex_unlock(&idle_mutex);
    }
}

void *thread_main2(void *arg) 
{
    int sockfd;
    SSL  *ssl;
    char buffer[MAXBUF + 1];
    int len;
    int  tag;
    tag = 0;
    pthread_mutex_lock(&queue_mutex);
    if(pool->queue_head != NULL)
    {
        CThread_worker *tmp = pool->queue_head;
        sockfd = tmp->socket;
        pool->queue_head = tmp->next;
        free(tmp);
        tag = 1;
    }
    pthread_mutex_unlock(&queue_mutex);
    
    if(tag == 0)
    {
        return NULL;
    }
    
    /* 基于 ctx 产生一个新的 SSL */
    ssl = SSL_new(ctx);
    SSL_set_fd(ssl, sockfd);
    /* 建立 SSL 连接 */
    if (SSL_connect(ssl) == -1)
        ERR_print_errors_fp(stderr);
    else
    {
        //printf("Connected with %s encryption\n", SSL_get_cipher(ssl));
    }
    
    bzero(buffer, MAXBUF + 1);
    strcpy(buffer, "from client->server");
    //发消息给服务器
    len = SSL_write(ssl, buffer, strlen(buffer));
    if (len < 0)
    {
        //printf("消息'%s'发送失败!错误代码是%d,错误信息是'%s'\n", buffer, errno, strerror(errno));
        printf("send error!\n");
        goto finish;
    }
    else
    {
        //printf("消息'%s'发送成功,共发送了%d个字节!\n", buffer, len);
    }
    
    //接收对方发过来的消息,最多接收 MAXBUF 个字节
    bzero(buffer, MAXBUF + 1);
    // 接收服务器来的消息
    len = SSL_read(ssl, buffer, MAXBUF);
    if (len > 0)
    {
        //printf("接收消息成功:'%s',共%d个字节的数据\n", buffer, len);
    }
    else
    {
        //printf("消息接收失败!错误代码是%d,错误信息是'%s'\n", errno, strerror(errno));
        printf("recv error!\n");
        goto finish;
    }
    
finish:
    //SSL_shutdown(ssl);
    SSL_free(ssl);
    close(sockfd);
    pthread_mutex_lock(&idle_mutex);
    pool->currentIdle = pool->currentIdle + 1;
    pthread_mutex_unlock(&idle_mutex);
}

int main(int argc,char *argv[])
{
    int server_len;
    struct sockaddr_in dest;
    int i;
    int sockfd;
    
    SSL_library_init();
    //载入所有 SSL 算法
    OpenSSL_add_all_algorithms();
    //载入所有 SSL 错误消息
    SSL_load_error_strings();
    //以 SSL V2 和 V3 标准兼容方式产生一个 SSL_CTX ,即 SSL Content Text
    ctx = SSL_CTX_new(SSLv23_client_method());
    //也可以用 SSLv2_server_method() 或 SSLv3_server_method() 单独表示 V2 或 V3标准
    if (ctx == NULL)
    {
        ERR_print_errors_fp(stdout);
        exit(1);
    }
    
    lock_cs = OPENSSL_malloc(CRYPTO_num_locks() * sizeof(pthread_mutex_t));
    lock_count = OPENSSL_malloc(CRYPTO_num_locks() * sizeof(long));
    server_sockfd = socket(AF_INET, SOCK_STREAM, 0);//创建套接字
    for (i=0; i < CRYPTO_num_locks(); i++)
    {
        lock_count[i] = 0;
        pthread_mutex_init(&(lock_cs[i]), NULL);
    }
    CRYPTO_set_id_callback((unsigned long (*)())pthreads_thread_id);
    CRYPTO_set_locking_callback((void (*)())pthreads_locking_callback);
    
    for(i = 0; i < 1; i++)
    {
        int reValue = fork();
        if(reValue == 0)
        {
            break;
        }
    }
    pool_init();

    int err;
    int client_sockfd;
    pthread_t pid;
    SSL *ssl;
    int tag;
    int optval = 1;
    int count = 0;
    struct timeval starttime,endtime;
    double timeuse;
    gettimeofday(&starttime, 0);
    while(1)
    {
        pthread_mutex_lock(&idle_mutex);
        tag = 0;
        if(pool->currentIdle > 0)
        {
            pool->currentIdle = pool->currentIdle - 1;
            sem_post(&pool->pool_sem);
            tag = 1;
        }
        pthread_mutex_unlock(&idle_mutex);
        if(tag == 0)
        {
            usleep(100);
            continue;
        }
        count++;
        if(count % 1000 == 0)
        {
            printf("process:%d --- 100 finished!\n", i);
            if(count == 10000)
            {
                break;
            }
        }
        /* 创建一个 socket 用于 tcp 通信 */
        if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
        {
            perror("Socket");
            exit(errno);
        }
        //printf("sockfd:%d\n", sockfd);
        memset (&dest, '\0', sizeof(dest));
        dest.sin_family      = AF_INET; 
        dest.sin_addr.s_addr = inet_addr("168.7.1.94");       /* Server IP */ 
        dest.sin_port        = htons(8701);   /* Server Port number */ 
        
        /* 连接服务器 */
        if (connect(sockfd, (struct sockaddr *) &dest, sizeof(dest)) != 0)
        {
            perror("Connect ");
            exit(errno);
        }
        setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval,sizeof(optval));
        CThread_worker *new_work = (CThread_worker *)malloc(sizeof(CThread_worker));
        new_work->next = NULL;
        new_work->socket = sockfd;
        pthread_mutex_lock(&queue_mutex);
        if(pool->queue_head == NULL)
        {
            pool->queue_head = new_work;
        }
        else
        {
            pool->queue_head->next = new_work;
        }
        pthread_mutex_unlock(&queue_mutex);
        
/* 
        pthread_mutex_lock(&idle_mutex);
        tag = 0;
        if(pool->currentIdle > 0)
        {
            pool->currentIdle = pool->currentIdle - 1;
            sem_post(&pool->pool_sem);
            tag = 1;
        }
        pthread_mutex_unlock(&idle_mutex);
        if(tag == 1)
        {
            continue;
        }
        printf("create new thread!\n");
        err = pthread_create(&pid, NULL, &thread_main2, NULL);
        pthread_detach(pid);*/
    }
    gettimeofday(&endtime, 0);
    timeuse = 1000000 * (endtime.tv_sec - starttime.tv_sec) + endtime.tv_usec - starttime.tv_usec;
    printf("SSL timeuse:%f\n", timeuse);
    SSL_CTX_free(ctx);
    shutdown(server_sockfd, 2);
}

生成密钥和证书以及程序编译

openssl genrsa -out privkey.pem 1024
openssl req -new -x509 -key privkey.pem -out cacert.pem -days 1095
gcc -g -o server server.c -I/usr/local/ssl/include -L/usr/local/ssl/lib -lssl -lcrypto -ldl -lpthread
gcc -g -o client client.c -I/usr/local/ssl/include -L/usr/local/ssl/lib -lssl -lcrypto -ldl -lpthread

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值