一:设计思路

  本服务器框架使用 UDP 传输协议,程序柱线程等待客户端数据,并将数组存取队列缓冲区。另外可开启多个工作线程,工作线程可以依据具体项目实现不同的功能 ,例如可以将队列缓冲区中的数据逐个取出存入数据库,本程序为说明方便只是将缓冲区中的数据逐个打印输出。

二:代码示例

1. 队列缓冲区实现

  队列缓冲区由 unordered_map 和 queue 共同实现,unordered_map 散列表中每个元素 key 设置成客户端的ip value 设置成该ip 地址传过来数据的队列。

 //file name: exclusive_queue.h

 #ifndef __EXCLUSIVE_QUEUE_H__
#define __EXCLUSIVE_QUEUE_H__ #include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <boost/thread.hpp>
#include <boost/unordered/unordered_map.hpp>
#include <boost/typeof/typeof.hpp>
#include <boost/assert.hpp>
#include <queue>
#include <string> #define BOOST_DATE_TIME_SOURCE
#define BOOST_THREAD_NO_LIB using namespace std;
using namespace boost; namespace proxy
{ template <typename T>
class exclusive_queue
{
private : typedef mutex mutex_t; class QueueState
{
public :
typedef shared_ptr<queue<T> > queue_t;
mutex_t m_mu_queue;
short m_busy;
queue_t m_queue; QueueState() : m_busy(), m_queue(new queue<T>())
{
} }; typedef shared_ptr<QueueState > queue_state_t;
typedef shared_ptr<unordered_map<string, queue_state_t> > unordered_map_t; unsigned int m_queue_size;
unordered_map_t m_queues;
queue_state_t m_cur_que;
mutex_t m_mu_queues; public : exclusive_queue(int cnt = ) : m_queue_size(cnt)
,m_queues(new unordered_map<string, queue_state_t>())
{ } void Enqueue(string key, T element)
{
{
mutex_t::scoped_lock lock(m_mu_queues);
if(!m_queues->count(key))
{
m_queues->insert(make_pair(key, make_shared<QueueState>()));
}
m_cur_que = (*m_queues)[key];
} {
mutex_t::scoped_lock lock(m_cur_que->m_mu_queue);
if((*m_cur_que).m_queue->size() >= m_queue_size)
{
cout<<"queue is full "<< key <<endl;
}
else
{
(*m_cur_que).m_queue->push(element);
}
} } void Dequeue(queue<T>& result, string& key)
{
queue_state_t cur_qs;
BOOST_ASSERT(cur_qs == NULL);
while(cur_qs == NULL)
{
mutex_t::scoped_lock lock(m_mu_queues);
BOOST_AUTO(it, m_queues->begin());
for(; it != m_queues->end(); ++it)
{
if((*it).second->m_busy == && (*it).second->m_queue->size() > )
{
key = (*it).first;
cur_qs = (*it).second;
cur_qs->m_busy = ;
break;
}
} }
BOOST_ASSERT(cur_qs != NULL);
{
if(cur_qs->m_busy == )
{
mutex_t::scoped_lock lock(cur_qs->m_mu_queue);
while(!cur_qs->m_queue->empty())
{
result.push(cur_qs->m_queue->front());
cur_qs->m_queue->pop();
}
BOOST_ASSERT(cur_qs->m_queue->size() == );
}
} } void Release(string key)
{
{
mutex_t::scoped_lock lock(m_mu_queues);
(*m_queues)[key]->m_busy = ;
} } }; } #endif

2 服务器端实现

服务器主线程首先开启若干个工作线程, 工作线程循环读取数据缓冲区内容,当数据缓冲器有数据则取出 打印输出。

 //file name: server.h

 #ifndef __SERVER_H__
#define __SERVER_H__ #define BOOST_THREAD_NO_LIB
#include <boost/thread.hpp> #define BOOST_REGEX_NO_LIB
#define BOOST_DATE_TIME_SOURCE
#define BOOST_SYSTEM_NO_LIB
#include <boost/asio.hpp>
#include <boost/date_time/posix_time/posix_time.hpp> #include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp> #include <ostream> #include "configurationmanager.h"
#include "datadump.h"
#include "exclusive_queue.h" using namespace boost::asio;
using namespace std;
namespace proxy
{ class server
{
typedef shared_ptr<ip::udp::socket> udp_socket_t;
private :
io_service m_ios;
udp_socket_t m_socket;
ip::udp::endpoint m_remote_ep;
system::error_code m_ec;
proxy::exclusive_queue<DataMessage> m_data_queue; private : void post_async(int id)
{
queue<DataMessage> data_queue;
cout<<"[Thread]:"<<id<<"start"<<endl;
string logstr;
string key;
while()
{
m_data_queue.Dequeue(data_queue, key);
if(data_queue.size() == )
continue;
cout<<"[thread "<<id<<"]"<<endl;
DataDump::Dump(data_queue);
m_data_queue.Release(key);
}
} void server_start()
{
cout<<"Server start..."<<endl;
DataMessage msg;
ip::udp::endpoint ep;
system::error_code ec;
while(true)
{
m_socket->receive_from(buffer(msg.m_data), m_remote_ep, , m_ec); if(ec && ec != error::message_size)
{
throw system::system_error(ec);
}
msg.m_ip = ep.address().to_string();
m_data_queue.Enqueue(ep.address().to_string(), msg);
}
} public : server()
{
int i;
int work_thread_num = ConfigurationManager<long>::AppSetting("conf.WorkThreadNum");
int port = ConfigurationManager<long>::AppSetting("conf.ListenningPort");
ip::udp::endpoint local_ep(ip::udp::v4(), port);
m_socket = udp_socket_t(new ip::udp::socket(m_ios, local_ep));
for(i = ; i < work_thread_num; ++i)
{
thread t(boost::bind(&server::post_async, this, i));
}
server_start();
} }; } #endif

3 数据协议格式

本程序协议格式只存在两个字段 ,客户端的 ip 与 数据,结构参考代码

 //file name : datamessage.h

 #ifndef __DATAMESSAGE_H__
#define __DATAMESSAGE_H__
#include <string> namespace proxy
{ class DataMessage
{ public :
std::string m_ip;
char m_data[];
}; } #endif

4 工作线程

本程序可依据不同的项目具体实现,本程序为说明简单,只是单纯的将工作线程取到的数据全部打印输出

 //file name: datadump.h

 #ifndef __DATADUMP_H__
#define __DATADUMP_H__ #include <ostream>
#include <queue>
#include <string> #include "datamessage.h"
using namespace std;
using namespace boost; namespace proxy
{ class DataDump
{ public :
static void Dump(queue<DataMessage> &queue)
{
DataMessage msg;
while(queue.size() != )
{
msg = queue.front();
queue.pop();
cout<<"[dump] "<<msg.m_ip<<" : "<<&(msg.m_data[]) <<endl;
}
}
}; } #endif

5 读取配置文件

  本程序只是简单讲boost 库中的 propertytree 库进行了简单封装,想参考Boost 详细说明

 //file name : configurationmanager.h

 #ifndef __CONFIGURATIONMANAGER_H__
#define __CONFIGURATIONMANAGER_H__ #include <ostream>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>
#include <boost/assign.hpp>
#include <boost/typeof//typeof.hpp> using namespace std;
using namespace boost::property_tree; namespace proxy
{ template <class T>
class ConfigurationManager
{
private : public :
static T AppSetting(string path)
{
ptree pt;
read_xml("conf.xml", pt); return pt.get<T>(path);
}
}; } #endif

6 配置文件

  使用 xml 格式,存放服务器监听端口与工作线程的数量

<?xml version="1.0" encoding="utf-8"?>
<conf>
<ListenningPort></ListenningPort>
<WorkThreadNum></WorkThreadNum>
</conf>

三 主要技术说明

 主要基于boost 库多线程,互斥锁,网络传输套接字,重点是实现一个线程安全型的数据队列。程序结构非常简单

  g++ *.cpp -o main -Wall -lboost_thread -lboost_system

基于BOOST 实现并发服务器框架的更多相关文章

  1. 基于Golang的游戏服务器框架cellnet开发日记(二)

    看官们肯定还有大部分不是很熟悉Actor模型. 我这里基于Erlang, Skynet等语言和框架库来实战型解释下Actor模型.  Actor概念 Actor模型和OO类似, 都是符合人的思维模式进 ...

  2. 基于EasyDarwin开源流媒体服务器框架实现EasyNVR H5无插件直播流媒体服务器方案

    背景分析 在之前的一篇博客<web无插件播放RTSP摄像机方案,拒绝插件,拥抱H5!>中,描述了实现一套H5无插件直播方案的各个组件的参考建议,又在博客<EasyNVR H5流媒体服 ...

  3. PHP写的异步高并发服务器,基于libevent

    PHP写的异步高并发服务器,基于libevent 博客分类: PHP PHPFPSocketLinuxQQ  本文章于2013年11月修改. swoole已使用C重写作为PHP扩展来运行.项目地址:h ...

  4. 跨平台网络通信与服务器框架 acl 3.2.0 发布,acl_cpp 是基于 acl 库的 C++ 库

    acl 3.2.0 版本发布了,acl 是 one advanced C/C++ library 的简称,主要包括网络通信库以及服务器框架库等功能,支持 Linux/Windows/Solaris/F ...

  5. 基于线程池、消息队列和epoll模型实现并发服务器架构

    引言 并发是什么?企业在进行产品开发过程中为什么需要考虑这个问题?想象一下天猫的双11和京东的618活动,一秒的点击量就有几十万甚至上百万,这么多请求一下子涌入到服务器,服务器需要对这么多的请求逐个进 ...

  6. RedRabbit——基于BrokerPattern服务器框架

    RedRabbit 经典网游服务器架构 该图省略了专门用途的dbserver.guildserver等用于专门功能的server,该架构的优点有: l LoginGate相当于DNS,可以动态的保证G ...

  7. 基于BrokerPattern服务器框架

    基于BrokerPattern服务器框架 RedRabbit 经典网游服务器架构 该图省略了专门用途的dbserver.guildserver等用于专门功能的server,该架构的优点有: l Log ...

  8. 并发服务器--02(基于I/O复用——运用Select函数)

    I/O模型 Unix/Linux下有5中可用的I/O模型: 阻塞式I/O 非阻塞式I/O I/O复用(select.poll.epoll和pselect) 信号驱动式I/O(SIGIO) 异步I/O( ...

  9. 基于Netty打造RPC服务器设计经验谈

    自从在园子里,发表了两篇如何基于Netty构建RPC服务器的文章:谈谈如何使用Netty开发实现高性能的RPC服务器.Netty实现高性能RPC服务器优化篇之消息序列化 之后,收到了很多同行.园友们热 ...

随机推荐

  1. 文件和目录之access函数

    本篇博文内容摘自<UNIX环境高级编程>(第二版),仅作个人学习记录所用.关于本书可参考:http://www.apuebook.com/. 当用open函数打开一个文件时,内核以进程的有 ...

  2. 简单改写SQL达到优化目的

    select * from (select t.row_id, t.supplier_name, t.tel, address, t.contact, t.contact_post, t.contac ...

  3. CSS3 旋转的八卦图

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  4. nodejs中package.json文件模块依赖的版本格式

    version 完全匹配 >version 大于这个版本 >=version大于或等于这个版本 <version 小于这个版本 <=version 小于等于这个版本 ~vers ...

  5. centos 7访问windows共享文件夹

    1. 首先centos要能识别win7的文件系统ntfs,原版的centos是不支持NTFS格式的文件系统,因此需要安装ntfs支持软件包,我使用的是rpmforge软件库,在此处http://pkg ...

  6. JavaScript入门(9)

    一.Math对象 Math对象,提供对数据的数学计算 使用Math的属性和方法,代码如下: <script type="text/javascript"> var my ...

  7. java poi出excel换行问题

    POI操作excel实现换行问题. package jp.co.misumi.mdm.batch.common.jobrunner; import java.io.FileInputStream; i ...

  8. ios fix UIRefreshControl bug

    NS_CLASS_AVAILABLE_IOS(6_0)   UIRefreshControl 有个毛病有时会出bug  动画下拉就不动了,这里给出修复处理: @interface UICollecti ...

  9. NSdata 与 NSString,Byte数组,UIImage 的相互转换

    1. NSData 与 NSString NSData-> NSString NSString *aString = [[NSString alloc] initWithData:adataen ...

  10. 12天学好C语言——记录我的C语言学习之路(Day 5)

    12天学好C语言--记录我的C语言学习之路 Day 5: 第五天的学习开始了,今天我们主要对几个程序进行编写,让自己充分的熟练编程语言,大量的题目会让自己变的精炼.以一个程序(program 5.1) ...