├── .gitignore ├── .idea ├── .gitignore ├── CmfNetLib.iml ├── encodings.xml ├── misc.xml ├── modules.xml └── vcs.xml ├── CMakeLists.txt ├── README.md ├── include ├── base │ ├── Log.hpp │ ├── StringArg.hpp │ ├── Thread.hpp │ ├── Timestamp.hpp │ ├── copyable.hpp │ └── noncopyable.hpp └── net │ ├── Acceptor.hpp │ ├── Buffer.hpp │ ├── Callbacks.hpp │ ├── Channel.hpp │ ├── EPollPoller.hpp │ ├── EventLoop.hpp │ ├── EventLoopThread.hpp │ ├── EventLoopThreadPool.hpp │ ├── InetAddress.hpp │ ├── Poller.hpp │ ├── Socket.hpp │ ├── SocketOps.hpp │ ├── TcpConnection.hpp │ └── TcpServer.hpp ├── main.cpp ├── src ├── base │ └── Thread.cpp └── net │ ├── Acceptor.cpp │ ├── Channel.cpp │ ├── DefaultPoller.cpp │ ├── EPollPoller.cpp │ ├── EventLoop.cpp │ ├── EventLoopThread.cpp │ ├── EventLoopThreadPool.cpp │ ├── Poller.cpp │ ├── SocketOps.cpp │ ├── TcpConnection.cpp │ └── TcpServer.cpp └── test └── log.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | # 项目排除路径 2 | /cmake-build-debug/ -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # 默认忽略的文件 2 | /shelf/ 3 | /workspace.xml 4 | # 基于编辑器的 HTTP 客户端请求 5 | /httpRequests/ 6 | # Datasource local storage ignored files 7 | /dataSources/ 8 | /dataSources.local.xml 9 | -------------------------------------------------------------------------------- /.idea/CmfNetLib.iml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.16) 2 | project(CmfNetLib) 3 | 4 | set(CMAKE_CXX_STANDARD 14) 5 | 6 | file(GLOB SRC_FILES 7 | "${PROJECT_SOURCE_DIR}/include/base/*" 8 | "${PROJECT_SOURCE_DIR}/include/net/*" 9 | "${PROJECT_SOURCE_DIR}/src/base/*" 10 | "${PROJECT_SOURCE_DIR}/src/net/*") 11 | 12 | include_directories( 13 | ${CMAKE_CURRENT_SOURCE_DIR}/include 14 | ) 15 | 16 | add_library(CmfNet STATIC ${SRC_FILES}) 17 | set_target_properties(CmfNet PROPERTIES OUTPUT_NAME CmfNet PREFIX lib SUFFIX .a VERSION ${CMAKE_PROJECT_VERSION} SOVERSION ${CMAKE_PROJECT_VERSION_MAJOR}) 18 | 19 | add_executable(${CMAKE_PROJECT_NAME} main.cpp ${SRC_FILES}) 20 | find_package(Threads) 21 | target_link_libraries (${PROJECT_NAME} ${CMAKE_THREAD_LIBS_INIT}) 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # C++14重写muduo网络库 -------------------------------------------------------------------------------- /include/base/Log.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Cmf on 2022/5/23. 3 | // 4 | 5 | #pragma once 6 | 7 | #include "base/noncopyable.hpp" 8 | #include "base/Timestamp.hpp" 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | /* 18 | * 日志级别 19 | */ 20 | enum class LogLevel : uint8_t { 21 | NONE = 0, 22 | DEBUG = 1, 23 | INFO = 2, 24 | WARN = 3, 25 | ERROR = 4, 26 | FATAL = 5 27 | }; 28 | 29 | class Logger; 30 | 31 | /* 32 | * 日志事件 33 | */ 34 | class LogEvent { 35 | public: 36 | using ptr = std::shared_ptr; 37 | 38 | template 39 | LogEvent(LogLevel level, 40 | const std::string &fileName, 41 | const uint32_t line, 42 | const std::string &format, 43 | const Args &...args) 44 | : _level(level), 45 | _fileName(fileName), 46 | _line(line), 47 | _time(GetCurrentSystemTime()), 48 | _msg(LogFormat(format, args...)), 49 | _threadId(std::this_thread::get_id()) { 50 | } 51 | 52 | const std::string GetCurrentSystemTime() { 53 | return std::move(Timestamp::Now().ToString()); 54 | } 55 | 56 | static const char *ToString(LogLevel level) noexcept { 57 | switch (level) { 58 | case LogLevel::DEBUG: 59 | return "DEBUG"; 60 | break; 61 | case LogLevel::INFO: 62 | return "INFO"; 63 | break; 64 | case LogLevel::WARN: 65 | return "WARN"; 66 | break; 67 | case LogLevel::ERROR: 68 | return "ERROR"; 69 | break; 70 | case LogLevel::FATAL: 71 | return "FATAL"; 72 | break; 73 | default: 74 | return "NONE"; 75 | } 76 | } 77 | 78 | template 79 | std::string LogFormat(const std::string &format, Args &... args) { 80 | size_t size = std::snprintf(nullptr, 0, format.c_str(), args ...) + 1; 81 | std::unique_ptr buf = std::make_unique(size); 82 | std::snprintf(buf.get(), size, format.c_str(), args ...); 83 | return std::string(buf.get(), buf.get() + size - 1); 84 | } 85 | 86 | static LogLevel FromString(const std::string &str) noexcept { 87 | if (str == "DEBUG") { 88 | return LogLevel::DEBUG; 89 | } else if (str == "INFO") { 90 | return LogLevel::INFO; 91 | } else if (str == "WARN") { 92 | return LogLevel::WARN; 93 | } else if (str == "ERROR") { 94 | return LogLevel::ERROR; 95 | } else if (str == "FATAL") { 96 | return LogLevel::FATAL; 97 | } else { 98 | return LogLevel::NONE; 99 | } 100 | } 101 | 102 | LogLevel GetLevel() const { 103 | return _level; 104 | } 105 | 106 | std::thread::id GetThreadId() const { 107 | return _threadId; 108 | } 109 | 110 | std::string GetFileName() const { 111 | return _fileName; 112 | } 113 | 114 | uint32_t GetLine() const { 115 | return _line; 116 | } 117 | 118 | std::string GetMsg() const { 119 | return _msg; 120 | } 121 | 122 | std::string GetTime() const { 123 | return _time; 124 | } 125 | 126 | private: 127 | uint32_t _line = 0; 128 | std::thread::id _threadId; 129 | std::string _fileName; 130 | std::string _time; 131 | std::string _msg; 132 | LogLevel _level; 133 | }; 134 | 135 | class LogAppender { 136 | public: 137 | using ptr = std::shared_ptr; 138 | 139 | LogAppender() = default; 140 | 141 | virtual ~LogAppender() noexcept {} 142 | 143 | virtual void Log(const LogEvent::ptr event) = 0; 144 | }; 145 | 146 | /* 147 | * 输出到控制台 148 | */ 149 | class StdoutLogAppender : public LogAppender { 150 | public: 151 | using ptr = std::shared_ptr; 152 | 153 | void Log(const LogEvent::ptr event) override { 154 | std::stringstream _ss; 155 | _ss << event->GetTime() << " " 156 | << event->ToString(event->GetLevel()) << " " 157 | << event->GetThreadId() << " " 158 | << event->GetFileName() << " " 159 | << event->GetLine() << " " 160 | << event->GetMsg() << std::endl; 161 | std::cout << _ss.str(); 162 | } 163 | }; 164 | 165 | /* 166 | * 输出到文件 167 | */ 168 | class FileLogAppender : public LogAppender { 169 | public: 170 | using ptr = std::shared_ptr; 171 | 172 | FileLogAppender(const std::string &fileName) : _fileName(fileName) { 173 | if (_ofs.is_open()) { 174 | _ofs.close(); 175 | } 176 | _ofs.open(_fileName.c_str(), std::ios::out | std::ios::app | std::ios::binary); 177 | } 178 | 179 | ~FileLogAppender() { 180 | if (_ofs.is_open()) { 181 | _ofs.flush(); 182 | _ofs.close(); 183 | } 184 | } 185 | 186 | virtual void Log(const LogEvent::ptr event) override { 187 | if (_ofs.is_open()) { 188 | _ofs << event->GetTime() << " " 189 | << event->ToString(event->GetLevel()) << " " 190 | << event->GetThreadId() << " " 191 | << event->GetFileName() << " " 192 | << event->GetLine() << " " 193 | << event->GetMsg() << " " << std::endl; 194 | } 195 | } 196 | 197 | private: 198 | std::string _fileName; 199 | std::ofstream _ofs; 200 | 201 | }; 202 | 203 | /* 204 | * 日志器 205 | */ 206 | class Logger : private noncopyable { 207 | public: 208 | using ptr = std::shared_ptr; 209 | 210 | static Logger &GetInstance() { 211 | static Logger logger; 212 | return logger; 213 | } 214 | 215 | LogAppender::ptr StdoutLog() { 216 | _logAppender = std::make_shared(); 217 | return _logAppender; 218 | } 219 | 220 | LogAppender::ptr FileLog(const std::string path) { 221 | _logAppender = std::make_shared(path); 222 | return _logAppender; 223 | } 224 | 225 | private: 226 | LogAppender::ptr _logAppender; 227 | }; 228 | 229 | #define LOG_BASE(level, fmt, ...) \ 230 | Logger::GetInstance().StdoutLog()->Log(std::make_shared(level,__FILE__,__LINE__,fmt,##__VA_ARGS__)); 231 | 232 | #define LOG_DEBUG(fmt, ...) LOG_BASE(LogLevel::DEBUG,fmt,##__VA_ARGS__) 233 | #define LOG_INFO(fmt, ...) LOG_BASE(LogLevel::INFO,fmt,##__VA_ARGS__) 234 | #define LOG_WARN(fmt, ...) LOG_BASE(LogLevel::WARN,fmt,##__VA_ARGS__) 235 | #define LOG_ERROR(fmt, ...) LOG_BASE(LogLevel::ERROR,fmt,##__VA_ARGS__) 236 | #define LOG_FATAL(fmt, ...) LOG_BASE(LogLevel::FATAL,fmt,##__VA_ARGS__) -------------------------------------------------------------------------------- /include/base/StringArg.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Cmf on 2022/5/31. 3 | // 4 | 5 | #ifndef CMFNETLIB_STRINGARG_HPP 6 | #define CMFNETLIB_STRINGARG_HPP 7 | 8 | #include 9 | 10 | class StringArg { 11 | public: 12 | StringArg(const char *str) : _str(str) {} 13 | 14 | StringArg(const std::string &str) : _str(str.c_str()) {} 15 | 16 | const char *c_str() { 17 | return _str; 18 | } 19 | 20 | private: 21 | const char *_str; 22 | }; 23 | 24 | #endif //CMFNETLIB_STRINGARG_HPP 25 | -------------------------------------------------------------------------------- /include/base/Thread.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Cmf on 2022/6/8. 3 | // 4 | 5 | #ifndef CMFNETLIB_THREAD_HPP 6 | #define CMFNETLIB_THREAD_HPP 7 | 8 | #include "base/noncopyable.hpp" 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | class Thread : private noncopyable { 16 | public: 17 | using ThreadFunc = std::function; 18 | using ptr = std::shared_ptr; 19 | 20 | explicit Thread(ThreadFunc func, const std::string &name = std::string()); 21 | 22 | ~Thread(); 23 | 24 | void Start(); 25 | 26 | void Join(); 27 | 28 | bool Started() const { 29 | return _started; 30 | } 31 | 32 | std::thread::id Tid() const { 33 | return _tid; 34 | } 35 | 36 | const std::string &Name() const { 37 | return _name; 38 | } 39 | 40 | static int NumCreated() { 41 | return _numCreated; 42 | } 43 | 44 | private: 45 | bool _started;//启动当前线程 46 | bool _joined;//当前线程等待其他线程完了再运行下去 47 | std::shared_ptr _thread;//自己来掌控线程对象产生的时机 48 | std::thread::id _tid; 49 | ThreadFunc _func;//存储线程函数 50 | std::string _name;//调试的时候打印 51 | static std::atomic_int _numCreated;//对线程数量计数 52 | }; 53 | 54 | 55 | #endif //CMFNETLIB_THREAD_HPP 56 | -------------------------------------------------------------------------------- /include/base/Timestamp.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Cmf on 2022/6/2. 3 | // 4 | 5 | #ifndef CMFNETLIB_TIMESTAMP_HPP 6 | #define CMFNETLIB_TIMESTAMP_HPP 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "copyable.hpp" 13 | 14 | class Timestamp : public copyable { 15 | public: 16 | using ptr = std::shared_ptr; 17 | 18 | explicit Timestamp() : _microSecondsSinceEpoch(0) {} 19 | 20 | explicit Timestamp(int64_t microSecondsSinceEpoch) : _microSecondsSinceEpoch(microSecondsSinceEpoch) {} 21 | 22 | static Timestamp Now() { 23 | return Timestamp(std::chrono::system_clock::to_time_t(std::chrono::system_clock::now())); 24 | } 25 | 26 | std::string ToString() const { 27 | tm *ptm = localtime(&_microSecondsSinceEpoch); 28 | char date[128] = {0}; 29 | sprintf(date, "%4d-%02d-%02d %02d:%02d:%02d", 30 | static_cast(ptm->tm_year + 1900), 31 | static_cast(ptm->tm_mon + 1), 32 | static_cast(ptm->tm_mday), 33 | static_cast(ptm->tm_hour), 34 | static_cast(ptm->tm_min), 35 | static_cast(ptm->tm_sec)); 36 | return std::move(std::string(date)); 37 | } 38 | 39 | private: 40 | int64_t _microSecondsSinceEpoch; 41 | }; 42 | 43 | 44 | #endif //CMFNETLIB_TIMESTAMP_HPP 45 | -------------------------------------------------------------------------------- /include/base/copyable.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Cmf on 2022/5/28. 3 | // 4 | #pragma once 5 | /** 6 | * copyable类是一个空的标记类,指示所有继承copyable的子类都应该是值类型,也就是可以安全拷贝的, 7 | * 而之所以设置成protected,意味着该类无法产生对象,而只能派生子类 8 | */ 9 | class copyable 10 | { 11 | protected: 12 | copyable() = default; 13 | ~copyable() = default; 14 | }; -------------------------------------------------------------------------------- /include/base/noncopyable.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Cmf on 2022/5/23. 3 | // 4 | 5 | #ifndef CMFNETLIB_NONCOPYABLE_HPP 6 | #define CMFNETLIB_NONCOPYABLE_HPP 7 | 8 | /* 9 | * 允许构造和析构禁止拷贝和赋值 10 | */ 11 | class noncopyable { 12 | private: 13 | noncopyable(const noncopyable &) = delete; 14 | 15 | const noncopyable &operator=(const noncopyable &) = delete; 16 | 17 | protected: //派生类可以访问,外部无法访问 18 | noncopyable() = default; 19 | 20 | ~noncopyable() = default; 21 | }; 22 | 23 | #endif //CMFNETLIB_NONCOPYABLE_HPP 24 | -------------------------------------------------------------------------------- /include/net/Acceptor.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Cmf on 2022/6/9. 3 | // 4 | 5 | #ifndef CMFNETLIB_ACCEPTOR_HPP 6 | #define CMFNETLIB_ACCEPTOR_HPP 7 | 8 | #include "base/noncopyable.hpp" 9 | #include "Socket.hpp" 10 | #include "Channel.hpp" 11 | #include 12 | 13 | class InetAddress; 14 | 15 | class EventLoop; 16 | 17 | class Acceptor : private noncopyable { 18 | public: 19 | using NewConnectionCallback = std::function; 20 | 21 | Acceptor(EventLoop *loop, const InetAddress &listenAddr, bool reusePort); 22 | 23 | ~Acceptor(); 24 | 25 | void SetNewConnectionCallback(const NewConnectionCallback &cb) { 26 | _newConnectionCallback = cb; 27 | } 28 | 29 | bool Listening() const { 30 | return _listening; 31 | } 32 | 33 | void Listen(); 34 | 35 | private: 36 | void HandleRead(); 37 | 38 | EventLoop *_loop;//Acceptor用的就是用户定义的那个baseLoop,也称作mainLoop 39 | Socket _acceptSocket; 40 | Channel _acceptChannel; 41 | NewConnectionCallback _newConnectionCallback; 42 | bool _listening; 43 | }; 44 | 45 | 46 | #endif //CMFNETLIB_ACCEPTOR_HPP 47 | -------------------------------------------------------------------------------- /include/net/Buffer.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Cmf on 2022/5/31. 3 | // 4 | 5 | #ifndef CMFNETLIB_BUFFER_HPP 6 | #define CMFNETLIB_BUFFER_HPP 7 | 8 | #include "base/noncopyable.hpp" 9 | #include "SocketOps.hpp" 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | 16 | class Buffer : public noncopyable { 17 | public: 18 | using ptr = std::shared_ptr; 19 | //8字节长度(解决粘包问题) 20 | static const size_t CheapPrepend = 8; 21 | static const size_t InitialSize = 1024; 22 | 23 | public: 24 | 25 | explicit Buffer(size_t size = InitialSize) : _buffer(InitialSize + CheapPrepend), 26 | _readIndex(CheapPrepend), 27 | _writerIndex(CheapPrepend) {} 28 | 29 | //可写入字节数 30 | size_t WritableBytes() const { 31 | return _buffer.size() - _writerIndex; 32 | } 33 | 34 | //可读出字节数 35 | size_t ReadableBytes() const { 36 | return _writerIndex - _readIndex; 37 | } 38 | 39 | //头部字节数 40 | size_t PrependableBytes() const { 41 | return _readIndex; 42 | } 43 | 44 | //读出字节 45 | void Retrieve(size_t len) { 46 | if (len < ReadableBytes()) { 47 | _readIndex += len; 48 | } else { 49 | RetrieveAll(); 50 | } 51 | } 52 | 53 | //把onMessage函数上报的Buffer数据,转成string类型的数据返回 54 | std::string RetrieveAllAsString() { 55 | return RetrieveAsString(ReadableBytes());//应用可读取数据的长度 56 | } 57 | 58 | std::string RetrieveAsString(size_t len) { 59 | std::string result(Peek(), len); 60 | Retrieve(len); 61 | return result; 62 | } 63 | 64 | //读出全部字节 65 | void RetrieveAll() { 66 | _readIndex = _writerIndex = CheapPrepend; 67 | } 68 | 69 | //追加数据 70 | void Append(const char *str, size_t len) { 71 | if (WritableBytes() < len) { 72 | MakeSpace(len); 73 | } 74 | std::copy(str, str + len, BeginWrite()); 75 | _writerIndex += len; 76 | } 77 | 78 | void Append(const void *str, size_t len) { 79 | Append(static_cast(str), len); 80 | } 81 | 82 | void Append(const std::string &str) { 83 | Append(str.c_str(), str.length()); 84 | } 85 | 86 | //返回可写入数据段的首位指针 87 | char *BeginWrite() { 88 | return Begin() + _writerIndex; 89 | } 90 | 91 | const char *BeginWrite() const { 92 | return Begin() + _writerIndex; 93 | } 94 | 95 | const char *Peek() const { 96 | return Begin() + _readIndex; 97 | } 98 | 99 | ssize_t ReadFd(int fd, int *savedErrno) { 100 | char extrabuf[65536] = {0}; 101 | const size_t writable = WritableBytes(); 102 | iovec vec[2]; 103 | vec[0].iov_base = Begin() + _writerIndex; //第一块缓冲 104 | vec[0].iov_len = writable; 105 | vec[1].iov_base = extrabuf; //第二块缓冲 106 | vec[1].iov_len = sizeof(extrabuf); 107 | //iovcnt:vec数组的长度,先填充vec[0],填满了才填vec[1] 108 | const int iovcnt = writable < sizeof(extrabuf) ? 2 : 1; 109 | const ssize_t n = SocketOps::Readv(fd, vec, iovcnt); 110 | if (n < 0) { 111 | *savedErrno = errno; 112 | } else if (n <= writable) { //如果读取的数据相等或比可写入空间还小 113 | _writerIndex += n; 114 | } else { //如果读取数据大于可写入空间 115 | _writerIndex = _buffer.size(); //第一块缓冲区空间写满了 116 | Append(extrabuf, n - writable); //就把第二块缓冲区的数据追加到第一块缓冲区中,数据大小为:总读取数据大小n - 第一块缓冲区可写入大小 117 | } 118 | return n; 119 | } 120 | 121 | ssize_t WriteFd(int fd, int *savedErrno) const { 122 | ssize_t len = SocketOps::Write(fd, Peek(), ReadableBytes()); 123 | if (len < 0) { 124 | *savedErrno = errno; 125 | } 126 | return len; 127 | } 128 | 129 | private: 130 | //扩充 131 | void MakeSpace(size_t len) { 132 | //如果首部+尾部空余的空间都不够存储数据就扩充 133 | if (WritableBytes() + PrependableBytes() < len + CheapPrepend) { 134 | _buffer.resize(_writerIndex + len); 135 | } else { //够的话就把首位空间合在一起 136 | size_t readSize = ReadableBytes(); 137 | std::copy(Begin() + _readIndex, Begin() + _writerIndex, Begin() + CheapPrepend); 138 | _readIndex = CheapPrepend; 139 | _writerIndex = _readIndex + readSize; 140 | } 141 | } 142 | 143 | char *Begin() { 144 | return &*_buffer.begin(); 145 | } 146 | 147 | const char *Begin() const { 148 | return &*_buffer.begin(); 149 | } 150 | 151 | private: 152 | std::vector _buffer; 153 | std::atomic _readIndex; //读出下标 154 | std::atomic _writerIndex;//写入下标 155 | }; 156 | 157 | #endif //CMFNETLIB_BUFFER_HPP 158 | -------------------------------------------------------------------------------- /include/net/Callbacks.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Cmf on 2022/6/9. 3 | // 4 | 5 | #ifndef CMFNETLIB_CALLBACKS_HPP 6 | #define CMFNETLIB_CALLBACKS_HPP 7 | 8 | #include 9 | #include 10 | 11 | class Buffer; 12 | 13 | class TcpConnection; 14 | 15 | class Timestamp; 16 | 17 | using TcpConnectionPtr = std::shared_ptr; 18 | using ConnectionCallback = std::function; 19 | using CloseCallback = std::function; 20 | using WriteCompleteCallback = std::function; 21 | using MessageCallback = std::function; 22 | using HighWaterMarkCallback = std::function; 23 | 24 | #endif //CMFNETLIB_CALLBACKS_HPP 25 | -------------------------------------------------------------------------------- /include/net/Channel.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Cmf on 2022/6/2. 3 | // 4 | 5 | #ifndef CMFNETLIB_CHANNEL_HPP 6 | #define CMFNETLIB_CHANNEL_HPP 7 | 8 | #include 9 | #include 10 | #include 11 | #include "base/Timestamp.hpp" 12 | #include "base/Log.hpp" 13 | 14 | 15 | /** 16 | * Channel(事件分发器),只属于一个EventLoop,Channel类中保存着IO事件的类型以及对应的回调函数,每个channel只负责一个文件描述符 17 | */ 18 | class EventLoop; 19 | 20 | class Channel : private noncopyable { 21 | public: 22 | using ptr = std::shared_ptr; 23 | using EventCallback = std::function; //事件回调 24 | using ReadEventCallback = std::function;//读事件回调 25 | 26 | 27 | Channel(EventLoop *loop, int fd) : _loop(loop), _fd(fd), _events(0), _revents(0), _index(-1), _tied(false) { 28 | } 29 | 30 | /** 31 | * 设置回调函数对象 32 | * @param cb 33 | */ 34 | void SetReadCallback(ReadEventCallback cb) { 35 | this->_readCallback = std::move(cb); 36 | } 37 | 38 | void SetWriteCallback(EventCallback cb) { 39 | this->_writeCallback = std::move(cb); 40 | } 41 | 42 | void SetCloseCallback(EventCallback cb) { 43 | this->_closeCallback = std::move(cb); 44 | } 45 | 46 | void SetErrorCallback(EventCallback cb) { 47 | this->_errorCallback = std::move(cb); 48 | } 49 | 50 | /** 51 | * 返回fd当前的事件状态 52 | */ 53 | bool IsNoneEvent() const { 54 | return this->_events == this->NoneEvent; 55 | } 56 | 57 | bool IsWriting() const { 58 | return this->_events & this->WriteEvent; 59 | } 60 | 61 | bool IsReading() const { 62 | return this->_events & this->ReadEvent; 63 | } 64 | 65 | /** 66 | * 设置fd相应的事件状态,要让fd对这个事件感兴趣,update就是调用epoll_ctrl,通知poller把fd感兴趣的事件添加到fd上 67 | */ 68 | void EnableReading(); 69 | 70 | void DisableReading(); 71 | 72 | void EnableWriting(); 73 | 74 | void DisableWriting(); 75 | 76 | void DisableAll(); 77 | 78 | uint32_t Revents() const { 79 | return this->_revents; 80 | } 81 | 82 | void SetRevents(uint32_t revt) { 83 | this->_revents = revt; 84 | } 85 | 86 | int Index() const { 87 | return this->_index; 88 | } 89 | 90 | void SetIndex(int index) { 91 | this->_index = index; 92 | } 93 | 94 | uint32_t Events() const { 95 | return this->_events; 96 | } 97 | 98 | int Fd() const { 99 | return this->_fd; 100 | } 101 | 102 | void Remove(); 103 | 104 | /** 105 | * 防止当channel被手动remove掉,channel还在执行回调操作 106 | * @param obj 107 | */ 108 | void Tie(const std::shared_ptr &obj) { 109 | this->_tie = obj; 110 | this->_tied = true; 111 | } 112 | 113 | /** 114 | * 处理事件 115 | * @param receiveTime 116 | */ 117 | void HandleEvent(Timestamp receiveTime) { 118 | if (this->_tied) { 119 | std::shared_ptr guard = this->_tie.lock(); 120 | if (guard) { 121 | this->HandleEventWithGuard(receiveTime); 122 | } 123 | } else { 124 | this->HandleEventWithGuard(receiveTime); 125 | } 126 | } 127 | 128 | 129 | private: 130 | /** 131 | * //根据poller通知的channel发生的具体事件, 由channel负责调用具体的回调操作 132 | * EPOLLIN:表示对应的文件描述符可以读; 133 | * EPOLLOUT:表示对应的文件描述符可以写; 134 | * EPOLLPRI:表示对应的文件描述符有紧急的数据可读 135 | * EPOLLERR:表示对应的文件描述符发生错误; 136 | * EPOLLHUP:表示对应的文件描述符被挂断; 137 | * EPOLLET:表示对应的文件描述符有事件发生; 138 | * @param receiveTime 139 | */ 140 | void HandleEventWithGuard(Timestamp receiveTime) { 141 | LOG_INFO("channel handleEvent revents:%d", Revents()); 142 | if ((this->_revents & EPOLLHUP) && !(this->_revents & EPOLLIN)) { 143 | if (this->_closeCallback) { 144 | this->_closeCallback(); 145 | } 146 | } 147 | if (this->_revents & EPOLLERR) { 148 | if (this->_errorCallback) { 149 | this->_errorCallback(); 150 | } 151 | } 152 | if (this->_revents & (EPOLLIN | EPOLLPRI)) { 153 | if (this->_readCallback) { 154 | this->_readCallback(receiveTime); 155 | } 156 | } 157 | if (this->_revents & EPOLLOUT) { 158 | if (this->_writeCallback) { 159 | this->_writeCallback(); 160 | } 161 | } 162 | } 163 | 164 | private: 165 | 166 | 167 | static const int NoneEvent = 0; //无事件 168 | static const int ReadEvent = EPOLLIN | EPOLLET; //可读事件 169 | static const int WriteEvent = EPOLLOUT; //可写事件 170 | 171 | EventLoop *_loop; //channel所属的loop,一个channel只属于一个loop 172 | const int _fd; //channel所属的文件描述符 173 | uint32_t _events; //注册的事件 174 | uint32_t _revents; //poller设置的就绪的事件 175 | int _index; //被poller使用的下标 176 | std::weak_ptr _tie; 177 | bool _tied; 178 | 179 | ReadEventCallback _readCallback;//读事件回调 180 | EventCallback _writeCallback; //写事件回调 181 | EventCallback _closeCallback; //关闭事件回调 182 | EventCallback _errorCallback; //错误事件回调 183 | }; 184 | 185 | #endif //CMFNETLIB_CHANNEL_HPP 186 | -------------------------------------------------------------------------------- /include/net/EPollPoller.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Cmf on 2022/6/4. 3 | // 4 | 5 | #ifndef CMFNETLIB_EPOLLPOLLER_HPP 6 | #define CMFNETLIB_EPOLLPOLLER_HPP 7 | 8 | #include "Poller.hpp" 9 | 10 | struct epoll_event; 11 | 12 | class EPollPoller : public Poller { 13 | public: 14 | using ptr = std::shared_ptr; 15 | 16 | EPollPoller(EventLoop *loop); 17 | 18 | ~EPollPoller() override; 19 | 20 | Timestamp Poll(int timeoutMs, ChannelList *activeChannels) override; 21 | 22 | void UpdateChannel(Channel *channel) override; 23 | 24 | void RemoveChannel(Channel *channel) override; 25 | 26 | private: 27 | static const int InitEventListSize = 16; 28 | 29 | void FillActiveChannels(int numEvents, ChannelList *activeChannels) const; 30 | 31 | void Update(int operation, Channel *channel); 32 | 33 | using EventList = std::vector; 34 | 35 | private: 36 | int _epollFd; 37 | EventList _events; 38 | }; 39 | 40 | 41 | #endif //CMFNETLIB_EPOLLPOLLER_HPP 42 | -------------------------------------------------------------------------------- /include/net/EventLoop.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Cmf on 2022/6/2. 3 | // 4 | 5 | #ifndef CMFNETLIB_EVENTLOOP_CPP 6 | #define CMFNETLIB_EVENTLOOP_CPP 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include "base/Timestamp.hpp" 15 | #include "base/noncopyable.hpp" 16 | 17 | class Channel; 18 | 19 | class Poller; 20 | 21 | class EventLoop : private noncopyable { 22 | public: 23 | using ptr = std::shared_ptr; 24 | using Functor = std::function; 25 | 26 | EventLoop(); 27 | 28 | ~EventLoop(); 29 | 30 | void Loop(); 31 | 32 | void Quit(); 33 | 34 | Timestamp PollReturnTime() const { return _pollReturnTime; } 35 | 36 | /** 37 | * 在当前loop中执行cb 38 | * @param cb 39 | */ 40 | void RunInLoop(Functor cb); 41 | 42 | /** 43 | * 把cb放入队列中,唤醒loop所在的线程,执行cb 44 | * @param cb 45 | */ 46 | void QueueInLoop(Functor cb); 47 | 48 | /** 49 | * 唤醒所有线程 50 | */ 51 | void WakeUp(); 52 | 53 | void UpdateChannel(Channel *channel); 54 | 55 | void RemoveChannel(Channel *channel); 56 | 57 | bool HasChannel(Channel *channel); 58 | 59 | /** 60 | * 判断EventLoop对象是否在自己的线程里面 61 | */ 62 | bool IsInLoopThread() const; 63 | 64 | 65 | private: 66 | using ChannelList = std::vector; 67 | 68 | void HandleRead(); 69 | 70 | void DoPendingFunctors(); 71 | 72 | private: 73 | std::atomic_bool _looping; 74 | std::atomic_bool _quit; //标识退出loop循环 75 | const std::thread::id _threadId; //记录当前loop所在线程的id 76 | int _wakeupFd; //linux内核的eventfd创建出来的 77 | Timestamp _pollReturnTime; //poller返回发生事件的channels的时间点 78 | std::unique_ptr _poller;//eventloop所管理的poller 79 | std::unique_ptr _wakeupChannel;//包括wakeupFd和感兴趣的事件 80 | ChannelList _activeChannels; //eventloop所管理的channel 81 | std::atomic_bool _callingPendingFunctors; //标识当前loop是否有需要执行的回调操作 82 | std::vector _pendingFunctors;//存储loop需要执行的所有的回调操作 83 | std::mutex _mtx;//互斥锁,用来保护上面vector容器的线程安全操作 84 | }; 85 | 86 | #endif //CMFNETLIB_EVENTLOOP_CPP 87 | -------------------------------------------------------------------------------- /include/net/EventLoopThread.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Cmf on 2022/6/8. 3 | // 4 | 5 | #ifndef CMFNETLIB_EVENTLOOPTHREAD_HPP 6 | #define CMFNETLIB_EVENTLOOPTHREAD_HPP 7 | 8 | #include "base/noncopyable.hpp" 9 | #include "base/Thread.hpp" 10 | #include 11 | #include 12 | 13 | class EventLoop; 14 | 15 | class EventLoopThread : private noncopyable { 16 | public: 17 | using ThreadInitCallback = std::function; 18 | 19 | EventLoopThread(const ThreadInitCallback &cb = ThreadInitCallback(), const std::string &name = std::string()); 20 | 21 | ~EventLoopThread(); 22 | 23 | EventLoop *StartLoop(); 24 | 25 | private: 26 | void ThreadFunc(); 27 | 28 | EventLoop *_loop; 29 | bool _exiting; 30 | Thread _thread; 31 | std::mutex _mtx; 32 | std::condition_variable _cond; 33 | ThreadInitCallback _callback; 34 | }; 35 | 36 | 37 | #endif //CMFNETLIB_EVENTLOOPTHREAD_HPP 38 | -------------------------------------------------------------------------------- /include/net/EventLoopThreadPool.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Cmf on 2022/6/8. 3 | // 4 | 5 | #ifndef CMFNETLIB_EVENTLOOPTHREADPOOL_HPP 6 | #define CMFNETLIB_EVENTLOOPTHREADPOOL_HPP 7 | 8 | #include "base/noncopyable.hpp" 9 | #include "base/Thread.hpp" 10 | #include 11 | #include 12 | 13 | class EventLoop; 14 | 15 | class EventLoopThread; 16 | 17 | class EventLoopThreadPool : private noncopyable { 18 | public: 19 | using ThreadInitCallback = std::function; 20 | 21 | EventLoopThreadPool(EventLoop *baseLoop, const std::string &nameArg); 22 | 23 | ~EventLoopThreadPool(); 24 | 25 | /** 26 | * 设置底层线程的数量,TcpServer::setThreadNum底层调用的就是EventLoopThreadPool::setThreadNum 27 | * @param numThreads 28 | */ 29 | void SetThreadNum(int numThreads) { 30 | _numThreads = numThreads; 31 | } 32 | 33 | void Start(const ThreadInitCallback &cb = ThreadInitCallback()); 34 | 35 | /** 36 | * 如果工作在多线程中,baseLoop_默认以轮询的方式分配Channel给subLoop 37 | * @return 38 | */ 39 | EventLoop *GetNextLoop(); 40 | 41 | /** 42 | * 返回事件循环池所有的EventLoop 43 | * @return 44 | */ 45 | std::vector GetAllLoops(); 46 | 47 | bool Started() const { 48 | return _started; 49 | } 50 | 51 | const std::string Name() const { 52 | return _name; 53 | } 54 | 55 | private: 56 | EventLoop *_baseLoop;// 我们使用muduo编写程序的时候,就会定义一个EventLoop变量,这个变量作为TcpServer构造函数的参数,用户创建的就叫做baseLoop 57 | std::string _name; 58 | bool _started; 59 | int _numThreads; 60 | int _next; 61 | std::vector> _threads; 62 | std::vector _loops; 63 | }; 64 | 65 | 66 | #endif //CMFNETLIB_EVENTLOOPTHREADPOOL_HPP 67 | -------------------------------------------------------------------------------- /include/net/InetAddress.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Cmf on 2022/5/31. 3 | // 4 | 5 | #ifndef CMFNETLIB_INETADDRESS_HPP 6 | #define CMFNETLIB_INETADDRESS_HPP 7 | 8 | #include 9 | #include 10 | #include 11 | #include "base/StringArg.hpp" 12 | #include "base/copyable.hpp" 13 | 14 | class InetAddress : public copyable { 15 | public: 16 | using ptr = std::shared_ptr; 17 | 18 | explicit InetAddress() = default; 19 | 20 | explicit InetAddress(uint16_t port,StringArg ip = "127.0.0.1") { 21 | memset(&_addr, 0, sizeof(_addr)); 22 | _addr.sin_family = AF_INET; 23 | _addr.sin_addr.s_addr = inet_addr(ip.c_str()); 24 | _addr.sin_port = htons(port); 25 | } 26 | 27 | InetAddress(StringArg ip, uint16_t port) { 28 | memset(&_addr, 0, sizeof(_addr)); 29 | _addr.sin_family = AF_INET; 30 | _addr.sin_port = htons(port); 31 | inet_pton(AF_INET, ip.c_str(), &_addr.sin_addr); 32 | } 33 | 34 | explicit InetAddress(const sockaddr_in &addr) : _addr(addr) { 35 | 36 | } 37 | 38 | const sockaddr *GetSockAddr() const { 39 | return (const sockaddr *) &_addr; 40 | } 41 | 42 | void SetSockAddr(const sockaddr_in &addr) { 43 | _addr = addr; 44 | } 45 | 46 | sa_family_t Family() const { 47 | return _addr.sin_family; 48 | } 49 | 50 | std::string GetIP() const { 51 | char buf[64]; 52 | inet_ntop(AF_INET, &_addr.sin_addr, buf, static_cast(sizeof(_addr))); 53 | return buf; 54 | } 55 | 56 | std::string ToIpPort() const { 57 | char buf[64] = {0}; 58 | inet_ntop(AF_INET, &_addr.sin_addr, buf, static_cast(sizeof(_addr))); 59 | snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ":%u", this->GetPort()); 60 | return buf; 61 | } 62 | 63 | uint16_t GetPort() const { 64 | return be16toh(_addr.sin_port); 65 | } 66 | 67 | 68 | private: 69 | sockaddr_in _addr; 70 | }; 71 | 72 | #endif //CMFNETLIB_INETADDRESS_HPP 73 | -------------------------------------------------------------------------------- /include/net/Poller.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Cmf on 2022/6/4. 3 | // 4 | 5 | #ifndef CMFNETLIB_POLLER_HPP 6 | #define CMFNETLIB_POLLER_HPP 7 | 8 | #include 9 | #include 10 | #include "base/noncopyable.hpp" 11 | #include "base/Timestamp.hpp" 12 | 13 | 14 | /** 15 | * poller监听的就是eventloop保存的那些channel 16 | */ 17 | class Channel; 18 | 19 | class EventLoop; 20 | 21 | class Poller : private noncopyable { 22 | public: 23 | using ChannelList = std::vector; 24 | 25 | Poller(EventLoop *loop); 26 | 27 | virtual ~Poller() = default; 28 | 29 | virtual Timestamp Poll(int timeoutMs, ChannelList *activeChannels) = 0; 30 | 31 | virtual void UpdateChannel(Channel *channel) = 0; 32 | 33 | virtual void RemoveChannel(Channel *channel) = 0; 34 | 35 | /** 36 | * 判断参数channel是否在当前Poller当中 37 | * @param channel 38 | * @return 39 | */ 40 | bool HasChannel(Channel *channel) const; 41 | 42 | /** 43 | * EventLoop可以通过该接口获取默认的IO复用的具体实现 44 | * @param loop 45 | * @return 46 | */ 47 | static Poller *NewDefaultPoller(EventLoop *loop); 48 | 49 | protected: 50 | using ChannelMap = std::unordered_map; 51 | ChannelMap _channels; 52 | private: 53 | EventLoop* _ownerLoop; 54 | }; 55 | 56 | #endif //CMFNETLIB_POLLER_HPP 57 | -------------------------------------------------------------------------------- /include/net/Socket.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Cmf on 2022/5/31. 3 | // 4 | 5 | #ifndef CMFNETLIB_SOCKET_HPP 6 | #define CMFNETLIB_SOCKET_HPP 7 | 8 | #include "base/noncopyable.hpp" 9 | #include "net/SocketOps.hpp" 10 | #include "net/InetAddress.hpp" 11 | 12 | #include 13 | #include 14 | 15 | class Socket : private noncopyable { 16 | public: 17 | using ptr = std::shared_ptr; 18 | 19 | explicit Socket(int fd) : _fd(fd) {} 20 | 21 | ~Socket() noexcept { 22 | SocketOps::Close(_fd); 23 | } 24 | 25 | int GetFd() const { 26 | return _fd; 27 | } 28 | 29 | void Bind(const InetAddress &addr) const { 30 | SocketOps::Bind(_fd, addr.GetSockAddr()); 31 | } 32 | 33 | void Listen() const { 34 | SocketOps::Listen(_fd); 35 | } 36 | 37 | void ShutdownWrite() { 38 | SocketOps::ShutdownWrite(_fd); 39 | } 40 | 41 | int Accept(InetAddress *peeraddr) { 42 | sockaddr_in addr; 43 | memset(&addr, 0, sizeof(addr)); 44 | int fd = SocketOps::Accept(_fd, &addr); 45 | if (fd >= 0) { 46 | peeraddr->SetSockAddr(addr); 47 | } 48 | return fd; 49 | } 50 | 51 | void SetTcpNoDelay(bool on) { 52 | int optval = on ? 1 : 0; 53 | setsockopt(_fd, IPPROTO_TCP, TCP_NODELAY, &optval, static_cast(sizeof(optval))); 54 | } 55 | 56 | void SetReuseAddr(bool on) { 57 | int optval = on ? 1 : 0; 58 | setsockopt(_fd, SOL_SOCKET, SO_REUSEADDR, &optval, static_cast(sizeof(optval))); 59 | } 60 | 61 | void SetReusePort(bool on) { 62 | int optval = on ? 1 : 0; 63 | int ret = setsockopt(_fd, SOL_SOCKET, SO_REUSEPORT, &optval, static_cast(sizeof(optval))); 64 | if (ret < 0 && on) { 65 | LOG_ERROR("setReusePort error!"); 66 | } 67 | } 68 | 69 | void SetKeepAlive(bool on) { 70 | int optval = on ? 1 : 0; 71 | setsockopt(_fd, SOL_SOCKET, SO_KEEPALIVE, &optval, static_cast(sizeof(optval))); 72 | } 73 | 74 | void Setnonblocking() { 75 | fcntl(_fd, F_SETFL, fcntl(_fd, F_GETFL) | O_NONBLOCK); 76 | } 77 | 78 | 79 | private: 80 | const int _fd; 81 | }; 82 | 83 | #endif //CMFNETLIB_SOCKET_HPP 84 | -------------------------------------------------------------------------------- /include/net/SocketOps.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Cmf on 2022/5/31. 3 | // 4 | 5 | #pragma once 6 | 7 | #include "base/Log.hpp" 8 | #include 9 | #include 10 | #include 11 | 12 | 13 | namespace SocketOps { 14 | int CreateNonblockingSocket(sa_family_t family); 15 | 16 | void Bind(int fd, const sockaddr *addr); 17 | 18 | void Listen(int fd); 19 | 20 | int Accept(int fd, sockaddr_in *addr); 21 | 22 | void Close(int fd); 23 | 24 | void ShutdownWrite(int fd); 25 | 26 | ssize_t Readv(int fd, const iovec *iov, int iovcnt); 27 | 28 | ssize_t Write(int fd, const void *buf, size_t size); 29 | } -------------------------------------------------------------------------------- /include/net/TcpConnection.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Cmf on 2022/6/9. 3 | // 4 | 5 | #ifndef CMFNETLIB_TCPCONNECTION_HPP 6 | #define CMFNETLIB_TCPCONNECTION_HPP 7 | 8 | #include "base/noncopyable.hpp" 9 | #include "InetAddress.hpp" 10 | #include "Callbacks.hpp" 11 | #include "Buffer.hpp" 12 | 13 | #include 14 | 15 | class EventLoop; 16 | 17 | class Socket; 18 | 19 | class Channel; 20 | 21 | class TcpConnection : private noncopyable, public std::enable_shared_from_this { 22 | public: 23 | TcpConnection(EventLoop *loop, const std::string &name, int sockfd, 24 | const InetAddress &localAddr, 25 | const InetAddress &peerAddr); 26 | 27 | ~TcpConnection(); 28 | 29 | void SetConnectionCallback(const ConnectionCallback &cb) { _connectionCallback = cb; } 30 | 31 | void SetMessageCallback(const MessageCallback &cb) { _messageCallback = cb; } 32 | 33 | void SetWriteCompleteCallback(const WriteCompleteCallback &cb) { _writeCompleteCallback = cb; } 34 | 35 | void SetHighWaterMarkCallback(const HighWaterMarkCallback &cb, size_t highWaterMark) { 36 | _highWaterMarkCallback = cb; 37 | _highWaterMark = highWaterMark; 38 | } 39 | 40 | void SetCloseCallback(const ConnectionCallback &cb) { _closeCallback = cb; } 41 | 42 | const std::string &Name() const { return _name; } 43 | 44 | EventLoop *GetLoop() const { return _loop; } 45 | 46 | //发送数据 47 | void Send(const std::string &buf); 48 | 49 | //关闭连接 50 | void Shutdown(); 51 | 52 | bool Connect() const { return _state == Connected; } 53 | 54 | const InetAddress &LocalAddress() const { return _localAddr; } 55 | 56 | const InetAddress &PeerAddress() const { return _peerAddr; } 57 | 58 | //建立连接 59 | void ConnectEstablished(); 60 | 61 | //连接销毁 62 | void ConnectDestroyed(); 63 | 64 | private: 65 | enum StateE { 66 | Disconnected, 67 | Connecting, 68 | Connected, 69 | Disconnecting 70 | }; 71 | 72 | void SetState(StateE state) { _state = state; } 73 | 74 | void HandleRead(Timestamp receiveTime); 75 | 76 | void HandleWrite(); 77 | 78 | void HandleClose(); 79 | 80 | void HandleError(); 81 | 82 | void SendInLoop(const std::string &msg); 83 | 84 | void ShutdownInLoop(); 85 | 86 | private: 87 | EventLoop *_loop; 88 | const std::string _name; 89 | std::atomic_int _state; 90 | bool _reading; 91 | 92 | std::unique_ptr _socket; 93 | std::unique_ptr _channel; 94 | 95 | const InetAddress _localAddr; //当前主机IP地址端口号 96 | const InetAddress _peerAddr;//对端IP地址端口号 97 | 98 | ConnectionCallback _connectionCallback; 99 | MessageCallback _messageCallback; 100 | WriteCompleteCallback _writeCompleteCallback; 101 | HighWaterMarkCallback _highWaterMarkCallback; 102 | CloseCallback _closeCallback; 103 | 104 | size_t _highWaterMark; 105 | Buffer _inputBuffer;//接收数据的缓冲区 106 | Buffer _outputBuffer;//发送数据的缓冲区 107 | }; 108 | 109 | 110 | #endif //CMFNETLIB_TCPCONNECTION_HPP 111 | -------------------------------------------------------------------------------- /include/net/TcpServer.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Cmf on 2022/6/2. 3 | // 4 | 5 | #ifndef CMFNETLIB_TCPSERVER_HPP 6 | #define CMFNETLIB_TCPSERVER_HPP 7 | 8 | #include "base/noncopyable.hpp" 9 | #include "base/Timestamp.hpp" 10 | #include "Acceptor.hpp" 11 | #include "Callbacks.hpp" 12 | #include "EventLoop.hpp" 13 | #include "InetAddress.hpp" 14 | #include "TcpConnection.hpp" 15 | #include "EventLoopThreadPool.hpp" 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | class TcpServer : private noncopyable { 23 | public: 24 | using ThreadInitCallback = std::function; 25 | enum Option { 26 | NoReusePort, 27 | ReusePort, 28 | }; 29 | 30 | TcpServer(EventLoop *loop, const InetAddress &listenAddr, const std::string &nameArg, Option option = NoReusePort); 31 | 32 | ~TcpServer(); 33 | 34 | void SetThreadInitCallback(const ThreadInitCallback &cb) {_threadInitCallback = cb;} 35 | 36 | void SetConnectionCallback(const ConnectionCallback &cb) { _connectionCallback = cb; } 37 | 38 | void SetMessageCallback(const MessageCallback &cb) { _messageCallback = cb; } 39 | 40 | void SetWriteCompleteCallback(const WriteCompleteCallback &cb) { _writeCompleteCallback = cb; } 41 | 42 | /** 43 | * 置底层subloop的个数 44 | * @param num 45 | */ 46 | void SetThreadNum(int num); 47 | 48 | /** 49 | * 开启服务器监听 实际上就是开启mainloop的accptor的listen 50 | */ 51 | void Start(); 52 | 53 | private: 54 | void NewConnection(int sockfd, const InetAddress &peerAddr);//有新连接来了 55 | void RemoveConnection(const TcpConnectionPtr &conn);//有连接断开了,不要这条连接了 56 | void RemoveConnectionInLoop(const TcpConnectionPtr &conn); 57 | 58 | private: 59 | using ConnectionMap = std::unordered_map; 60 | EventLoop *_loop;//baseLoop 用户定义的loop 一个线程一个loop循环 61 | const std::string _ipPort; 62 | const std::string _name; 63 | std::unique_ptr _acceptor;//运行在mainLoop,任务就是监听新连接事件 64 | std::shared_ptr _threadPool;//线程池 one loop per base 65 | ConnectionCallback _connectionCallback; //有新连接时的回调 66 | MessageCallback _messageCallback;//已连接用户有读写消息时的回调 reactor调用 67 | WriteCompleteCallback _writeCompleteCallback;//消息发送完成以后的回调 68 | ThreadInitCallback _threadInitCallback;//loop线程初始化的回调 69 | std::atomic_int _started; 70 | int _nextConnId; 71 | ConnectionMap _connections;//保存所有的连接 72 | }; 73 | 74 | #endif //CMFNETLIB_TCPSERVER_HPP 75 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | class EchoServer { 7 | public: 8 | EchoServer(EventLoop *loop, 9 | const InetAddress &addr, 10 | const std::string &name) 11 | : server_(loop, addr, name), loop_(loop) { 12 | //注册回调函数 13 | server_.SetConnectionCallback(std::bind(&EchoServer::onConnection, this, std::placeholders::_1)); 14 | 15 | server_.SetMessageCallback(std::bind(&EchoServer::onMessage, this, std::placeholders::_1, std::placeholders::_2,std::placeholders::_3)); 16 | 17 | //设置合适的loop线程数量 loopthread 18 | server_.SetThreadNum(3); 19 | } 20 | 21 | void Start() { 22 | server_.Start(); 23 | } 24 | 25 | private: 26 | //连接建立或者断开的回调 27 | void onConnection(const TcpConnectionPtr &conn) { 28 | if (conn->Connect()) { 29 | LOG_INFO("Connection UP : %s", conn->PeerAddress().ToIpPort().c_str()); 30 | } else { 31 | LOG_INFO("Connection DOWN : %s", conn->PeerAddress().ToIpPort().c_str()); 32 | } 33 | } 34 | 35 | //可读写事件回调 36 | void onMessage(const TcpConnectionPtr &conn, Buffer *buf, Timestamp time) { 37 | std::string msg = buf->RetrieveAllAsString(); 38 | conn->Send(msg); 39 | conn->Shutdown(); // 写端 EPOLLHUP =》 closeCallback_ 40 | } 41 | 42 | private: 43 | EventLoop *loop_; 44 | TcpServer server_; 45 | }; 46 | 47 | int main() { 48 | 49 | EventLoop loop; 50 | InetAddress addr(8000); 51 | EchoServer server(&loop, addr, "EchoServer-01");//Acceptor non-blocking listenfd create bind 52 | server.Start();//listen loopthread listenfd => acceptChannel => mainLoop => 53 | loop.Loop();//启动mainLoop的底层Poller 54 | return 0; 55 | } 56 | -------------------------------------------------------------------------------- /src/base/Thread.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Cmf on 2022/6/8. 3 | // 4 | 5 | #include "base/Thread.hpp" 6 | #include 7 | #include 8 | 9 | std::atomic_int Thread::_numCreated(0); 10 | 11 | Thread::Thread(ThreadFunc func, const std::string &name) : _func(std::move(func)), 12 | _name(name), 13 | _tid(0), 14 | _started(false), 15 | _joined(false) { 16 | int num = ++_numCreated; 17 | if (_name.empty()) {//线程还没有名字 18 | char buf[32] = {0}; 19 | snprintf(buf, sizeof(buf), "Thread %d", num); 20 | _name = buf; 21 | } 22 | } 23 | 24 | Thread::~Thread() { 25 | if (_started && !_joined) {//线程已经运行起来并且不是工作线程join 26 | _thread->detach(); // std::thread类提供的设置分离线程的方法,detach后成为守护线程,守护线程结束后,内核自动回收,不会出现孤儿线程 27 | } 28 | } 29 | 30 | void Thread::Start() { 31 | _started = true; 32 | sem_t sem; 33 | sem_init(&sem, false, 0); 34 | _thread = std::make_shared([&] { 35 | _tid = std::this_thread::get_id(); 36 | sem_post(&sem); 37 | _func(); 38 | }); 39 | sem_wait(&sem); 40 | } 41 | 42 | void Thread::Join() { 43 | _joined = true; 44 | _thread->join(); 45 | } -------------------------------------------------------------------------------- /src/net/Acceptor.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Cmf on 2022/6/9. 3 | // 4 | 5 | #include "net/Acceptor.hpp" 6 | #include "net/SocketOps.hpp" 7 | 8 | Acceptor::Acceptor(EventLoop *loop, const InetAddress &listenAddr, bool reusePort) : 9 | _loop(loop), 10 | _listening(false), 11 | _acceptSocket(SocketOps::CreateNonblockingSocket(listenAddr.Family())), 12 | _acceptChannel(loop, _acceptSocket.GetFd()) { 13 | _acceptSocket.SetReuseAddr(true);//设置端口可重用 14 | _acceptSocket.SetReusePort(true); //设置地址可重用 15 | _acceptSocket.Bind(listenAddr); 16 | _acceptChannel.SetReadCallback(std::bind(&Acceptor::HandleRead, this)); 17 | } 18 | 19 | Acceptor::~Acceptor() { 20 | _acceptChannel.DisableAll();//将其冲poller监听集合中移除,此时为kDeleted状态 21 | _acceptChannel.Remove();//将其从EventList events_中移除,此时为kNew状态 22 | } 23 | 24 | void Acceptor::Listen() { 25 | _listening = true; 26 | _acceptSocket.Listen(); 27 | _acceptChannel.EnableReading();//注册可读事件 28 | } 29 | 30 | void Acceptor::HandleRead() { 31 | InetAddress peerAddr; 32 | int connfd = _acceptSocket.Accept(&peerAddr); 33 | if (connfd >= 0) { 34 | if (_newConnectionCallback) { 35 | _newConnectionCallback(connfd, peerAddr); 36 | } else { 37 | ::close(connfd); 38 | } 39 | } else { 40 | LOG_ERROR("%s:%s:%d accept err:%d", __FILE__, __FUNCTION__, __LINE__, errno); 41 | if (errno == EMFILE) { 42 | LOG_ERROR("%s:%s:%d sockfd reached limit!", __FILE__, __FUNCTION__, __LINE__); 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /src/net/Channel.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Cmf on 2022/6/3. 3 | // 4 | 5 | #include "net/Channel.hpp" 6 | #include "net/EventLoop.hpp" 7 | 8 | void Channel::EnableReading() { 9 | _events |= ReadEvent; 10 | _loop->UpdateChannel(this); 11 | } 12 | 13 | void Channel::DisableReading() { 14 | _events &= ~ReadEvent; 15 | _loop->UpdateChannel(this); 16 | } 17 | 18 | void Channel::EnableWriting() { 19 | _events |= WriteEvent; 20 | _loop->UpdateChannel(this); 21 | } 22 | 23 | void Channel::DisableWriting() { 24 | _events &= ~WriteEvent; 25 | _loop->UpdateChannel(this); 26 | } 27 | 28 | void Channel::DisableAll() { 29 | _events = NoneEvent; 30 | _loop->UpdateChannel(this); 31 | } 32 | 33 | void Channel::Remove() { 34 | _loop->RemoveChannel(this); 35 | } -------------------------------------------------------------------------------- /src/net/DefaultPoller.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Cmf on 2022/6/4. 3 | // 4 | #include "net/Poller.hpp" 5 | #include "net/EPollPoller.hpp" 6 | 7 | Poller *Poller::NewDefaultPoller(EventLoop *loop) { 8 | // 通过此环境变量来决定使用poll还是epoll 9 | if (getenv("MUDUO_USE_POLL")) { 10 | return nullptr; 11 | } else return new EPollPoller(loop); 12 | } -------------------------------------------------------------------------------- /src/net/EPollPoller.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Cmf on 2022/6/4. 3 | // 4 | 5 | #include "net/EPollPoller.hpp" 6 | #include "net/Channel.hpp" 7 | #include 8 | #include 9 | #include 10 | 11 | const int New = -1; //未添加 12 | const int Added = 1; //已添加 13 | const int Deleted = 2; //已删除 14 | 15 | EPollPoller::EPollPoller(EventLoop *loop) : Poller(loop), 16 | _epollFd(epoll_create1(EPOLL_CLOEXEC)), 17 | _events(InitEventListSize) { 18 | if (_epollFd < 0) { 19 | LOG_FATAL("EPollPoller::EPollPoller: %d", errno); 20 | } 21 | } 22 | 23 | EPollPoller::~EPollPoller() noexcept { 24 | close(this->_epollFd); 25 | } 26 | 27 | void EPollPoller::RemoveChannel(Channel *channel) { 28 | int fd = channel->Fd(); 29 | _channels.erase(fd);//从map中删除 30 | LOG_INFO("func:%s fd:%d", __FUNCTION__, fd); 31 | if (channel->Index() == Added) { //如果已经注册过了 32 | this->Update(EPOLL_CTL_DEL, channel);//删除 33 | } 34 | channel->SetIndex(New);//设置为为添加状态 35 | } 36 | 37 | void EPollPoller::UpdateChannel(Channel *channel) { 38 | const int index = channel->Index(); 39 | LOG_INFO("func=%s => fd=%d events=%d index=%d", __FUNCTION__, channel->Fd(), channel->Events(), index); 40 | if (index == New || index == Deleted) { //未添加或已删除 41 | if (index == New) { //如果未添加,键值对写入map中 42 | int fd = channel->Fd(); 43 | _channels[fd] = channel; 44 | } 45 | channel->SetIndex(Added); 46 | this->Update(EPOLL_CTL_ADD, channel); //添加一个channel到epoll 47 | } else { //如果已经添加 48 | int fd = channel->Fd(); 49 | if (channel->IsNoneEvent()) { //如果对任何事件都不感兴趣 50 | this->Update(EPOLL_CTL_DEL, channel); //删除已注册的channel的感兴趣的事件 51 | channel->SetIndex(Deleted); 52 | } else { 53 | this->Update(EPOLL_CTL_MOD, channel); 54 | } 55 | } 56 | } 57 | 58 | Timestamp EPollPoller::Poll(int timeoutMs, ChannelList *activeChannels) { 59 | //LOG_FATAL("fd total count %d", _channels.size()); 60 | int numEvents = epoll_wait(_epollFd, &*_events.begin(), static_cast(_events.size()), timeoutMs); 61 | int saveErrno = errno;// 全局变量errno,poll可能在多个线程中的eventloop被调用,被读写,所以先用局部变量存起来 62 | Timestamp now(Timestamp::Now()); 63 | if (numEvents > 0) {//表示有已经发生相应事件的个数 64 | LOG_INFO("%d events happened", numEvents); 65 | FillActiveChannels(numEvents, activeChannels); 66 | if (numEvents == _events.size()) {//所有的监听的event都发生事件了,得扩容了 67 | _events.resize(_events.size() * 2); 68 | } 69 | } else if (numEvents == 0) {//epoll_wait这一轮监听没有事件发生,timeout超时了 70 | //LOG_DEBUG("%s timeout!", __FUNCTION__); 71 | } else { 72 | if (saveErrno != EINTR) {//不等于外部的中断,是由其他错误类型引起的 73 | errno = saveErrno;//适配,把errno重置成当前loop之前发生的错误的值 74 | LOG_ERROR("EPollPoller::poll() err!"); 75 | } 76 | } 77 | return now; 78 | 79 | } 80 | 81 | void EPollPoller::FillActiveChannels(int numEvents, ChannelList *activeChannels) const { 82 | for (int i = 0; i < numEvents; ++i) { 83 | Channel *channel = static_cast(_events[i].data.ptr); 84 | channel->SetRevents(_events[i].events); 85 | activeChannels->emplace_back(channel);//EventLoop就拿到了它的poller给它返回的所有发生事件的channel列表了 86 | } 87 | } 88 | 89 | void EPollPoller::Update(int operation, Channel *channel) { 90 | epoll_event event; 91 | int fd = channel->Fd(); 92 | memset(&event, 0, sizeof(event)); 93 | event.events = channel->Events(); 94 | event.data.fd = fd; 95 | event.data.ptr = channel; 96 | if (::epoll_ctl(_epollFd, operation, fd, &event) < 0) { 97 | if (operation == EPOLL_CTL_DEL) { 98 | LOG_ERROR("epoll_ctl del error:%d", errno); 99 | } else { 100 | LOG_FATAL("epoll_ctl add/mod error:%d", errno); 101 | } 102 | } 103 | 104 | } 105 | -------------------------------------------------------------------------------- /src/net/EventLoop.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Cmf on 2022/6/7. 3 | // 4 | 5 | #include "net/EventLoop.hpp" 6 | #include "net/Channel.hpp" 7 | #include "net/Poller.hpp" 8 | #include 9 | #include 10 | 11 | //防止一个线程创建多个EventLoop __thread:thread_local 12 | //当一个eventloop创建起来它就指向那个对象,在一个线程里再去创建一个对象,由于这个指针为空,就不创建 13 | __thread EventLoop *t_loopInThisThread = nullptr; 14 | 15 | //定义默认的Poller IO复用接口的超时时间 16 | const int PollTimeMs = 10000;//10秒钟 17 | 18 | EventLoop::EventLoop() : _looping(false), 19 | _quit(false), 20 | _callingPendingFunctors(false), 21 | _poller(Poller::NewDefaultPoller(this)), 22 | _threadId(std::this_thread::get_id()) { 23 | int evtfd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); 24 | if (evtfd < 0) { 25 | LOG_FATAL("eventfd error:%d \n", errno); 26 | } 27 | this->_wakeupFd = evtfd; 28 | this->_wakeupChannel = std::make_unique(this, _wakeupFd); 29 | 30 | LOG_DEBUG("EventLoop Created %p in base %d", this, _threadId); 31 | if (t_loopInThisThread) {//这个线程已经有loop了,就不创建了 32 | LOG_FATAL("Another EventLoop %p exists in this base %d", t_loopInThisThread, _threadId); 33 | } else { 34 | t_loopInThisThread = this; 35 | } 36 | //设置wakeupfd的事件类型以及发生事件后的回调操作 37 | _wakeupChannel->SetReadCallback(std::bind(&EventLoop::HandleRead, this)); 38 | //每一个eventloop都将监听wakeupchannel的EPOLLIN读事件了 39 | _wakeupChannel->EnableReading(); 40 | } 41 | 42 | EventLoop::~EventLoop() { 43 | _wakeupChannel->DisableAll(); 44 | _wakeupChannel->Remove(); 45 | close(_wakeupFd); 46 | t_loopInThisThread = nullptr; 47 | } 48 | 49 | //开启事件循环 驱动底层的poller执行poll 50 | void EventLoop::Loop() { 51 | _looping = true; 52 | _quit = false; 53 | LOG_INFO("EventLoop %p Start Looping!", this); 54 | while (!_quit) { 55 | _activeChannels.clear(); 56 | _pollReturnTime = _poller->Poll(PollTimeMs, &_activeChannels); 57 | for (Channel *channel: _activeChannels) { 58 | //Poller监听哪些channel发生事件了,然后上报给EventLoop,通知channel处理相应的事件 59 | channel->HandleEvent((_pollReturnTime)); 60 | } 61 | this->DoPendingFunctors(); 62 | } 63 | LOG_INFO("EventLoop %p Stop Looping!", this); 64 | _looping = false; 65 | } 66 | 67 | void EventLoop::Quit() { 68 | _quit = true; 69 | if (!this->IsInLoopThread()) { 70 | this->WakeUp(); 71 | } 72 | } 73 | 74 | void EventLoop::RunInLoop(Functor cb) { 75 | if (this->IsInLoopThread()) { 76 | cb(); 77 | } else { 78 | this->QueueInLoop(cb); 79 | } 80 | } 81 | 82 | bool EventLoop::IsInLoopThread() const { 83 | return this->_threadId == std::this_thread::get_id(); 84 | } 85 | 86 | void EventLoop::QueueInLoop(Functor cb) { 87 | { 88 | std::unique_lock(_mtx); 89 | _pendingFunctors.emplace_back(cb); 90 | } 91 | if (!this->IsInLoopThread() || this->_callingPendingFunctors) { 92 | this->WakeUp(); 93 | } 94 | } 95 | 96 | void EventLoop::HandleRead() { 97 | uint64_t one = 1; 98 | ssize_t n = read(_wakeupFd, &one, sizeof(one)); 99 | if (n != sizeof(one)) { 100 | LOG_ERROR("EventLoop::handleRead() reads % lu bytes instead of 8", n); 101 | } 102 | } 103 | 104 | void EventLoop::WakeUp() { 105 | uint64_t one = 1; 106 | ssize_t n = write(_wakeupFd, &one, sizeof(one)); 107 | if (n != sizeof(one)) { 108 | LOG_ERROR("EventLoop::wakeup() writes % lu bytes instead of 8", n); 109 | } 110 | } 111 | 112 | void EventLoop::UpdateChannel(Channel *channel) { 113 | this->_poller->UpdateChannel(channel); 114 | } 115 | 116 | void EventLoop::RemoveChannel(Channel *channel) { 117 | this->_poller->RemoveChannel(channel); 118 | } 119 | 120 | bool EventLoop::HasChannel(Channel *channel) { 121 | return this->_poller->HasChannel(channel); 122 | } 123 | 124 | void EventLoop::DoPendingFunctors() { 125 | std::vector functors; 126 | _callingPendingFunctors = true; 127 | { 128 | std::unique_lock lk(_mtx); 129 | functors.swap(_pendingFunctors); 130 | } 131 | for (const Functor &functor: functors) { 132 | functor(); 133 | } 134 | _callingPendingFunctors = false; 135 | } -------------------------------------------------------------------------------- /src/net/EventLoopThread.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Cmf on 2022/6/8. 3 | // 4 | 5 | #include "net/EventLoopThread.hpp" 6 | #include "net/EventLoop.hpp" 7 | 8 | EventLoopThread::EventLoopThread(const ThreadInitCallback &cb, const std::string &name) : 9 | _loop(nullptr), 10 | _exiting(false), 11 | _thread(std::bind(&EventLoopThread::ThreadFunc, this), name), 12 | _mtx(), 13 | _cond(), 14 | _callback(cb) { 15 | 16 | } 17 | 18 | EventLoopThread::~EventLoopThread() { 19 | _exiting = true; 20 | if (_loop != nullptr) { 21 | _loop->Quit(); 22 | _thread.Join(); 23 | } 24 | } 25 | 26 | EventLoop *EventLoopThread::StartLoop() { 27 | _thread.Start();//启动底层的新线程,启动后执行的是EventLoopThread::threadFunc 28 | EventLoop *loop = nullptr; 29 | { 30 | std::unique_lock lk(_mtx); 31 | while (_loop == nullptr) { 32 | _cond.wait(lk);// 成员变量loop_没有被新线程初始化的时候,一直wait在lock上 33 | } 34 | loop = this->_loop; 35 | } 36 | return loop; 37 | } 38 | 39 | void EventLoopThread::ThreadFunc() { 40 | EventLoop loop;//创建一个独立的eventloop,和上面的线程是一一对应的,one loop per base 41 | if (_callback) { 42 | // 如果我们实现传递了callback_,ThreadInitCallback就是在底层启一个新线程绑定EventLoop时调用的,进行一些init相关操作 43 | _callback(&loop); 44 | } 45 | { 46 | std::unique_lock lk(_mtx); 47 | this->_loop = &loop; 48 | _cond.notify_one(); 49 | } 50 | loop.Loop(); // EventLoop loop => Poller.poll,开启事件循环,监听新用户的连接或者已连接用户的读写事件 51 | //一般来说,loop是一直执行的,能执行到下面的语句,说明程序要退出了,要关闭事件循环 52 | std::unique_lock lk(_mtx); 53 | _loop = nullptr; 54 | } -------------------------------------------------------------------------------- /src/net/EventLoopThreadPool.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Cmf on 2022/6/8. 3 | // 4 | 5 | #include "net/EventLoopThreadPool.hpp" 6 | #include "net/EventLoop.hpp" 7 | #include "net/EventLoopThread.hpp" 8 | 9 | 10 | EventLoopThreadPool::EventLoopThreadPool(EventLoop *baseLoop, const std::string &nameArg) : 11 | _baseLoop(baseLoop), 12 | _started(false), 13 | _name(nameArg), 14 | _numThreads(0), 15 | _next(0) { 16 | 17 | } 18 | 19 | EventLoopThreadPool::~EventLoopThreadPool() {} 20 | 21 | /** 22 | * 根据指定的numThreads_创建线程,开启事件循环 23 | * @param cb 24 | */ 25 | void EventLoopThreadPool::Start(const ThreadInitCallback &cb) { 26 | _started = true; 27 | //整个服务端只有一个线程,运行着baseloop,就是用户创建的mainloop 28 | if (_numThreads == 0 && cb) { 29 | cb(_baseLoop); 30 | } else { 31 | for (int i = 0; i < _numThreads; ++i) { 32 | char buf[this->_name.size() + 32]; 33 | snprintf(buf, sizeof(buf), "%s %d", _name.c_str()), i; 34 | EventLoopThread *t = new EventLoopThread(cb, buf); 35 | _threads.emplace_back(std::unique_ptr(t)); 36 | _loops.emplace_back(t->StartLoop());//底层创建线程,绑定一个新的EventLoop,并返回该loop的地址 37 | } 38 | } 39 | } 40 | 41 | EventLoop *EventLoopThreadPool::GetNextLoop() { 42 | EventLoop *loop = _baseLoop; 43 | if (!_loops.empty()) { 44 | loop = _loops[_next++]; 45 | if (_next >= _loops.size()) { 46 | _next = 0; 47 | } 48 | } 49 | return loop; 50 | } 51 | 52 | std::vector EventLoopThreadPool::GetAllLoops() { 53 | if (_loops.empty()) { 54 | return std::vector(1, _baseLoop); 55 | } else { 56 | return _loops; 57 | } 58 | } -------------------------------------------------------------------------------- /src/net/Poller.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Cmf on 2022/6/4. 3 | // 4 | 5 | #include "net/Poller.hpp" 6 | #include "net/Channel.hpp" 7 | 8 | Poller::Poller(EventLoop *loop) 9 | : _ownerLoop(loop) { 10 | } 11 | 12 | bool Poller::HasChannel(Channel *channel) const { 13 | auto it = _channels.find(channel->Fd()); 14 | return it != _channels.end() && it->second == channel; 15 | } 16 | -------------------------------------------------------------------------------- /src/net/SocketOps.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Cmf on 2022/8/22. 3 | // 4 | 5 | #include "net/SocketOps.hpp" 6 | 7 | 8 | int SocketOps::CreateNonblockingSocket(sa_family_t family) { 9 | int fd = ::socket(family, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, IPPROTO_TCP); 10 | if (fd < 0) { 11 | LOG_FATAL("Sockets::CreateNonblockingSocket"); 12 | } 13 | return fd; 14 | } 15 | 16 | void SocketOps::Bind(int fd, const sockaddr *addr) { 17 | if (::bind(fd, addr, sizeof(sockaddr_in)) < 0) { 18 | LOG_FATAL("Sockets::Bind"); 19 | } 20 | } 21 | 22 | void SocketOps::Listen(int fd) { 23 | if (::listen(fd, SOMAXCONN) < 0) { 24 | LOG_FATAL("Sockets::Listen"); 25 | } 26 | } 27 | 28 | int SocketOps::Accept(int fd, sockaddr_in *addr) { 29 | socklen_t addrlen = static_cast(sizeof(*addr)); 30 | int connfd = ::accept4(fd, (sockaddr *) addr, &addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC); 31 | if (connfd < 0) { 32 | LOG_FATAL("Sockets::Accept"); 33 | int no = errno; 34 | switch (no) { 35 | case EMFILE: 36 | errno = no; 37 | break; 38 | case EOPNOTSUPP: 39 | LOG_FATAL("unexpected error of ::accept %d", no); 40 | break; 41 | } 42 | } 43 | return connfd; 44 | } 45 | 46 | void SocketOps::Close(int fd) { 47 | if (::close(fd) < 0) { 48 | LOG_FATAL("Sockets::Close"); 49 | } 50 | } 51 | 52 | void SocketOps::ShutdownWrite(int fd) { 53 | if (::shutdown(fd, SHUT_WR) < 0) { 54 | LOG_FATAL("sockets::shutdownWrite"); 55 | } 56 | } 57 | 58 | ssize_t SocketOps::Readv(int fd, const iovec *iov, int iovcnt) { 59 | return ::readv(fd, iov, iovcnt); 60 | } 61 | 62 | ssize_t SocketOps::Write(int fd, const void *buf, size_t size) { 63 | return ::write(fd, buf, size); 64 | } 65 | -------------------------------------------------------------------------------- /src/net/TcpConnection.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Cmf on 2022/6/9. 3 | // 4 | 5 | #include "net/TcpConnection.hpp" 6 | #include "net/EventLoop.hpp" 7 | #include "net/Socket.hpp" 8 | #include "net/Channel.hpp" 9 | 10 | TcpConnection::TcpConnection(EventLoop *loop, const std::string &name, int sockfd, const InetAddress &localAddr, 11 | const InetAddress &peerAddr) : 12 | _loop(loop), 13 | _name(name), 14 | _state(Connecting), 15 | _reading(true), 16 | _socket(new Socket(sockfd)), 17 | _channel(new Channel(loop, sockfd)), 18 | _localAddr(localAddr), 19 | _peerAddr(peerAddr), 20 | _highWaterMark(64 * 1024 * 1024) /*超过64M就到水位线了,要停止发送*/ { 21 | _channel->SetReadCallback(std::bind(&TcpConnection::HandleRead, this, std::placeholders::_1)); 22 | _channel->SetWriteCallback(std::bind(&TcpConnection::HandleWrite, this)); 23 | _channel->SetErrorCallback(std::bind(&TcpConnection::HandleError, this)); 24 | _channel->SetCloseCallback(std::bind(&TcpConnection::HandleClose, this)); 25 | LOG_INFO("TcpConnection::ctor[%s] at fd=%d", _name.c_str(), sockfd); 26 | _socket->SetKeepAlive(true); 27 | } 28 | 29 | TcpConnection::~TcpConnection() { 30 | LOG_INFO("TcpConnection::dtor[%s] at fd=%d state=%d", _name.c_str(), _channel->Fd(), static_cast(_state)); 31 | } 32 | 33 | void TcpConnection::Send(const std::string &buf) { 34 | if (_state == Connected) { 35 | if (_loop->IsInLoopThread()) {//当前loop是不是在对应的线程 36 | SendInLoop(buf); 37 | } else { 38 | _loop->RunInLoop(std::bind(&TcpConnection::SendInLoop, this, buf)); 39 | } 40 | } 41 | } 42 | 43 | /** 44 | * 发送数据 应用写的快, 而内核发送数据慢, 需要把待发送数据写入缓冲区, 而且设置了水位回调 45 | */ 46 | void TcpConnection::SendInLoop(const std::string &msg) { 47 | ssize_t nwrote = 0; 48 | size_t remaining = msg.size(); 49 | bool faultError = false; 50 | //之前调用过该connection的shutdown,不能再进行发送了 51 | if (_state == Disconnected) { 52 | LOG_ERROR("disconnected, give up writing!"); 53 | return; 54 | } 55 | //表示channel_第一次开始写数据,而且缓冲区没有待发送数据 56 | if (!_channel->IsWriting() && _outputBuffer.ReadableBytes() == 0) { 57 | nwrote = ::write(_channel->Fd(), msg.c_str(), msg.size()); 58 | if (nwrote >= 0) { 59 | remaining = msg.size() - nwrote; 60 | if (remaining == 0 && _writeCompleteCallback) { 61 | //既然在这里数据全部发送完成,就不用再给channel设置epollout事件了 62 | _loop->QueueInLoop(std::bind(_writeCompleteCallback, shared_from_this())); 63 | } 64 | } else {//nwrote < 0 65 | nwrote = 0; 66 | if (errno != EWOULDBLOCK) { 67 | LOG_ERROR("TcpConnection::sendInLoop"); 68 | if (errno == EPIPE || errno == ECONNRESET) {// SIGPIPE RESET 69 | faultError = true; 70 | } 71 | } 72 | } 73 | } 74 | //说明当前这一次write,并没有把数据全部发送出去,剩余的数据需要保存到缓冲区当中,然后给channel 75 | //注册epollout事件,poller发现tcp的发送缓冲区有空间,会通知相应的sock-channel,调用writeCallback_回调方法 76 | //也就是调用TcpConnection::handleWrite方法,把发送缓冲区中的数据全部发送完成 77 | if (!faultError && remaining > 0) { 78 | //目前发送缓冲区剩余的待发送数据的长度 79 | size_t oldLen = _outputBuffer.ReadableBytes(); 80 | if (oldLen + remaining >= _highWaterMark 81 | && oldLen < _highWaterMark 82 | && _highWaterMarkCallback) { 83 | _loop->QueueInLoop(std::bind(_highWaterMarkCallback, shared_from_this(), oldLen + remaining)); 84 | } 85 | _outputBuffer.Append(msg.c_str() + nwrote, remaining); 86 | if (!_channel->IsWriting()) { 87 | _channel->EnableWriting();//这里一定要注册channel的写事件,否则poller不会给channel通知epollout 88 | } 89 | } 90 | } 91 | 92 | void TcpConnection::Shutdown() { 93 | if (_state == Connected) { 94 | SetState(Disconnecting); 95 | _loop->RunInLoop(std::bind(&TcpConnection::ShutdownInLoop, this)); 96 | } 97 | } 98 | 99 | void TcpConnection::ShutdownInLoop() { 100 | if (!_channel->IsWriting()) { 101 | _socket->ShutdownWrite();//关闭写端 102 | } 103 | } 104 | 105 | void TcpConnection::ConnectEstablished() { 106 | SetState(Connected); 107 | _channel->Tie(shared_from_this()); 108 | _channel->EnableReading();//向poller注册channel的epollin事件 109 | } 110 | 111 | void TcpConnection::ConnectDestroyed() { 112 | if (_state == Connected) { 113 | SetState(Disconnected); 114 | _channel->DisableAll(); // 把channel的所有感兴趣的事件,从poller中del掉 115 | _connectionCallback(shared_from_this()); 116 | } 117 | _channel->Remove();//把channel从poller中删除掉 118 | } 119 | 120 | void TcpConnection::HandleRead(Timestamp receiveTime) { 121 | int savedErrno = 0; 122 | ssize_t n = _inputBuffer.ReadFd(_channel->Fd(), &savedErrno); 123 | //已建立连接的用户,有可读事件发生了,调用用户传入的回调操作onMessage 124 | if (n > 0) { 125 | _messageCallback(shared_from_this(), &_inputBuffer, receiveTime); 126 | } else if (n == 0) { 127 | this->HandleClose(); 128 | } else { 129 | errno = savedErrno; 130 | LOG_ERROR("TcpConnection::handleRead"); 131 | this->HandleError(); 132 | } 133 | } 134 | 135 | void TcpConnection::HandleWrite() { 136 | if (_channel->IsWriting()) { 137 | int savedErrno = 0; 138 | ssize_t n = _outputBuffer.WriteFd(_channel->Fd(), &savedErrno); 139 | if (n > 0) { 140 | _outputBuffer.Retrieve(n); 141 | if (_outputBuffer.ReadableBytes() == 0) { 142 | _channel->DisableWriting(); 143 | if (_writeCompleteCallback) { 144 | //唤醒loop_对应的thread线程,执行回调 145 | _loop->QueueInLoop(std::bind(_writeCompleteCallback, shared_from_this())); 146 | } 147 | if (_state == Disconnecting) { 148 | ShutdownInLoop(); 149 | } 150 | } 151 | } else { 152 | LOG_ERROR("TcpConnection::handleWrite"); 153 | } 154 | } else { 155 | LOG_ERROR("TcpConnection fd=%d is down, no more writing", _channel->Fd()); 156 | } 157 | } 158 | 159 | void TcpConnection::HandleClose() { 160 | LOG_INFO("TcpConnection::handleClose fd=%d state=%d", _channel->Fd(), static_cast(_state)); 161 | SetState(Disconnected); 162 | _channel->DisableAll(); 163 | TcpConnectionPtr connPtr(shared_from_this()); 164 | _connectionCallback(connPtr);//执行连接关闭的回调 165 | _closeCallback(connPtr);//关闭连接的回调 执行的是TcpServer::removeConnection回调方法 166 | } 167 | 168 | void TcpConnection::HandleError() { 169 | int optval; 170 | socklen_t optlen = sizeof optval; 171 | int err = 0; 172 | if (getsockopt(_channel->Fd(), SOL_SOCKET, SO_ERROR, &optval, &optlen) < 0) { 173 | err = errno; 174 | } else { 175 | err = optval; 176 | } 177 | LOG_ERROR("TcpConnection::handleError name:%s - SO_ERROR:%d", _name.c_str(), err); 178 | } -------------------------------------------------------------------------------- /src/net/TcpServer.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Cmf on 2022/6/9. 3 | // 4 | #include "net/TcpServer.hpp" 5 | #include "net/EventLoopThreadPool.hpp" 6 | 7 | TcpServer::TcpServer(EventLoop *loop, const InetAddress &listenAddr, const std::string &nameArg, Option option) : 8 | _loop(loop), 9 | _ipPort(listenAddr.ToIpPort()), 10 | _name(nameArg), 11 | _acceptor(new Acceptor(loop, listenAddr, option == ReusePort)), 12 | _threadPool(new EventLoopThreadPool(loop, _name)), 13 | _connectionCallback(), 14 | _messageCallback(), 15 | _writeCompleteCallback(), 16 | _nextConnId(1), 17 | _started(0) { 18 | _acceptor->SetNewConnectionCallback( 19 | std::bind(&TcpServer::NewConnection, this, std::placeholders::_1, std::placeholders::_2)); 20 | } 21 | 22 | TcpServer::~TcpServer() { 23 | for (auto &item: _connections) { 24 | //这个局部的shared_ptr智能指针对象,出右括号,可以自动释放new出来的TcpConnection对象资源了 25 | TcpConnectionPtr conn(item.second); 26 | item.second.reset(); 27 | conn->GetLoop()->RunInLoop(std::bind(&TcpConnection::ConnectDestroyed, conn)); 28 | } 29 | } 30 | 31 | void TcpServer::SetThreadNum(int num) { 32 | _threadPool->SetThreadNum(num); 33 | } 34 | 35 | void TcpServer::Start() { 36 | if (_started++ == 0) { 37 | _threadPool->Start(_threadInitCallback); 38 | _loop->RunInLoop(std::bind(&Acceptor::Listen, _acceptor.get())); 39 | } 40 | } 41 | 42 | /** 43 | * 有一个新的客户端的连接,acceptor会执行这个回调操作 44 | * @param sockfd 45 | * @param peerAddr 46 | */ 47 | void TcpServer::NewConnection(int sockfd, const InetAddress &peerAddr) { 48 | EventLoop *ioLoop = _threadPool->GetNextLoop(); 49 | char buf[64] = {0}; 50 | snprintf(buf, sizeof(buf), "-%s#%d", _ipPort.c_str(), _nextConnId); 51 | ++_nextConnId; 52 | std::string connName = _name + buf; 53 | LOG_INFO("TcpServer::newConnection [%s] - new connection [%s] from %s", _name.c_str(), connName.c_str(), 54 | peerAddr.ToIpPort().c_str()); 55 | //通过sockfd获取其绑定的本机的ip地址和端口信息 56 | sockaddr_in local; 57 | memset(&local, 0, sizeof(local)); 58 | socklen_t addrlen = sizeof(local); 59 | if (getsockname(sockfd, (sockaddr *) &local, &addrlen) < 0) { 60 | LOG_ERROR("sockets::getLocalAddr"); 61 | } 62 | InetAddress localAddr(local); 63 | //根据连接成功的sockfd,创建TcpConnection连接对象 64 | TcpConnectionPtr conn(new TcpConnection(ioLoop, connName, sockfd, localAddr, peerAddr)); 65 | _connections[connName] = conn; 66 | //下面的回调都是用户设置给TcpServer=>TcpConnection=>Channel=>Poller=>notify channel调用回调 67 | conn->SetConnectionCallback(_connectionCallback); 68 | conn->SetMessageCallback(_messageCallback); 69 | conn->SetWriteCompleteCallback(_writeCompleteCallback); 70 | //设置了如何关闭连接的回调 conn->shutDown() 71 | conn->SetCloseCallback(std::bind(&TcpServer::RemoveConnection, this, std::placeholders::_1)); 72 | //直接调用TcpConnection::connectEstablished 73 | ioLoop->RunInLoop(std::bind(&TcpConnection::ConnectEstablished, conn)); 74 | } 75 | 76 | void TcpServer::RemoveConnection(const TcpConnectionPtr &conn) { 77 | _loop->RunInLoop(std::bind(&TcpServer::RemoveConnectionInLoop, this, conn)); 78 | } 79 | 80 | void TcpServer::RemoveConnectionInLoop(const TcpConnectionPtr &conn) { 81 | LOG_INFO("TcpServer::removeConnectionInLoop [%s] - connection %s", _name.c_str(), conn->Name().c_str()); 82 | _connections.erase(conn->Name()); 83 | EventLoop *ioLoop = conn->GetLoop(); 84 | ioLoop->QueueInLoop(std::bind(&TcpConnection::ConnectDestroyed, conn)); 85 | } -------------------------------------------------------------------------------- /test/log.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Cmf on 2022/5/23. 3 | // 4 | 5 | #include "NetLib/log/Log.hpp" 6 | #include 7 | 8 | int main() { 9 | 10 | std::vector threads; 11 | for (int i = 0; i < 10; ++i) { 12 | threads.push_back(std::thread([]() { 13 | for(int i = 0 ;i<10;++i) 14 | { 15 | LOG_INFO("Just a FMT INFO Test! %d, %s", 1, "中文"); 16 | //std::this_thread::sleep_for(std::chrono::milliseconds(1000)); 17 | } 18 | })); 19 | } 20 | for (auto &thread: threads) { 21 | thread.join(); 22 | } 23 | return 0; 24 | } 25 | --------------------------------------------------------------------------------