服务端
#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