一:设计思路

  本服务器框架使用 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. android startActivityForResult(Intent intent, int requestCode) 整理与总结! .

    假设有两个Activity,主界面A,功能界面B,由A启动B,并传数据给B,B在经过处理后把数据传回给A. 先是A传B: Bundle bundle = new Bundle();bundle.put ...

  2. 自定义手势_GestureOverlayVIew

    xml文件: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns ...

  3. win7 cmd命令行窗口 宽度无法变大 自由调整大小

    偶然遇到了这个问题,百度查到了解决方案,执行一个bat批处理命令. mode con lines=40 mode con cols=160 color 250 cls @cmd

  4. pat 1006 Sign In and Sign Out (25)

    At the beginning of every day, the first person who signs in the computer room will unlock the door, ...

  5. android之硬件访问服务框架

    一.硬件接口描述文件aidl 新增\frameworks\base\core\java\android\os\ILedService.aidl 二.mk编译脚本 修改vi frameworks/bas ...

  6. Android的自动对焦

    1,什么是自动对焦? ---安卓的自动对焦的概念是指能够在指定的位置计算出准确的焦点位置. 这个就好像是传统意义上的手动对焦.但是google是这个意思. 2.什么是追焦? ----安卓的追焦是指FO ...

  7. vs2010开发android的准备工作

    安装 Mono for Android for Visual Studio 2010 需要下面4个步骤: 安装 JDK 安装 Android SDK 配置模拟器 安装 Mono for Android ...

  8. iOS自学之NSOperation、NSOperationQueue、Background

    iOS中多线程编程主要分为NSThread.NSOperation和GCD,今天主要记录下自己在学习NSOperation中的点滴-如有不对的地方帮忙指出下,PS:人生第一次写blog,各位看官请轻虐 ...

  9. javascript异步执行函数导致的变量变化问题解决思路

    for(var i=0;i<3;i++) { setTimeout(function(){ console.log(i) },0); }控制台输出:333 这是因为执行方法的时候for循环已经执 ...

  10. 如何从零开始实现一个soa远程调用服务基础组件

    说起soa远程调用基础组件,最著名的莫过于淘宝的dubbo了,目前很多的大型互联网公司都有一套自己的远程服务调用分布式框架,或者是使用开源的(例如dubbo),或者是自己基于某种协议(例如hessia ...