├── .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 |
--------------------------------------------------------------------------------