基于预线程化的并发服务器
来源:互联网 发布:淘宝永久封店保证金 编辑:程序博客网 时间:2024/06/08 15:36
本文摘录自 深入理解计算机系统 :需要消费者-生产者模型的基本知识 ,和网络编程的基础知识
消费者-生产者模型:http://blog.csdn.net/lujiandong1/article/details/45502165
网络编程:http://blog.csdn.net/lujiandong1/article/details/45506543
预线程化的并发服务器模型如下:
在一般的并发服务器中,我们为每一个新客户端创建了一个新线程,每来一个请求,我们就创建一个线程,导致不小的代价。一个基于预线程化的服务器通过生产者-消费者 模型来降低开销。服务器由一个主线程和一组工作线程构成。主线程不断接受来自客户端的连接请求,并将得到的连接描述符放在一个有限的缓冲区中。每一个工作者线程反复从共享缓冲区取出描述符,为客户端服务,等待下一个描述符。
总结:提前创建了几个工作者线程,相当于构建一个线程池,工作者线程不断运行,只要缓冲区里面有连接描述符,就取出连接描述符,并进行服务,服务完之后,工作者线程不会取消,还是在等缓冲区里面产生新的连接描述符。
贴上代码:代码也只能在linux平台下运行,在windows下跑不了
//客户端程序在http://blog.csdn.net/lujiandong1/article/details/45506543中已经讲解了。
客户端程序 echoclient.c---------------------------------------------------------------------------------------------------------------------------------------------
/* * echoclient.c - An echo client *//* $begin echoclientmain */#include "csapp.h"int main(int argc, char **argv) { int clientfd, port; char *host, buf[MAXLINE]; rio_t rio; if (argc != 3) {fprintf(stderr, "usage: %s <host> <port>\n", argv[0]);exit(0); } host = argv[1]; port = atoi(argv[2]); clientfd = Open_clientfd(host, port); Rio_readinitb(&rio, clientfd); while (Fgets(buf, MAXLINE, stdin) != NULL) {Rio_writen(clientfd, buf, strlen(buf));Rio_readlineb(&rio, buf, MAXLINE);Fputs(buf, stdout); } Close(clientfd); //line:netp:echoclient:close exit(0);}/* $end echoclientmain */-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
服务器程序--------------------------------------------------------------------------------------------------------------------------------------------------------------
/* * echoservert_pre.c - A prethreaded concurrent echo server *//* $begin echoservertpremain */#include "csapp.h"#include "sbuf.h"#define NTHREADS 4#define SBUFSIZE 16 void echo_cnt(int connfd);void *thread(void *vargp);sbuf_t sbuf; /* shared buffer of connected descriptors */int main(int argc, char **argv) { int i, listenfd, connfd, port; socklen_t clientlen=sizeof(struct sockaddr_in); struct sockaddr_in clientaddr; pthread_t tid; if (argc != 2) {fprintf(stderr, "usage: %s <port>\n", argv[0]);exit(0); } port = atoi(argv[1]); sbuf_init(&sbuf, SBUFSIZE); //line:conc:pre:initsbuf listenfd = Open_listenfd(port); for (i = 0; i < NTHREADS; i++) /* Create worker threads */ //line:conc:pre:begincreatePthread_create(&tid, NULL, thread, NULL); //line:conc:pre:endcreate while (1) { connfd = Accept(listenfd, (SA *) &clientaddr, &clientlen);sbuf_insert(&sbuf, connfd); /* Insert connfd in buffer */ }}void *thread(void *vargp) { Pthread_detach(pthread_self()); while (1) { int connfd = sbuf_remove(&sbuf); /* Remove connfd from buffer */ //line:conc:pre:removeconnfdecho_cnt(connfd); /* Service client */Close(connfd); }}/* $end echoservertpremain */
解释:1、sbuf_init ,sbuf_insert等都来自开发的基于生产者-消费者模型的SBUF包,见博客
http://blog.csdn.net/lujiandong1/article/details/45502165
2、创建了NTHREADS个工作这线程
for (i = 0; i < NTHREADS; i++) /* Create worker threads */ //line:conc:pre:begincreatePthread_create(&tid, NULL, thread, NULL); //line:conc:pre:endcreate3、服务器主线程进入无限循环,不断监听连接请求,只要客户端有请求到达,就创建一个已连接描述符,插入缓冲区。
4、每个工作者线程的行为也比较简单,从已连接描述符的缓冲区里面取一个已连接描述符,然后调用echo_cnt为客户端服务。echo_cnt只是回送客户端的输入。
5、使用Pthread_detach(pthread_self())分离线程,当线程结束时,线程的存储器资源自动被系统回收
/* * A thread-safe version of echo that counts the total number * of bytes received from clients. *//* $begin echo_cnt */#include "csapp.h"static int byte_cnt; /* byte counter */static sem_t mutex; /* and the mutex that protects it */static void init_echo_cnt(void){ Sem_init(&mutex, 0, 1); byte_cnt = 0;}void echo_cnt(int connfd) { int n; char buf[MAXLINE]; rio_t rio; static pthread_once_t once = PTHREAD_ONCE_INIT; Pthread_once(&once, init_echo_cnt); //line:conc:pre:pthreadonce Rio_readinitb(&rio, connfd); //line:conc:pre:rioinitb while((n = Rio_readlineb(&rio, buf, MAXLINE)) != 0) {P(&mutex);byte_cnt += n; //line:conc:pre:cntaccess1printf("thread %d received %d (%d total) bytes on fd %d\n", (int) pthread_self(), n, byte_cnt, connfd); //line:conc:pre:cntaccess2V(&mutex);Rio_writen(connfd, buf, n); }}/* $end echo_cnt */
解释:
1、对共享变量byte_cnt的访问,要保证互斥访问,使用P和V操作。
2、全局变量byte_cnt中记录了从客户端接收到的累计字节数
3、要初始化化byte_cnt计数器和mutex信号量,可以提供一个初始化函数,然后在例程函数中去调用Pthread_once.
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- 基于预线程化的并发服务器
- 基于线程的高并发服务器
- Linux TCP 服务器编程(六):基于线程的并发服务器
- Python基于线程的并发编程
- 基于 TCP 协议的并发服务器程序
- 10.3 基于多任务的并发服务器
- lesson6 基于多线程的tcp并发服务器
- 线程实现并发服务器
- 基于线程池的http服务器
- 基于线程池的简单Web服务器
- Unix网络编程--基于线程的并发编程(1)
- 一个简单的基于select的并发服务器
- Linux之并发线程服务器
- tcp并发服务器之线程
- 线程并发测试服务器性能
- C 线程实现并发服务器
- 基于I/O 多路复用技术的并发服务器
- 基于select函数的单进程并发服务器程序----TCP
- jquery: click()与bind('click')的区别
- 对抽屉效果几大github第三方库
- scrapy使用笔记
- 体验Dundas Dashboard数据可视化控件
- [SPOJ1557][GSS2][线段树]Can you answer these queries II[好题]
- 基于预线程化的并发服务器
- 不用TTL线,OpenWrt刷回原厂或其他系统方法 841n测试通过
- HTTP 方法:GET 对比 POST
- leetcode(java):100 Same Tree
- 703N V1刷OpenWrt再刷回原厂教程(无图版)
- Mono为何能跨平台?聊聊CIL(MSIL)
- iOS开发NSUserDefaults
- C语言的字符与字符串处理函数
- WarDrive:使用Backtrack 4中的Kismet进行嗅探并使用GE绘制地图的简明攻略