一个好的服务器的设计一个良好的服务器应该怎么设计在之后的文章里面我不仅仅会写网络库也会解析sylar服务器框架所以一个良好的服务器设计很重要。我们现在都是多核的计算机所以多线程服务的问题就转化成了如何设计一个高效且易于使用的eventLoop然后每一个线程run一个eventLoop就可以了。eventLoop是non-blocking网络编程的核心而且non-blocking一般都和IO多路复用一起连用。原因有几个没有人会一直轮询某个non-blocking的IO这样子很费CPU如果我们选择阻塞像read/write/connect/accept 都有可能意外的阻塞当前的线程导致当前线程就没有办法在socket处理其他的事情了。Reactor我们在书写网络库的时候一定要好好的理解Reactor模型Reactor模型里面有4个部分event事件reactor反应堆demultiplex事件分发器eventhandler事件处理器。当有事件event和handler注册时就会进入reactorreactor里面维护了所有的event集合reactor会通过epoll_ctl()来注册发生的事件在事件分发器里面调整event并且启动反应堆开启epoll_wait如果epoll_wait监听到有事件产生事件分发器就会返回event给reactor。为什么要返回呢因为事件的发生就意味着需要执行回调函数那么我们的回调函数全部都在反应堆里面。所以reactor就像一个大脑可以开启监听epoll_wait也就是事件分发器也会调用回调函数也就是EventHandler这个就是muduo库的reactor的模型不过这里有一点点的不一样这里的reactor吧reactor和demultiplex合二为一了我们可以简单的陈述一下子这个过程。当服务器开启之后会创建一个mainLoop这个mainLoop就是监听所有客户端的接口。因为现在的计算机都是多核多个CPU所以我们肯定不会是单线程运行每个线程都会对应一个CPU。当客户端发来信息我们计算机后端需要进行接受read解码decode编码encode最后发送给客户端。mainLoop里面有一个acceptor这个有两个部分的功能一个是listen监听一个是分发给subLoop子reactor这样子就可以有多个线程进行工作了。日志打印日志的打印是一个项目必备的部分当项目发生错误的时候我们可以快速的定位。我们打印器是一个单例模式然后每当使用打印器的时候定义其打印水平一遍打印出不同的东西。enum LogLevel { INFO, ERROR, FATAL, DEBUG, }; class Logger { public: static Logger* getInstance(); void setLogLevel(int level); void log(std::string msg); private: Logger(){} Logger(const Logger) delete; void operator(const Logger) delete; private: int m_logLevel; };#include ../include/Logger.h Litguidyo::Logger* Litguidyo::Logger::getInstance() { static Logger logger; return logger; } void Litguidyo::Logger::setLogLevel(int level) { m_logLevel level; } void Litguidyo::Logger::log(std::string msg) { switch (m_logLevel) { case INFO: std::cout [INFO]; break; case ERROR: std::cout [ERROR]; break; case FATAL: std::cout [FATAL]; break; case DEBUG: std::cout [DEBUG]; break; default: break; } // 打印时间 std::cout print time : msg std::endl; }为了更加方便使用打印日志我们一般都会定义很多宏。打印日志很多时候都是do while的结构防止出现一些语句的匹配错误debug我们一般都会在配置的时候确定是否开启所以要加ifdef DEBUG在出现致命错误的时候整个程序都必须要停止所以会有exit-1#define LOG_INFO(logmsgFormat, ...) \ do { \ Logger* logger Logger::getInstance(); \ logger-setLogLevel(INFO); \ char buf[1024] {0}; \ snprintf(buf, sizeof(buf), logmsgFormat, ##__VA_ARGS__); \ logger-log(buf); \ } while(0) #define LOG_ERROR(logmsgFormat, ...) \ do { \ Logger* logger Logger::getInstance(); \ logger-setLogLevel(ERROR); \ char buf[1024] {0}; \ snprintf(buf, sizeof(buf), logmsgFormat, ##__VA_ARGS__); \ logger-log(buf); \ } while(0) #ifdef MUDBUG #define LOG_DEBUG(logmsgFormat, ...) \ do { \ Logger* logger Logger::getInstance(); \ logger-setLogLevel(DEBUG); \ char buf[1024] {0}; \ snprintf(buf, sizeof(buf), logmsgFormat, ##__VA_ARGS__); \ logger-log(buf); \ } while(0) #else #define LOG_DEBUG(logmsgFormat, ...) #endif #define LOG_FATAL(logmsgFormat, ...) \ do { \ Logger* logger Logger::getInstance(); \ logger-setLogLevel(FATAL); \ char buf[1024] {0}; \ snprintf(buf, sizeof(buf), logmsgFormat, ##__VA_ARGS__); \ logger-log(buf); \ exit(-1); \ } while(0) }总结本篇文章到这里就结束了希望可以帮助大家理解~~~