基于c++11新标准开发一个支持多线程高并发的网络库

背景

新的c++11标准出后,c++语法得到了很多的扩展,比起以往任何时候都要灵活和高效,提高了程序编码的效率,为软件开发人员节省了不少的时间。 之前我也写过基于ACE的网络服务器框架,但ACE毕竟有些臃肿,内部对象关系错综复杂,容易给人造成只见树木不见森林的错觉。 所以打算用c++11开发一个较为简洁,高效,支持高并发的网络库。

开源

        花了两三周,终于把基础的结构开发完成,代码也开源在github上,网址是 https://github.com/lichuan/fly 欢迎各位提出建议。

结构

fly网络库主要分为base模块,task模块,net模块。base主要是一些最基础的功能集合,包括日志,id分配器,随机数,队列等;task主要封装了任务抽象以及任务调度执行等功能;net主要是实现网络层面的封装,为上层使用者提供简单易用的网络接口,这也是fly库的核心模块,实现了解析协议的Parser封装,负责监听网络的Acceptor,负责网络连接io功能的Poller封装体,在Parser、Acceptor、和Poller的基础上还进一步封装了作为服务器来使用的Server类和作为客户端来使用的Client类,这两个类是fly库的核心类,上层的应用可以直接使用Server对象和Client对象来建立网络服务器。作为网络连接概念的Connection对象则是通过std::shared_ptr来管理它的生命周期的,shared_ptr内置共享对象的功能大大地简化了网络连接生命期的管理。

协议

fly库的网络协议基于全世界最通用的json格式,而它的解析则依赖于rapidson第三方库来完成。

协议组成如下:

|长度字段|{协议类型:类型值,协议命令:命令值,其他json字段}|

协议类型和协议命令组成了二级消息字,就可以组合出各种约定的协议了。

应用

fly库的test目录提供了一个简单的例程。其中test_server.cpp代码如下:

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *                    _______    _                                     *
 *                   (  ____ \  ( \     |\     /|                      *
 *                   | (    \/  | (     ( \   / )                      *
 *                   | (__      | |      \ (_) /                       *
 *                   |  __)     | |       \   /                        *
 *                   | (        | |        ) (                         *
 *                   | )        | (____/\  | |                         *
 *                   |/         (_______/  \_/                         *
 *                                                                     *
 *                                                                     *
 *     fly is an awesome c++11 network library.                        *
 *                                                                     *
 *   @author: lichuan                                                  *
 *   @qq: 308831759                                                    *
 *   @email: [email protected]                                          *
 *   @github: https://github.com/lichuan/fly                           *
 *   @date: 2015-06-10 13:34:21                                        *
 *                                                                     *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#include <unistd.h>
#include <unordered_map>
#include "fly/init.hpp"
#include "fly/net/server.hpp"
#include "fly/base/logger.hpp"

using namespace std::placeholders;

class Test_Server : public fly::base::Singleton<Test_Server>
{
public:
    bool allow(std::shared_ptr<fly::net::Connection> connection)
    {
        return true;
    }

    void init(std::shared_ptr<fly::net::Connection> connection)
    {
        std::lock_guard<std::mutex> guard(m_mutex);
        m_connections[connection->id()] = connection;
        LOG_INFO("connection count: %u", m_connections.size());
    }

    void dispatch(std::unique_ptr<fly::net::Message> message)
    {
        std::shared_ptr<fly::net::Connection> connection = message->get_connection();
        const fly::net::Addr &addr = connection->peer_addr();
        LOG_INFO("recv message from %s:%d raw_data: %s", addr.m_host.c_str(), addr.m_port, message->raw_data().c_str());
    }

    void close(std::shared_ptr<fly::net::Connection> connection)
    {
        LOG_INFO("close connection from %s:%d", connection->peer_addr().m_host.c_str(), connection->peer_addr().m_port);
        std::lock_guard<std::mutex> guard(m_mutex);
        m_connections.erase(connection->id());
        LOG_INFO("connection count: %u", m_connections.size());
    }

    void be_closed(std::shared_ptr<fly::net::Connection> connection)
    {
        LOG_INFO("connection from %s:%d be closed", connection->peer_addr().m_host.c_str(), connection->peer_addr().m_port);
        std::lock_guard<std::mutex> guard(m_mutex);
        m_connections.erase(connection->id());
        LOG_INFO("connection count: %u", m_connections.size());
    }

    void main()
    {
        //init library
        fly::init();

        //init logger
        fly::base::Logger::instance()->init(fly::base::DEBUG, "server", "./log/");

        //test tcp server
        std::unique_ptr<fly::net::Server> server(new fly::net::Server(fly::net::Addr("127.0.0.1", 8899),
                                                                      std::bind(&Test_Server::allow, this, _1),
                                                                      std::bind(&Test_Server::init, this, _1),
                                                                      std::bind(&Test_Server::dispatch, this, _1),
                                                                      std::bind(&Test_Server::close, this, _1),
                                                                      std::bind(&Test_Server::be_closed, this, _1)));

        if(server->start())
        {
            LOG_INFO("start server ok!");
            server->wait();
        }
        else
        {
            LOG_ERROR("start server failed");
        }
    }

private:
    std::unordered_map<uint64, std::shared_ptr<fly::net::Connection>> m_connections;
    std::mutex m_mutex;
};

int main()
{
    Test_Server::instance()->main();
}

Server对象构造时会要求传入监听地址和回调函数,当Server对象start启动时,fly库底层就会建立相应的Poller、Parser、Acceptor对象,如果想实现多线程Poller和Parser,则需传入并发线程数量即可,回调函数说明如下:

allow_cb:当有新的连接到达时调用,来判断是否允许该连接的注册。

init_cb:当把连接对象注册到某一个Poller和Parser后调用,进行初始化处理。

dispatch_cb:当有消息到达时会调用,进行消息派发。

close_cb:主动关闭连接对象时调用。

be_closed_cb:检测到对端关闭连接对象时调用。

test_client.cpp主要使用Client对象来连接到某一个服务器,同样Client构造时也需要传入回调函数,其作用与Server构造时传入的回调一样。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-07 01:26:22

基于c++11新标准开发一个支持多线程高并发的网络库的相关文章

python 开发一个支持多用户在线的FTP

### 作者介绍:* author:lzl### 博客地址:* http://www.cnblogs.com/lianzhilei/p/5813986.html### 功能实现 作业:开发一个支持多用户在线的FTP程序 要求: 用户加密认证 允许同时多用户登录 每个用户有自己的家目录 ,且只能访问自己的家目录 对用户进行磁盘配额,每个用户的可用空间不同 允许用户在ftp server上随意切换目录 允许用户查看当前目录下文件 允许上传和下载文件,保证文件一致性 文件传输过程中显示进度条 附加功能

C++11新标准:nullptr关键字

一.nullptr的意义 1.NULL在C中的定义 #define NULL (void*)0 2.NULL在C++中的定义 #ifndef NULL #ifdef __cplusplus #define NULL 0 #else #define NULL ((void *)0) #endif #endif 3.为什么C++和C中NULL定义不一样呢? void foo(int a) { cout<<"This is int"<<endl; } void foo

关注C++细节——C++11新标准之decltype的使用注意

c++11新特性--decltype decltype是C++11添加的一个新的关键字,目的是选择并返回操作数的数据类型,重要的是,在此过程中编译器分析表达式并得到它的类型,却不实际计算表达式的值. 对于内置类型的对象,使用decltype很直观,但当参数为复合类型的时候就应该注意一些使用细节问题. 1.当decltype作用于数组的时候就应该小心了,本文作者(CSDN   iaccepted). intiarr[10] = {0}; decltype(iarr)ib; 这个时候ib的定义等价于

C++11新标准:decltype关键字

一.decltype意义 有时我们希望从表达式的类型推断出要定义的变量类型,但是不想用该表达式的值初始化变量(如果要初始化就用auto了).为了满足这一需求,C++11新标准引入了decltype类型说明符,它的作用是选择并返回操作数的数据类型,在此过程中,编译器分析表达式并得到它的类型,却不实际计算表达式的值. 二.decltype用法 1.基本用法 int getSize(); int main(void) { int tempA = 2; /*1.dclTempA为int*/ declty

C++11新标准:auto关键字

一.auto意义 编程时常常需要把表达式的值赋给变量,这就要求在声明变量的时候清楚地知道表达式的类型,然后要做到这一点并非那么容易.为了解决这个问题,C++11新标准引入了auto类型说明符,用它就能让编译器替我们去分析表达式所属的类型. 二.auto用法 1.基本用法 int tempA = 1; int tempB = 2; /*1.正常推断auto为int,编译通过*/ auto autoTempA = tempA + tempB; /*2.正常推断auto为int,编译通过*/ auto

开发一个支持多用户在线的FTP程序

一,项目题目:开发一个支持多用户在线的FTP程序 二,项目要求: 1.用户加密认证 2.允许同时多用户登录 3.每个用户有自己的家目录 ,且只能访问自己的家目录 4.对用户进行磁盘配额,每个用户的可用空间不同 5.允许用户在ftp server上随意切换目录 6.允许用户查看当前目录下文件 7.允许上传和下载文件,保证文件一致性(md5) 8.文件传输过程中显示进度条 9.附加功能:支持文件的断点续传 三,注意事项: 基本要求. 完成1,2,3,5,6,7,8 实力选手. 完成 上条 及需求4

Linux统系统开发11 Socket API编程2 多进程 多线程 高并发处理

[本文谢绝转载原文来自http://990487026.blog.51cto.com] <纲要> Linux统系统开发11 Socket API编程2 多进程 多线程 高并发处理 UDP服务器 客户端最小模型,处理字符转大写 TCP 多进程并发服务器模型,为每个客户端开启一个进程: TCP 多线程服务器模型,使用wrap函数封装 作业: ---------------------------------------------------- UDP服务器 客户端最小模型,处理字符转大写 [em

4412开发板支持GPS高强度信号

三星Exynos 4412开发板支持GPS高强度信号,GPS信号强度可达50dbm 2012年,三星正式推出了自家的首款四核移动处理器Exynos 4412. 这款新Exynos A9 四核处理器,拥有4枚主频为1.4-1.6 GHz的Cortex-A9通用处理核心,拥有32/32 KB I/D Cache, 1 MB L2 Cache, 并且集成ARM Mali 400 MP图形处理核心,而且三星公司已将这颗图形处理器主频由此前的266MHz提升至400MHz: 采用32nm HKMG(高K金

[开源] gnet: 一个轻量级且高性能的 Golang 网络库

Github 主页 https://github.com/panjf2000/gnet 欢迎大家围观~~,目前还在持续更新,感兴趣的话可以 star 一下暗中观察哦. 简介 gnet 是一个基于 Event-Loop 事件驱动的高性能和轻量级网络库.这个库直接使用 epoll 和 kqueue 系统调用而非标准 Golang 网络包:net 来构建网络应用,它的工作原理类似于两个开源的网络库:libuv 和 libevent. 这个项目存在的价值是提供一个在网络包处理方面能和 Redis.Hap