TCP多线程并发服务器+线程池+echo

来源:互联网 发布:仿720云全景制作源码 编辑:程序博客网 时间:2024/05/29 03:10

这个架构容易写,在《Unix网络编程》中可以看到性能也还可以,最关键是我学会了。

基本思路就是服务器接收到一个客户的请求,就将个这个请求的任务添加到线程池的任务队列中,使用AddWork(void* (*func)(void *arg), void *arg)。

因此我们可以将自己的业务代码写在void* (*func)(void *arg)中,然后就OK了。我这里的业务是一个服务器echo客户端。

先看服务器端的代码:

线程池:

/* * ThreadPool.h * *  Created on: 2014年4月21日 *      Author: tomcat */#ifndef THREADPOOL_H_#define THREADPOOL_H_#include <stdlib.h>#include <pthread.h>typedef struct work{void* (*func)(void *arg);void *arg;struct work *next;}tpool_work_t;typedef struct{int threadNum;bool shutDown;tpool_work_t* head;tpool_work_t* tail;pthread_t *tid;pthread_mutex_t queueMutex;pthread_cond_t queueReady;}tpool;static tpool *thread_pool = NULL;int CreateThreadPool(tpool *thread_pool);int AddWork(void* (*func)(void *arg), void *arg);void DestroyThreadPool();static void* ThreadFunc(void *arg){tpool_work_t *work;while(1){pthread_mutex_lock(&thread_pool->queueMutex);while(!thread_pool->head && !thread_pool->shutDown){pthread_cond_wait(&thread_pool->queueReady, &thread_pool->queueMutex);}if(thread_pool->shutDown){pthread_mutex_unlock(&thread_pool->queueMutex);pthread_exit(NULL);}work = thread_pool->head;thread_pool->head = thread_pool->head->next;pthread_mutex_unlock(&thread_pool->queueMutex);work->func(work->arg);free(work);}return NULL;}int CreateThreadPool(int threadNum){int i;thread_pool = (tpool*)malloc(sizeof(tpool));if(!thread_pool){printf("thread_pool create fail!\n");return -1;}thread_pool->threadNum = threadNum;thread_pool->shutDown = false;thread_pool->head = NULL;thread_pool->tail = NULL;thread_pool->tid = (pthread_t *)malloc(threadNum*sizeof(pthread_t));if(!thread_pool->tid){printf("thread create fail!\n");return -1;}if(pthread_mutex_init(&thread_pool->queueMutex, NULL) != 0){printf("mutex initialize error!\n");return -1;}if(pthread_cond_init(&thread_pool->queueReady, NULL) != 0){printf("cond initialize error!\n");return -1;}for(i=0; i<threadNum; i++){if(pthread_create(&thread_pool->tid[i], NULL, ThreadFunc, NULL)){printf("thread create error!\n");return -1;}}return 0;}int AddWork(void* (*func)(void *arg), void *arg){tpool_work_t *work;if(!arg){printf("the input function is invalid!\n");return -1;}work = (tpool_work_t*)malloc(sizeof(tpool_work_t));if(!work){printf("new work create fail!\n");return -1;}work->func = func;work->arg = arg;work->next = NULL;pthread_mutex_lock(&thread_pool->queueMutex);if(!thread_pool->head){thread_pool->head = work;thread_pool->tail = work;}else{thread_pool->tail->next = work;thread_pool->tail = work;}pthread_cond_signal(&thread_pool->queueReady);pthread_mutex_unlock(&thread_pool->queueMutex);return 0;}void DestroyThreadPool(){int i;tpool_work_t *work;if(thread_pool->shutDown){return ;}thread_pool->shutDown = true;pthread_cond_broadcast(&thread_pool->queueReady);for(i=0; i<thread_pool->threadNum; ++i){pthread_join(thread_pool->tid[i], NULL);}free(thread_pool->tid);while(thread_pool->head){work = thread_pool->head;thread_pool->head = thread_pool->head->next;free(work);}pthread_mutex_destroy(&thread_pool->queueMutex);pthread_cond_destroy(&thread_pool->queueReady);free(thread_pool);}#endif /* THREADPOOL_H_ */

EchoServer.cpp


//============================================================================// Name        : EchoServer.cpp// Author      : // Version     :// Copyright   : Your copyright notice// Description : Hello World in C++, Ansi-style//============================================================================#include <sys/socket.h>#include <sys/types.h>#include <netinet/in.h>#include <string.h>#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <pthread.h>#include "ThreadPool.h"const unsigned int PORT = 7777;const unsigned int LISTEN_NUM = 128;const unsigned int MAXLINE = 1024;void* doit(void *arg){pthread_detach(pthread_self());char buf[MAXLINE];int connfd = (int)arg;int n = 0;while((n = recv(connfd, buf, sizeof(buf), 0)) > 0){send(connfd, buf, n, 0);}if(n == -1){printf("receive error\n");}close(connfd);return NULL;}int main() {struct sockaddr_in cliaddr, serveraddr;int listenfd, connfd;socklen_t clilen;pthread_t tid;listenfd = socket(AF_INET, SOCK_STREAM, 0);bzero(&serveraddr, sizeof(serveraddr));serveraddr.sin_family = AF_INET;serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);serveraddr.sin_port = htons(PORT);if(bind(listenfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) == -1){printf("bind error\n");return -1;}if(listen(listenfd,LISTEN_NUM) == -1){printf("listen error\n");return -1;}CreateThreadPool(LISTEN_NUM);for(;;){clilen = sizeof(cliaddr);connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &clilen);if(connfd>0){//if(pthread_create(&tid, NULL, doit, (void *)connfd)){if(AddWork(doit, (void *)connfd)){printf("pthread create error\n");return -1;}}}        DestroyThreadPool();close(listenfd);return 0;}
这里的
void* doit(void *arg)
就是我的echo业务。

客户端:

//============================================================================// Name        : EchoClient.cpp// Author      : // Version     :// Copyright   : Your copyright notice// Description : Hello World in C++, Ansi-style//============================================================================#include <sys/socket.h>#include <strings.h>#include <unistd.h>#include <netinet/in.h>#include <arpa/inet.h>#include <stdio.h>#include <string.h>#include <sys/types.h>const char *IPADRR = "127.0.0.1";const unsigned int SERVERPORT = 7777;const unsigned int MAXLINE = 1024;void doit(FILE *fp, int sockfd){int ret;char send_buf[MAXLINE], recv_buf[MAXLINE];while(fgets(send_buf, MAXLINE, fp) != NULL){if((ret = send(sockfd, send_buf, strlen(send_buf), 0)) == -1){printf("send error\n");return;}//每次接收数据前将recv_buf清空,主要是填充'\0',因为接收数据不会在添上'\0'为结尾bzero(recv_buf, MAXLINE);if((ret = recv(sockfd, recv_buf, MAXLINE, 0)) == 0){printf("server stopped!\n");}fputs(recv_buf, stdout);}}int main() {int clifd;struct sockaddr_in serveraddr;if((clifd = socket(AF_INET, SOCK_STREAM, 0)) < 0){printf("socket create error\n");return -1;}bzero(&serveraddr, sizeof(serveraddr));serveraddr.sin_family = AF_INET;serveraddr.sin_addr.s_addr = inet_addr(IPADRR);serveraddr.sin_port = htons(SERVERPORT);if(connect(clifd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0){printf("connect to server fail\n");return -1;}printf("connect to server successfully!\n");doit(stdin, clifd);return 0;}

客户端的执行结果就是这个样子:

tomcat@tomcat-Lenovo-IdeaPad-Y550:~/文档/Echo$ ./EchoClient
connect to server successfully!
12344
12344
2
2
adasdasdad
adasdasdad




0 0
原创粉丝点击