引言

并发是什么?企业在进行产品开发过程中为什么需要考虑这个问题?想象一下天猫的双11和京东的618活动,一秒的点击量就有几十万甚至上百万,这么多请求一下子涌入到服务器,服务器需要对这么多的请求逐个进行消化掉,假如服务器一秒的处理能力就几万,那么剩下的不能及时得到处理的这些请求作何处理?总不能让用户界面一直等着,因此消息队列应运而生,所有的请求都统一放入消息队列,工作线程从消息队列不断的消费,消息队列相当于一个缓冲区,可达到解藕、异步和削峰的目的。

Kafka、ActiveMQ、RabbitMQ和RockerMQ都是消息队列的典型,每一种都有其自身的优势和劣势。本文我用自己编写的Buffer类模拟消息队列,如果是企业级需要上线的应用,一般都是基于业界已有的MQ框架上开发。

需求原型

  1. N个Client从标准输入接收数据,然后连续不断的发送到Server端;
  2. Server端接收来自每个Client的数据,将数据中的小写字母全部转换成大写字母,其他字符保持不变,最后把转换结果发送给对应的Client。

需求分解

  1. 拿到需求,第一步要做的就是分析需求并选择合适的设计架构,考虑到Server需要和Client进行通信,Client来自四面八方,端对端通信自然选择TCP,因此Server端需要能够监听新的连接请求和已有连接的业务请求;
  2. 又由于Server需要响应多个Client的业务请求,我们希望把业务处理交给Server端的工作线程(消费者)来做;
  3. 同时还需要一个IO线程负责监听Socket描述符,当IO线程监听到已有连接的业务请求时,立即把请求内容封装成一个任务推入消息队列尾;
  4. IO线程与工作线程互斥访问消息队列,当然工作线程消费一个任务或者IO线程添加一个任务都需要通知对方,也就是同步;
  5. 工作线程处理完毕后,把处理结果交给IO线程,由IO线程负责把结果发送给对应的Client,也就是IO线程与工作线程的分离,这里工作线程通知IO线程的方式我用eventfd来实现;
  6. 我们希望引入Log4cpp记录服务端的日志,并能够保存到文件中;
  7. 分析完这些,一个整体架构和大体的样子在脑海中就已经形成了,接着就需要编写设计文档和画流程图、类图和时序图了。

详细设计文档

1.UML静态类图:

2.UML动态时序图:

效果

1.如图,开了三个Client,运行结果正确:

2.Server端通过Log4cpp把日志写到文件中:

源码获取

https://github.com/icoty/cs_threadpool_epoll_mq

目录结构

.
├── client // 客户端Demo
│   ├── Client.cc
│   ├── Client.exe
│   ├── client.sh // 进入该目录下启动Client Demo: sh client.sh
│   ├── Log4func.cc // 引入日志模块重新疯转
│   ├── Log4func.h
│   └── Makefile // 编译方式:make
├── conf
│   └── my.conf // IP,Port配置文件, 从这里进行修改
├── include // 头文件
│   ├── Configuration.hpp // 配置文件,单例类,my.conf的内存化
│   ├── FileName.hpp // 全局定义,Configuration会用到
│   ├── log // 日志模块头文件
│   │   └── Log4func.hpp
│   ├── net // 网络框架模块头文件
│   │   ├── EpollPoller.hpp
│   │   ├── InetAddress.hpp
│   │   ├── Socket.hpp
│   │   ├── SockIO.hpp
│   │   ├── TcpConnection.hpp
│   │   └── TcpServer.hpp
│   ├── String2Upper.hpp // 工作线程转换成大写实际走的这里面的接口
│   ├── String2UpperServer.hpp // Server端的整个工厂
│   └── threadpool // 线程池、锁、条件变量和消息队列的封装
│   ├── Buffer.hpp
│   ├── Condition.hpp
│   ├── MutexLock.hpp
│   ├── Noncopyable.hpp
│   ├── Pthread.hpp
│   ├── Task.hpp
│   └── Threadpool.hpp
├── log // Server端的日志通过Log4cpp记录到这个文件中
│   └── log4test.log
├── Makefile // 编译方式:make
├── README.md
├── server // server端Demo
│   ├── server.exe
│   └── server.sh // 进入该目录下启动Server Demo:sh server.sh
└── src // 源文件
├── Configuration.cpp
├── log
│   └── Log4func.cpp
├── main.cpp
├── net
│   ├── EpollPoller.cpp
│   ├── InetAddress.cpp
│   ├── Socket.cpp
│   ├── SockIO.cpp
│   ├── TcpConnection.cpp
│   └── TcpServer.cpp
├── String2Upper.cpp
├── String2UpperServer.cpp
└── threadpool
├── Buffer.cpp
├── Condition.cpp
├── MutexLock.cpp // MutexLockGuard封装
├── Pthread.cpp
└── Threadpool.cpp

参考文献

[1] UNIX环境高级编程第3版

[2] cpp reference

[3] UML时序图

[4] Log4cpp官网下载

[5] Log4cpp安装

基于线程池、消息队列和epoll模型实现并发服务器架构的更多相关文章

  1. HQueue:基于HBase的消息队列

    HQueue:基于HBase的消息队列   凌柏   ​1. HQueue简介 HQueue是一淘搜索网页抓取离线系统团队基于HBase开发的一套分布式.持久化消息队列.它利用HTable存储消息数据 ...

  2. 设计模式:基于线程池的并发Visitor模式

    1.前言 第二篇设计模式的文章我们谈谈Visitor模式. 当然,不是简单的列个的demo,我们以电商网站中的购物车功能为背景,使用线程池实现并发的Visitor模式,并聊聊其中的几个关键点. 一,基 ...

  3. 基于线程池的多并发Socket程序的实现

    Socket“服务器-客户端”模型的多线程并发实现效果的大体思路是:首先,在Server端建立“链接循环”,每一个链接都开启一个“线程”,使得每一个Client端都能通过已经建立好的线程来同时与Ser ...

  4. 【Java TCP/IP Socket】基于线程池的TCP服务器(含代码)

    了解线程池 在http://blog.csdn.net/ns_code/article/details/14105457(读书笔记一:TCP Socket)这篇博文中,服务器端采用的实现方式是:一个客 ...

  5. Windows 消息以及消息处理算法--线程和消息队列详解

    Windows以消息驱动的方式,使得线程能够通过处理消息来响应外界. Windows 为每个需要接受消息和处理消息的线程建立消息队列(包括发送消息队列,登记消息队列,输入消息队列,响应消息队列),其中 ...

  6. 深入浅出Win32多线程设计之MFC的多线程-线程与消息队列(经典)

    1.创建和终止线程 在MFC程序中创建一个线程,宜调用AfxBeginThread函数.该函数因参数不同而具有两种重载版本,分别对应工作者线程和用户接口(UI)线程. 工作者线程 CWinThread ...

  7. 基于线程池的多线程售票demo2.0(原创)

    继上回基于线程池的多线程售票demo,具体链接: http://www.cnblogs.com/xifenglou/p/8807323.html以上算是单机版的实现,特别使用了redis 实现分布式锁 ...

  8. 基于线程池的多线程售票demo(原创)

    废话不多说,直接就开撸import org.springframework.util.StopWatch;import java.util.concurrent.*;/** * 基于线程池实现的多线程 ...

  9. requests模块session处理cookie 与基于线程池的数据爬取

    引入 有些时候,我们在使用爬虫程序去爬取一些用户相关信息的数据(爬取张三“人人网”个人主页数据)时,如果使用之前requests模块常规操作时,往往达不到我们想要的目的,例如: #!/usr/bin/ ...

随机推荐

  1. 2.1.1Remove Duplicates from Sorted Arr

    /* 题目:2.1.1 Remove Duplicates from Sorted Array Given a sorted array, remove the duplicates in place ...

  2. AbstractQueuedSynchronizer AQS源码分析

    申明:jdk版本为1.8 AbstractQueuedSynchronizer是jdk中实现锁的一个抽象类,有排他和共享两种模式. 我们这里先看排他模式,共享模式后面结合java.util.concu ...

  3. Python中神秘的-5到256

    注:本文不区分作为编程语言的Python和作为语言实现的Python.后者均默认为CPython. 了解他人对Python源代码的掌握情况,我喜欢问这样一个问题 请问,在Python中,256和257 ...

  4. CSS选择器整理

    基本选择器 标签选择器:直接写标签名 id选择器:#id名 class选择器:.class名 通配选择器:* 组合选择器 交集:ABCDEFG...... 并集:E, F, G, ...... 关系选 ...

  5. linear-gradient()的用法

    linear-gradient() 函数用于创建一个线性渐变的 "图像" 它的语法是 background: linear-gradient(direction, color-st ...

  6. DOMContentLoaded 事件

    DOMContentLoaded 事件 字面上看,它会在dom加载完成后触发. 与window.onload事件非常相似,但有一定区别: DOMContentLoaded 事件是在文档完全加载和解析之 ...

  7. Docker示例命令

    1.docker run -t -i -v /root/workspace/node:/home/exam:rw docker.io/node bin/sh    -t 给容器挂载一个伪终端    - ...

  8. Go的WaitGroup

    goroutine使用方便,但是如果不加以处理一般会deadlock,因为goroutine配合Chanel的话只能是一进一出,否则就会卡在那里.下面一个示例就是利用这个WaitGroup处理这种死锁 ...

  9. 将图片转化为base64编码字符串

    pom依赖 <dependency> <groupId>org.ops4j.base</groupId> <artifactId>ops4j-base- ...

  10. 正确使用 Android 的 Theme 和 Style

    原文:http://www.tuicool.com/articles/ZjEZFj Android 5.0 可以给一个 View 单独设置一个 theme 了,其主要用途就是用在 ToolBar 上, ...