├── CMakeLists.txt ├── README.md ├── example ├── http_server │ ├── CMakeLists.txt │ ├── http │ │ ├── HttpContext.cpp │ │ ├── HttpContext.hpp │ │ ├── HttpRequest.hpp │ │ ├── HttpResponse.cpp │ │ ├── HttpResponse.hpp │ │ ├── HttpServer.cpp │ │ └── HttpServer.hpp │ └── main.cpp └── muduo_server │ └── example_server.cpp ├── includes ├── async_logging ├── muduo_logger │ ├── AsyncLogging.hpp │ ├── Condition.hpp │ ├── FileUtil.hpp │ ├── LogFile.hpp │ ├── LogStream.hpp │ ├── Logger.hpp │ ├── Thread.hpp │ ├── TimeStamp.hpp │ ├── ptr_vector.hpp │ └── scoped_ptr.hpp ├── muduo_network │ ├── Acceptor.hpp │ ├── Atomic.hpp │ ├── Buffer.hpp │ ├── CallBacks.hpp │ ├── Channel.hpp │ ├── CurrentThread.hpp │ ├── Endian.hpp │ ├── Epoll.hpp │ ├── EventLoop.hpp │ ├── EventLoopThread.hpp │ ├── EventLoopThreadPool.hpp │ ├── InetAddress.hpp │ ├── Poll.hpp │ ├── Poller.hpp │ ├── Socket.hpp │ ├── SocketHelp.hpp │ ├── TcpConnection.hpp │ ├── TcpServer.hpp │ ├── Timer.hpp │ ├── TimerId.hpp │ └── TimerQueue.hpp └── muduo_server └── sources ├── muduo_logger ├── AsyncLogging.cpp ├── FileUtil.cpp ├── LogFile.cpp ├── LogStream.cpp ├── Logger.cpp ├── Thread.cpp └── TimeStamp.cpp └── muduo_network ├── Acceptor.cpp ├── Buffer.cpp ├── Channel.cpp ├── CurrentThread.cpp ├── Epoll.cpp ├── EventLoop.cpp ├── EventLoopThread.cpp ├── EventLoopThreadPool.cpp ├── InetAddress.cpp ├── Poll.cpp ├── Poller.cpp ├── Socket.cpp ├── SocketHelp.cpp ├── TcpConnection.cpp ├── TcpServer.cpp ├── Timer.cpp └── TimerQueue.cpp /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 2.8.7) 2 | project (cpp11_muduo) 3 | 4 | ### 5 | # variables 6 | ### 7 | set(SOURCES_DIRECTORY ${PROJECT_SOURCE_DIR}/sources) 8 | set(INCLUDES_DIRECTORY ${PROJECT_SOURCE_DIR}/includes) 9 | set(EXAMPLE_DIRECTORY ${PROJECT_SOURCE_DIR}/example) 10 | 11 | set(MUDUO_LOGGER_INCLUDES ${INCLUDES_DIRECTORY}/muduo_logger) 12 | set(MUDUO_NETWORK_INCLUDES ${INCLUDES_DIRECTORY}/muduo_network) 13 | 14 | ### 15 | # includes 16 | ### 17 | include_directories(${INCLUDES_DIRECTORY} 18 | ${MUDUO_LOGGER_INCLUDES} 19 | ${MUDUO_NETWORK_INCLUDES}) 20 | 21 | ### 22 | # libraries 23 | ### 24 | link_directories("${PROJECT_SOURCE_DIR}/library") 25 | 26 | ### 27 | # outputs 28 | ### 29 | #set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) 30 | #set(CMAKE_PKGCONFIG_OUTPUT_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/pkgconfig) 31 | #set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) 32 | 33 | set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/library) 34 | set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin) 35 | 36 | ### 37 | # compilation options 38 | ### 39 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -W -Wall -Wextra -O3") 40 | 41 | # print compile info 42 | #set(CMAKE_VERBOSE_MAKEFILE ON) 43 | 44 | ### 45 | # sources file 46 | ### 47 | set(MUDUO_NETWORK_SOURCES_DIRECTORY ${SOURCES_DIRECTORY}/muduo_network) 48 | set(MUDUO_LOGGER_SOURCES_DIRECTORY ${SOURCES_DIRECTORY}/muduo_logger) 49 | 50 | foreach(dir ${MUDUO_LOGGER_SOURCES_DIRECTORY}) 51 | # get directory sources and headers 52 | file(GLOB s_${dir} "${dir}/*.cpp") 53 | file(GLOB h_${dir} "${dir}/*.hpp") 54 | 55 | # set muiduo_logger sources 56 | set(muduo_logger_sources ${s_${dir}} ${h_${dir}}) 57 | endforeach() 58 | 59 | foreach(dir ${MUDUO_NETWORK_SOURCES_DIRECTORY}) 60 | # get directory sources and headers 61 | file(GLOB s_${dir} "${dir}/*.cpp") 62 | file(GLOB h_${dir} "${dir}/*.hpp") 63 | 64 | # set muiduo_network sources 65 | set(muduo_network_sources ${s_${dir}} ${h_${dir}}) 66 | endforeach() 67 | 68 | #message("muduo_network_sources: ${muduo_network_sources}") 69 | 70 | set(example_server_sources 71 | ${EXAMPLE_DIRECTORY}/muduo_server/example_server.cpp 72 | ) 73 | 74 | ### 75 | #library 76 | ### 77 | add_library(async_logging ${muduo_logger_sources}) 78 | 79 | add_library(muduo_server ${muduo_network_sources}) 80 | 81 | ### 82 | # executable 83 | ### 84 | add_executable(example_server ${example_server_sources}) 85 | 86 | ### 87 | # link librarys 88 | ### 89 | target_link_libraries(async_logging pthread) 90 | 91 | target_link_libraries(muduo_server async_logging) 92 | target_link_libraries(muduo_server pthread) 93 | 94 | 95 | target_link_libraries(example_server async_logging 96 | muduo_server 97 | pthread) 98 | 99 | ### 100 | #sub project 101 | ### 102 | add_subdirectory(${EXAMPLE_DIRECTORY}/http_server) 103 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cpp11_muduo 2 | c++11 implementation of muduo net lib and muduo asynclogging. 3 | 4 | original author github: https://github.com/chenshuo/muduo 5 | 6 | 7 | ## 整理的muduo网络库的c++11版 8 | 9 | 因为SimpleMuduo不是稳定版,于是新建了一个仓库维护下这个c++11版。 10 | 小bug会在这里修复,SimpleMuduo不再更新,有兴趣的话可以一起维护一下。 11 | 12 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20190430180209604.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzE3MzA4MzIx,size_16,color_FFFFFF,t_70) 13 | 14 | 15 | ```cpp 16 | #include 17 | #include 18 | 19 | void on_connection(const muduo::TcpConnectionPtr& conn){ 20 | LOG_DEBUG << "new conn from " << conn->peerAddress().toIpPort(); 21 | } 22 | 23 | void on_message(const muduo::TcpConnectionPtr& conn, muduo::Buffer* buffer, ssize_t len){ 24 | LOG_DEBUG << "on message : " << len << " bytes " << buffer->peek(); 25 | buffer->retrieve(len); 26 | } 27 | 28 | int main(){ 29 | 30 | Logger::setLogLevel(Logger::DEBUG); 31 | 32 | muduo::EventLoop loop; 33 | 34 | InetAddress localAddr(8080); 35 | muduo::TcpServer tcp_server(&loop, localAddr); 36 | 37 | tcp_server.setConnectionCallBack(std::bind(on_connection, std::placeholders::_1)); 38 | tcp_server.setMessageCallBack(std::bind(on_message, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); 39 | //tcp_server.setCloseCallBack(std::bind(on_close, std::placeholders::_1)); 40 | tcp_server.start(); 41 | 42 | loop.loop(); 43 | 44 | getchar(); 45 | } 46 | ``` 47 | 48 | ![Alt text](https://img-blog.csdnimg.cn/20190429233902624.png) 49 | 50 | -------------------2019/4/30 51 | ## 添加http处理代码及测试样例 : 52 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20190430175347932.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzE3MzA4MzIx,size_16,color_FFFFFF,t_70) 53 | -------------------------------------------------------------------------------- /example/http_server/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 2.8.7) 2 | project (http_server) 3 | 4 | ### 5 | # variables 6 | ### 7 | set(PROJECT_ROOT_DIR ${PROJECT_SOURCE_DIR}/../../) 8 | set(SOURCES_DIRECTORY ../../example) 9 | set(INCLUDES_DIRECTORY ../../includes) 10 | 11 | set(MUDUO_LOGGER_INCLUDES ${INCLUDES_DIRECTORY}/muduo_logger) 12 | set(MUDUO_NETWORK_INCLUDES ${INCLUDES_DIRECTORY}/muduo_network) 13 | 14 | ### 15 | # includes 16 | ### 17 | include_directories(. 18 | ./http 19 | ${INCLUDES_DIRECTORY} 20 | ${MUDUO_LOGGER_INCLUDES} 21 | ${MUDUO_NETWORK_INCLUDES}) 22 | 23 | ### 24 | # libraries 25 | ### 26 | link_directories("${PROJECT_ROOT_DIR}/library") 27 | 28 | ### 29 | # outputs 30 | ### 31 | #set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) 32 | #set(CMAKE_PKGCONFIG_OUTPUT_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/pkgconfig) 33 | #set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) 34 | 35 | set(LIBRARY_OUTPUT_PATH ${PROJECT_ROOT_DIR}/library) 36 | set(EXECUTABLE_OUTPUT_PATH ${PROJECT_ROOT_DIR}/bin) 37 | 38 | ### 39 | # compilation options 40 | ### 41 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -W -Wall -Wextra -O3") 42 | 43 | # print compile info 44 | #set(CMAKE_VERBOSE_MAKEFILE ON) 45 | 46 | ### 47 | # sources file 48 | ### 49 | set(http_server_sources 50 | ${SOURCES_DIRECTORY}/http_server/http/HttpContext.cpp 51 | ${SOURCES_DIRECTORY}/http_server/http/HttpResponse.cpp 52 | ${SOURCES_DIRECTORY}/http_server/main.cpp 53 | ) 54 | 55 | ### 56 | #library 57 | ### 58 | 59 | ### 60 | # executable 61 | ### 62 | add_executable(http_server ${http_server_sources}) 63 | 64 | ### 65 | # link librarys 66 | ### 67 | target_link_libraries(http_server async_logging 68 | muduo_server 69 | pthread) -------------------------------------------------------------------------------- /example/http_server/http/HttpContext.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | // 9 | 10 | #include 11 | #include "HttpContext.hpp" 12 | 13 | using namespace muduo; 14 | using namespace http; 15 | 16 | bool HttpContext::processRequestLine(const char* begin, const char* end) 17 | { 18 | bool succeed = false; 19 | const char* start = begin; 20 | const char* space = std::find(start, end, ' '); 21 | if (space != end && request_.setMethod(start, space)) 22 | { 23 | start = space+1; 24 | space = std::find(start, end, ' '); 25 | if (space != end) 26 | { 27 | const char* question = std::find(start, space, '?'); 28 | if (question != space) 29 | { 30 | request_.setPath(start, question); 31 | request_.setQuery(question, space); 32 | } 33 | else 34 | { 35 | request_.setPath(start, space); 36 | } 37 | start = space+1; 38 | succeed = end-start == 8 && std::equal(start, end-1, "HTTP/1."); 39 | if (succeed) 40 | { 41 | if (*(end-1) == '1') 42 | { 43 | request_.setVersion(HttpRequest::kHttp11); 44 | } 45 | else if (*(end-1) == '0') 46 | { 47 | request_.setVersion(HttpRequest::kHttp10); 48 | } 49 | else 50 | { 51 | succeed = false; 52 | } 53 | } 54 | } 55 | } 56 | return succeed; 57 | } 58 | 59 | // return false if any error 60 | bool HttpContext::parseRequest(Buffer* buf, TimeStamp receiveTime) 61 | { 62 | bool ok = true; 63 | bool hasMore = true; 64 | while (hasMore) 65 | { 66 | if (state_ == kExpectRequestLine) 67 | { 68 | const char* crlf = buf->findCRLF(); 69 | if (crlf) 70 | { 71 | ok = processRequestLine(buf->peek(), crlf); 72 | if (ok) 73 | { 74 | request_.setReceiveTime(receiveTime); 75 | buf->retrieveUntil(crlf + 2); 76 | state_ = kExpectHeaders; 77 | } 78 | else 79 | { 80 | hasMore = false; 81 | } 82 | } 83 | else 84 | { 85 | hasMore = false; 86 | } 87 | } 88 | else if (state_ == kExpectHeaders) 89 | { 90 | const char* crlf = buf->findCRLF(); 91 | if (crlf) 92 | { 93 | const char* colon = std::find(buf->peek(), crlf, ':'); 94 | if (colon != crlf) 95 | { 96 | request_.addHeader(buf->peek(), colon, crlf); 97 | } 98 | else 99 | { 100 | // empty line, end of header 101 | // FIXME: 102 | state_ = kGotAll; 103 | hasMore = false; 104 | } 105 | buf->retrieveUntil(crlf + 2); 106 | } 107 | else 108 | { 109 | hasMore = false; 110 | } 111 | } 112 | else if (state_ == kExpectBody) 113 | { 114 | // FIXME: 115 | } 116 | } 117 | return ok; 118 | } 119 | -------------------------------------------------------------------------------- /example/http_server/http/HttpContext.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "HttpRequest.hpp" 4 | 5 | namespace muduo { 6 | class Buffer; 7 | } 8 | 9 | namespace http { 10 | 11 | class HttpContext 12 | { 13 | public: 14 | enum HttpRequestParseState 15 | { 16 | kExpectRequestLine, 17 | kExpectHeaders, 18 | kExpectBody, 19 | kGotAll, 20 | }; 21 | 22 | HttpContext() 23 | : state_(kExpectRequestLine) 24 | { 25 | } 26 | 27 | // default copy-ctor, dtor and assignment are fine 28 | 29 | // return false if any error 30 | bool parseRequest(muduo::Buffer* buf, TimeStamp receiveTime); 31 | 32 | bool gotAll() const 33 | { return state_ == kGotAll; } 34 | 35 | void reset() 36 | { 37 | state_ = kExpectRequestLine; 38 | HttpRequest dummy; 39 | request_.swap(dummy); 40 | } 41 | 42 | const HttpRequest& request() const 43 | { return request_; } 44 | 45 | HttpRequest& request() 46 | { return request_; } 47 | 48 | private: 49 | bool processRequestLine(const char* begin, const char* end); 50 | 51 | HttpRequestParseState state_; 52 | HttpRequest request_; 53 | }; 54 | 55 | } // namespace http 56 | 57 | -------------------------------------------------------------------------------- /example/http_server/http/HttpRequest.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace http 9 | { 10 | 11 | class HttpRequest 12 | { 13 | public: 14 | enum Method 15 | { 16 | kInvalid, kGet, kPost, kHead, kPut, kDelete 17 | }; 18 | enum Version 19 | { 20 | kUnknown, kHttp10, kHttp11 21 | }; 22 | 23 | HttpRequest() 24 | : method_(kInvalid), 25 | version_(kUnknown) 26 | { 27 | } 28 | 29 | void setVersion(Version v) 30 | { 31 | version_ = v; 32 | } 33 | 34 | Version getVersion() const 35 | { return version_; } 36 | 37 | bool setMethod(const char* start, const char* end) 38 | { 39 | assert(method_ == kInvalid); 40 | std::string m(start, end); 41 | if (m == "GET") 42 | { 43 | method_ = kGet; 44 | } 45 | else if (m == "POST") 46 | { 47 | method_ = kPost; 48 | } 49 | else if (m == "HEAD") 50 | { 51 | method_ = kHead; 52 | } 53 | else if (m == "PUT") 54 | { 55 | method_ = kPut; 56 | } 57 | else if (m == "DELETE") 58 | { 59 | method_ = kDelete; 60 | } 61 | else 62 | { 63 | method_ = kInvalid; 64 | } 65 | return method_ != kInvalid; 66 | } 67 | 68 | Method method() const 69 | { return method_; } 70 | 71 | const char* methodString() const 72 | { 73 | const char* result = "UNKNOWN"; 74 | switch(method_) 75 | { 76 | case kGet: 77 | result = "GET"; 78 | break; 79 | case kPost: 80 | result = "POST"; 81 | break; 82 | case kHead: 83 | result = "HEAD"; 84 | break; 85 | case kPut: 86 | result = "PUT"; 87 | break; 88 | case kDelete: 89 | result = "DELETE"; 90 | break; 91 | default: 92 | break; 93 | } 94 | return result; 95 | } 96 | 97 | void setPath(const char* start, const char* end) 98 | { 99 | path_.assign(start, end); 100 | } 101 | 102 | const std::string& path() const 103 | { return path_; } 104 | 105 | void setQuery(const char* start, const char* end) 106 | { 107 | query_.assign(start, end); 108 | } 109 | 110 | const std::string& query() const 111 | { return query_; } 112 | 113 | void setReceiveTime(TimeStamp t) 114 | { receiveTime_ = t; } 115 | 116 | TimeStamp receiveTime() const 117 | { return receiveTime_; } 118 | 119 | void addHeader(const char* start, const char* colon, const char* end) 120 | { 121 | std::string field(start, colon); 122 | ++colon; 123 | while (colon < end && isspace(*colon)) 124 | { 125 | ++colon; 126 | } 127 | std::string value(colon, end); 128 | while (!value.empty() && isspace(value[value.size()-1])) 129 | { 130 | value.resize(value.size()-1); 131 | } 132 | headers_[field] = value; 133 | } 134 | 135 | std::string getHeader(const std::string& field) const 136 | { 137 | std::string result; 138 | std::map::const_iterator it = headers_.find(field); 139 | if (it != headers_.end()) 140 | { 141 | result = it->second; 142 | } 143 | return result; 144 | } 145 | 146 | const std::map& headers() const 147 | { return headers_; } 148 | 149 | void swap(HttpRequest& that) 150 | { 151 | std::swap(method_, that.method_); 152 | std::swap(version_, that.version_); 153 | path_.swap(that.path_); 154 | query_.swap(that.query_); 155 | receiveTime_.swap(that.receiveTime_); 156 | headers_.swap(that.headers_); 157 | } 158 | 159 | private: 160 | Method method_; 161 | Version version_; 162 | std::string path_; 163 | std::string query_; 164 | TimeStamp receiveTime_; 165 | std::map headers_; 166 | }; 167 | 168 | } // namespace http 169 | 170 | -------------------------------------------------------------------------------- /example/http_server/http/HttpResponse.cpp: -------------------------------------------------------------------------------- 1 | #include "HttpResponse.hpp" 2 | #include 3 | 4 | #include 5 | 6 | using namespace muduo; 7 | using namespace http; 8 | 9 | void HttpResponse::appendToBuffer(Buffer* output) const 10 | { 11 | char buf[32]; 12 | snprintf(buf, sizeof buf, "HTTP/1.1 %d ", statusCode_); 13 | output->append(buf); 14 | output->append(statusMessage_); 15 | output->append("\r\n"); 16 | 17 | if (closeConnection_) 18 | { 19 | output->append("Connection: close\r\n"); 20 | } 21 | else 22 | { 23 | snprintf(buf, sizeof buf, "Content-Length: %zd\r\n", body_.size()); 24 | output->append(buf); 25 | output->append("Connection: Keep-Alive\r\n"); 26 | } 27 | 28 | for (const auto& header : headers_) 29 | { 30 | output->append(header.first); 31 | output->append(": "); 32 | output->append(header.second); 33 | output->append("\r\n"); 34 | } 35 | 36 | output->append("\r\n"); 37 | output->append(body_); 38 | } 39 | -------------------------------------------------------------------------------- /example/http_server/http/HttpResponse.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace muduo { 6 | class Buffer; 7 | } 8 | 9 | namespace http 10 | { 11 | 12 | class HttpResponse 13 | { 14 | public: 15 | enum HttpStatusCode 16 | { 17 | kUnknown, 18 | k200Ok = 200, 19 | k301MovedPermanently = 301, 20 | k400BadRequest = 400, 21 | k404NotFound = 404, 22 | }; 23 | 24 | explicit HttpResponse(bool close) 25 | : statusCode_(kUnknown), 26 | closeConnection_(close) 27 | { 28 | } 29 | 30 | void setStatusCode(HttpStatusCode code) 31 | { statusCode_ = code; } 32 | 33 | void setStatusMessage(const std::string& message) 34 | { statusMessage_ = message; } 35 | 36 | void setCloseConnection(bool on) 37 | { closeConnection_ = on; } 38 | 39 | bool closeConnection() const 40 | { return closeConnection_; } 41 | 42 | void setContentType(const std::string& contentType) 43 | { addHeader("Content-Type", contentType); } 44 | 45 | // FIXME: replace std::string with std::stringPiece 46 | void addHeader(const std::string& key, const std::string& value) 47 | { headers_[key] = value; } 48 | 49 | void setBody(const std::string& body) 50 | { body_ = body; } 51 | 52 | void appendToBuffer(muduo::Buffer* output) const; 53 | 54 | private: 55 | std::map headers_; 56 | HttpStatusCode statusCode_; 57 | // FIXME: add http version 58 | std::string statusMessage_; 59 | bool closeConnection_; 60 | std::string body_; 61 | }; 62 | 63 | } // namespace http 64 | 65 | -------------------------------------------------------------------------------- /example/http_server/http/HttpServer.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | // 9 | 10 | #include "HttpServer.hpp" 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | using namespace muduo; 18 | using namespace http; 19 | 20 | namespace muduo 21 | { 22 | namespace net 23 | { 24 | namespace detail 25 | { 26 | 27 | void defaultHttpCallback(const HttpRequest&, HttpResponse* resp) 28 | { 29 | resp->setStatusCode(HttpResponse::k404NotFound); 30 | resp->setStatusMessage("Not Found"); 31 | resp->setCloseConnection(true); 32 | } 33 | 34 | } // namespace detail 35 | } // namespace net 36 | } // namespace muduo 37 | 38 | HttpServer::HttpServer(EventLoop* loop, 39 | const InetAddress& listenAddr, 40 | const string& name, 41 | TcpServer::Option option) 42 | : server_(loop, listenAddr, name, option), 43 | httpCallback_(detail::defaultHttpCallback) 44 | { 45 | server_.setConnectionCallback( 46 | std::bind(&HttpServer::onConnection, this, _1)); 47 | server_.setMessageCallback( 48 | std::bind(&HttpServer::onMessage, this, _1, _2, _3)); 49 | } 50 | 51 | void HttpServer::start() 52 | { 53 | LOG_WARN << "HttpServer[" << server_.name() 54 | << "] starts listenning on " << server_.ipPort(); 55 | server_.start(); 56 | } 57 | 58 | void HttpServer::onConnection(const TcpConnectionPtr& conn) 59 | { 60 | if (conn->connected()) 61 | { 62 | conn->setContext(HttpContext()); 63 | } 64 | } 65 | 66 | void HttpServer::onMessage(const TcpConnectionPtr& conn, 67 | Buffer* buf, 68 | Timestamp receiveTime) 69 | { 70 | HttpContext* context = boost::any_cast(conn->getMutableContext()); 71 | 72 | if (!context->parseRequest(buf, receiveTime)) 73 | { 74 | conn->send("HTTP/1.1 400 Bad Request\r\n\r\n"); 75 | conn->shutdown(); 76 | } 77 | 78 | if (context->gotAll()) 79 | { 80 | onRequest(conn, context->request()); 81 | context->reset(); 82 | } 83 | } 84 | 85 | void HttpServer::onRequest(const TcpConnectionPtr& conn, const HttpRequest& req) 86 | { 87 | const string& connection = req.getHeader("Connection"); 88 | bool close = connection == "close" || 89 | (req.getVersion() == HttpRequest::kHttp10 && connection != "Keep-Alive"); 90 | HttpResponse response(close); 91 | httpCallback_(req, &response); 92 | Buffer buf; 93 | response.appendToBuffer(&buf); 94 | conn->send(&buf); 95 | if (response.closeConnection()) 96 | { 97 | conn->shutdown(); 98 | } 99 | } 100 | 101 | -------------------------------------------------------------------------------- /example/http_server/http/HttpServer.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace muduo 6 | { 7 | 8 | class HttpRequest; 9 | class HttpResponse; 10 | 11 | /// A simple embeddable HTTP server designed for report status of a program. 12 | /// It is not a fully HTTP 1.1 compliant server, but provides minimum features 13 | /// that can communicate with HttpClient and Web browser. 14 | /// It is synchronous, just like Java Servlet. 15 | class HttpServer : noncopyable 16 | { 17 | public: 18 | typedef std::function HttpCallback; 20 | 21 | HttpServer(EventLoop* loop, 22 | const InetAddress& listenAddr, 23 | const string& name, 24 | TcpServer::Option option = TcpServer::kNoReusePort); 25 | 26 | EventLoop* getLoop() const { return server_.getLoop(); } 27 | 28 | /// Not thread safe, callback be registered before calling start(). 29 | void setHttpCallback(const HttpCallback& cb) 30 | { 31 | httpCallback_ = cb; 32 | } 33 | 34 | void setThreadNum(int numThreads) 35 | { 36 | server_.setThreadNum(numThreads); 37 | } 38 | 39 | void start(); 40 | 41 | private: 42 | void onConnection(const TcpConnectionPtr& conn); 43 | void onMessage(const TcpConnectionPtr& conn, 44 | Buffer* buf, 45 | Timestamp receiveTime); 46 | void onRequest(const TcpConnectionPtr&, const HttpRequest&); 47 | 48 | TcpServer server_; 49 | HttpCallback httpCallback_; 50 | }; 51 | 52 | } // namespace http 53 | -------------------------------------------------------------------------------- /example/http_server/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | void on_connection(const muduo::TcpConnectionPtr& conn){ 8 | LOG_DEBUG << "new conn from " << conn->peerAddress().toIpPort(); 9 | } 10 | 11 | void onRequest(const muduo::TcpConnectionPtr& conn, const http::HttpRequest& req) 12 | { 13 | const std::string& connection = req.getHeader("Connection"); 14 | bool close = connection == "close" || connection == "Close" || 15 | (req.getVersion() == http::HttpRequest::kHttp10 && connection != "Keep-Alive"); 16 | http::HttpResponse response(close); 17 | response.setStatusCode(http::HttpResponse::k200Ok); 18 | response.setBody("welcome!\n"); 19 | muduo::Buffer buf; 20 | response.appendToBuffer(&buf); 21 | LOG_DEBUG << "http buffer :\n" << buf.peek(); 22 | conn->send(&buf); 23 | if (response.closeConnection()) 24 | { 25 | conn->shutdown(); 26 | } 27 | } 28 | 29 | void on_message(const muduo::TcpConnectionPtr& conn, muduo::Buffer* buffer, ssize_t len){ 30 | LOG_DEBUG << "on message : " << len << " bytes " << buffer->peek(); 31 | 32 | LOG_TRACE << "readAbleBytes:" << buffer->readableBytes() << " len:" << len; 33 | 34 | http::HttpContext context; 35 | 36 | if (!context.parseRequest(buffer, TimeStamp::now())) 37 | { 38 | conn->send("HTTP/1.1 400 Bad Request\r\n\r\n"); 39 | conn->shutdown(); 40 | } 41 | 42 | if (context.gotAll()) 43 | { 44 | LOG_TRACE << "request version: " << context.request().getVersion(); 45 | LOG_TRACE << "request method : " << context.request().methodString(); 46 | LOG_TRACE << "request path : " << context.request().path(); 47 | onRequest(conn, context.request()); 48 | context.reset(); 49 | } 50 | 51 | LOG_TRACE << "readAbleBytes:" << buffer->readableBytes() << " len:" << len; 52 | } 53 | 54 | int main(){ 55 | Logger::setLogLevel(Logger::TRACE); 56 | 57 | muduo::EventLoop loop; 58 | 59 | InetAddress localAddr(8080); 60 | muduo::TcpServer tcp_server(&loop, localAddr); 61 | 62 | tcp_server.setConnectionCallBack(std::bind(on_connection, std::placeholders::_1)); 63 | tcp_server.setMessageCallBack(std::bind(on_message, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); 64 | tcp_server.start(); 65 | 66 | loop.loop(); 67 | 68 | } 69 | -------------------------------------------------------------------------------- /example/muduo_server/example_server.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void on_connection(const muduo::TcpConnectionPtr& conn){ 5 | LOG_DEBUG << "new conn from " << conn->peerAddress().toIpPort(); 6 | } 7 | 8 | void on_message(const muduo::TcpConnectionPtr& conn, muduo::Buffer* buffer, ssize_t len){ 9 | LOG_DEBUG << "on message : " << len << " bytes " << buffer->peek(); 10 | buffer->retrieve(len); 11 | } 12 | 13 | int main(){ 14 | 15 | Logger::setLogLevel(Logger::DEBUG); 16 | 17 | muduo::EventLoop loop; 18 | 19 | InetAddress localAddr(8080); 20 | muduo::TcpServer tcp_server(&loop, localAddr); 21 | 22 | tcp_server.setConnectionCallBack(std::bind(on_connection, std::placeholders::_1)); 23 | tcp_server.setMessageCallBack(std::bind(on_message, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); 24 | //tcp_server.setCloseCallBack(std::bind(on_close, std::placeholders::_1)); 25 | tcp_server.start(); 26 | 27 | loop.loop(); 28 | 29 | } -------------------------------------------------------------------------------- /includes/async_logging: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | -------------------------------------------------------------------------------- /includes/muduo_logger/AsyncLogging.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _ASYNC_LOGGING_HH 2 | #define _ASYNC_LOGGING_HH 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "Thread.hpp" 9 | #include "LogStream.hpp" 10 | #include "ptr_vector.hpp" 11 | #include "Condition.hpp" 12 | 13 | class AsyncLogging 14 | { 15 | public: 16 | AsyncLogging(const std::string filePath, off_t rollSize, double flushInterval = 3.0); 17 | ~AsyncLogging(); 18 | 19 | void start(){ 20 | m_isRunning = true; 21 | m_thread.start(); 22 | } 23 | 24 | void stop(){ 25 | m_isRunning = false; 26 | m_cond.notify(); 27 | m_thread.join(); 28 | } 29 | 30 | void append(const char *logline, std::size_t len); 31 | 32 | private: 33 | AsyncLogging(const AsyncLogging&); 34 | AsyncLogging& operator=(const AsyncLogging&); 35 | 36 | void threadRoutine(); 37 | 38 | typedef LogBuffer Buffer; 39 | typedef myself::ptr_vector BufferVector; 40 | typedef std::unique_ptr BufferPtr; 41 | 42 | std::string m_filePath; 43 | off_t m_rollSize; 44 | const double m_flushInterval; 45 | bool m_isRunning; 46 | Thread m_thread; 47 | std::mutex m_mutex; 48 | Condition m_cond; 49 | 50 | BufferPtr m_currentBuffer; 51 | BufferPtr m_nextBuffer; 52 | BufferVector m_buffers; 53 | }; 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /includes/muduo_logger/Condition.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _CONDITION_HH 2 | #define _CONDITION_HH 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | class Condition{ 9 | public: 10 | explicit Condition(){}; 11 | ~Condition(){}; 12 | void wait(std::unique_lock& lock) { m_cond.wait(lock); } 13 | void waitForSeconds(std::unique_lock& lock, double seconds) 14 | { 15 | const int64_t kNanoSecondsPerSecond = 1000000000; 16 | int64_t nanoseconds = static_cast(seconds * kNanoSecondsPerSecond); 17 | 18 | m_cond.wait_for(lock, std::chrono::nanoseconds(nanoseconds)); 19 | } 20 | void notify() { m_cond.notify_one(); } 21 | void notifyAll() { m_cond.notify_all(); }; 22 | private: 23 | Condition(const Condition&); 24 | const Condition& operator=(const Condition&); 25 | 26 | std::condition_variable m_cond; 27 | }; 28 | 29 | #endif 30 | 31 | -------------------------------------------------------------------------------- /includes/muduo_logger/FileUtil.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _FILE_UTIL_HH 2 | #define _FILE_UTIL_HH 3 | #include 4 | 5 | // For passing C-style string argument to a function. 6 | class StringArg 7 | { 8 | public: 9 | StringArg(const char *str):m_str(str){ 10 | } 11 | 12 | StringArg(const std::string& str):m_str(str.c_str()){ 13 | } 14 | 15 | const char* c_str() const{ return m_str;} 16 | 17 | private: 18 | const char* m_str; 19 | }; 20 | 21 | namespace FileUtil{ 22 | 23 | class AppendFile{ 24 | public: 25 | explicit AppendFile(StringArg filePath); 26 | 27 | ~AppendFile(); 28 | 29 | void append(const char* logline, const size_t len); 30 | 31 | size_t write(const char* logline, const size_t len); 32 | 33 | void flush(); 34 | 35 | off_t writtenBytes() const{ 36 | return m_writtenBytes; 37 | } 38 | 39 | private: 40 | 41 | static const size_t kFileBufferSize = 4096; 42 | size_t write(const char *logline, int len); 43 | 44 | FILE* m_fp; 45 | off_t m_writtenBytes; 46 | char m_buffer[kFileBufferSize]; 47 | }; 48 | 49 | } 50 | #endif -------------------------------------------------------------------------------- /includes/muduo_logger/LogFile.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _LOG_FILE_HH 2 | #define _LOG_FILE_HH 3 | #include 4 | #include 5 | #include "scoped_ptr.hpp" 6 | 7 | namespace FileUtil{ 8 | class AppendFile; 9 | } 10 | 11 | class LogFile 12 | { 13 | public: 14 | LogFile(const std::string& filePath, off_t rollSize = 2048*1000, bool threadSafe = true, int flushInterval = 0); 15 | ~LogFile(); 16 | 17 | void append(const char* logline, int len); 18 | void flush(); 19 | 20 | std::string getlogFileName(const std::string& baseName); 21 | 22 | private: 23 | void append_unlocked(const char* logline, int len); 24 | 25 | //static std::string getlogFileName(const std::string& filePath); 26 | bool rollFile(); 27 | 28 | const std::string m_filePath; 29 | const int m_flushInterval; 30 | 31 | int m_rollCnt; 32 | off_t m_roolSize; 33 | scoped_ptr m_mutex; 34 | scoped_ptr m_file; 35 | }; 36 | 37 | #endif -------------------------------------------------------------------------------- /includes/muduo_logger/LogStream.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _LOG_STREAM_HH 2 | #define _LOG_STREAM_HH 3 | #include 4 | #include 5 | #include 6 | 7 | const int kSmallBuffer = 4096; 8 | const int kLargeBuffer = 4096*1000; 9 | 10 | template 11 | class LogBuffer 12 | { 13 | public: 14 | LogBuffer(): m_cur(m_data){ 15 | } 16 | 17 | ~LogBuffer(){ 18 | //printf("%s", m_data); 19 | } 20 | 21 | void append(const char* /*restrict*/ buf, std::size_t len){ 22 | // append partially 23 | if (/*implicit_cast*/(avail()) > len) 24 | { 25 | memcpy(m_cur, buf, len); 26 | m_cur += len; 27 | } 28 | } 29 | 30 | // write in m_data directly 31 | char* current() { return m_cur; }; 32 | std::size_t avail() const { return static_cast (end() - m_cur); } 33 | void add(std::size_t len) { m_cur += len; } 34 | std::size_t length() const {return m_cur - m_data;} 35 | void bzero() { ::bzero(m_data, sizeof(m_data)); } 36 | void reset() {m_cur = m_data;} 37 | 38 | const char* data() const { return m_data; } 39 | 40 | private: 41 | const char* end() const { return m_data + sizeof(m_data); } 42 | 43 | char m_data[SIZE]; 44 | char* m_cur; 45 | }; 46 | 47 | class LogStream{ 48 | public: 49 | LogStream(); 50 | ~LogStream(); 51 | 52 | typedef LogBuffer Buffer; 53 | typedef LogStream self; 54 | self& operator<<(bool v); 55 | 56 | self& operator<<(short); 57 | self& operator<<(unsigned short); 58 | self& operator<<(int); 59 | self& operator<<(unsigned int); 60 | self& operator<<(long); 61 | self& operator<<(unsigned long); 62 | self& operator<<(long long); 63 | self& operator<<(unsigned long long); 64 | 65 | self& operator<<(const void*); 66 | 67 | self& operator<<(float v); 68 | self& operator<<(double); 69 | 70 | self& operator<<(char v); 71 | self& operator<<(const char *); 72 | 73 | self& operator<<(const std::string& s); 74 | 75 | void append(const char* data, int len) { return m_buffer.append(data, len); } 76 | const Buffer& buffer() const { return m_buffer; } 77 | 78 | private: 79 | LogStream(const LogStream& ls); //no copyable 80 | LogStream& operator=(const LogStream& ls); 81 | 82 | template 83 | void formatInteger(T v); 84 | 85 | Buffer m_buffer; 86 | static const std::size_t kMaxNumericSize = 32; 87 | 88 | }; 89 | 90 | class Fmt{ 91 | public: 92 | template 93 | Fmt(const char* fmt, T val); 94 | 95 | const char* data() const { return m_buf; } 96 | int length() const { return m_length; } 97 | 98 | private: 99 | char m_buf[32]; 100 | int m_length; 101 | }; 102 | 103 | inline LogStream& operator<<(LogStream &s, const Fmt& fmt){ 104 | s.append(fmt.data(), fmt.length()); 105 | return s; 106 | } 107 | 108 | #endif -------------------------------------------------------------------------------- /includes/muduo_logger/Logger.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _LOGGER_HH 2 | #define _LOGGER_HH 3 | 4 | #include 5 | #include "LogStream.hpp" 6 | #include "TimeStamp.hpp" 7 | 8 | // CAUTION: do not write: 9 | // 10 | // if (good) 11 | // LOG_INFO << "Good news"; 12 | // else 13 | // LOG_WARN << "Bad news"; 14 | // 15 | // this expends to 16 | // 17 | // if (good) 18 | // if (logging_INFO) 19 | // logInfoStream << "Good news"; 20 | // else 21 | // logWarnStream << "Bad news"; 22 | // 23 | 24 | #define LOG_TRACE if (Logger::logLevel() <= Logger::TRACE) \ 25 | Logger(__FILE__, __LINE__, Logger::TRACE, __func__).stream() 26 | #define LOG_DEBUG if (Logger::logLevel() <= Logger::DEBUG) \ 27 | Logger(__FILE__, __LINE__, Logger::DEBUG, __func__).stream() 28 | #define LOG_INFO if (Logger::logLevel() <= Logger::INFO) \ 29 | Logger(__FILE__, __LINE__).stream() 30 | #define LOG_WARN if (Logger::logLevel() <= Logger::WARN) \ 31 | Logger(__FILE__, __LINE__, Logger::WARN).stream() 32 | #define LOG_ERROR if (Logger::logLevel() <= Logger::ERROR) \ 33 | Logger(__FILE__, __LINE__, Logger::ERROR).stream() 34 | #define LOG_FATAL if (Logger::logLevel() <= Logger::FATAL) \ 35 | Logger(__FILE__, __LINE__, Logger::FATAL).stream() 36 | #define LOG_SYSERR if (Logger::logLevel() <= Logger::ERROR) \ 37 | Logger(__FILE__, __LINE__, false).stream() 38 | #define LOG_SYSFATAL if (Logger::logLevel() <= Logger::FATAL) \ 39 | Logger(__FILE__, __LINE__, true).stream() 40 | 41 | class Logger 42 | { 43 | public: 44 | enum LogLevel 45 | { 46 | TRACE, 47 | DEBUG, 48 | INFO, 49 | WARN, 50 | ERROR, 51 | FATAL, 52 | NUM_LOG_LEVELS, 53 | }; 54 | 55 | //compile time calculation of basename of source file 56 | class SourceFile 57 | { 58 | public: 59 | template 60 | inline SourceFile(const char (&arr)[N]) 61 | :m_data(arr), 62 | m_size(N-1){ 63 | const char* slash = strrchr(m_data, '/'); // builtin function 64 | if (slash){ 65 | m_data = slash + 1; 66 | m_size -= static_cast(m_data - arr); 67 | } 68 | } 69 | 70 | explicit SourceFile(const char* filename) 71 | : m_data(filename){ 72 | const char* slash = strrchr(filename, '/'); 73 | if (slash){ 74 | m_data = slash + 1; 75 | } 76 | m_size = static_cast(strlen(m_data)); 77 | } 78 | 79 | const char* m_data; 80 | int m_size; 81 | }; 82 | 83 | Logger(SourceFile file, int line); 84 | Logger(SourceFile file, int line, LogLevel level); 85 | Logger(SourceFile file, int line, LogLevel level, const char* func); 86 | Logger(SourceFile file, int line, bool toAbort); 87 | ~Logger(); 88 | 89 | static void setLogLevel(LogLevel level); 90 | static LogLevel logLevel(); 91 | 92 | LogStream& stream() { return m_impl.m_stream; } 93 | 94 | typedef void (*outputFunc)(const char *msg, int len); 95 | typedef void (*flushFunc)(); 96 | 97 | static void setOutput(outputFunc); 98 | static void setFlush(flushFunc); 99 | 100 | private: 101 | Logger(const Logger &lg); //no copyable 102 | Logger& operator=(const Logger &lg); 103 | 104 | class Impl 105 | { 106 | public: 107 | typedef Logger::LogLevel LogLevel; 108 | Impl(LogLevel level, int old_errno, const SourceFile& file, int line); 109 | void formatTime(); 110 | void finish(); 111 | 112 | TimeStamp m_time; 113 | LogStream m_stream; 114 | LogLevel m_level; 115 | int m_line; 116 | SourceFile m_fileBaseName; 117 | }; 118 | 119 | Impl m_impl; 120 | 121 | }; 122 | 123 | const char* strerror_tl(int savedErrno); 124 | 125 | #endif -------------------------------------------------------------------------------- /includes/muduo_logger/Thread.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _THREAD_HH 2 | #define _THREAD_HH 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | class Thread{ 10 | public: 11 | typedef std::function ThreadFunc; 12 | 13 | explicit Thread(const ThreadFunc& threadRoutine); 14 | ~Thread(); 15 | 16 | void start(); 17 | void join(); 18 | void detach(); 19 | 20 | bool isStarted() { return m_isStarted; } 21 | bool isJoined() { return m_isJoined; } 22 | 23 | std::thread::id getThreadId() const{ assert(m_isStarted); return p_thread->get_id(); } 24 | 25 | private: 26 | Thread(const Thread&); 27 | const Thread& operator=(const Thread&); 28 | 29 | bool m_isStarted; 30 | bool m_isJoined; 31 | ThreadFunc m_threadRoutine; 32 | std::unique_ptr p_thread; 33 | }; 34 | 35 | 36 | #endif -------------------------------------------------------------------------------- /includes/muduo_logger/TimeStamp.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _TIME_STAMP_HH 2 | #define _TIME_STAMP_HH 3 | 4 | #include 5 | #include 6 | 7 | class TimeStamp { 8 | public: 9 | // 10 | // Constucts an invalid TimeStamp. 11 | // 12 | TimeStamp() 13 | : m_microSecondsSinceEpoch(0){ 14 | } 15 | 16 | // 17 | // Constucts a TimeStamp at specific time 18 | // 19 | // @param microSecondsSinceEpoch 20 | explicit TimeStamp(int64_t microSecondsSinceEpochArg) 21 | : m_microSecondsSinceEpoch(microSecondsSinceEpochArg){ 22 | } 23 | 24 | int64_t microSecondsSinceEpoch() const { return m_microSecondsSinceEpoch; } 25 | 26 | // 27 | // Get time of now. 28 | // 29 | std::string toString() const; 30 | 31 | bool valid() const { return m_microSecondsSinceEpoch > 0; } 32 | 33 | static TimeStamp now(); 34 | static TimeStamp invalid() { return TimeStamp(); } 35 | static TimeStamp addTime(TimeStamp timestamp, double seconds) 36 | { 37 | int64_t delta = static_cast(seconds * TimeStamp::kMicroSecondsPerSecond); 38 | return TimeStamp(timestamp.microSecondsSinceEpoch() + delta); 39 | } 40 | 41 | void swap(TimeStamp& other) 42 | { 43 | std::swap(m_microSecondsSinceEpoch, other.m_microSecondsSinceEpoch); 44 | } 45 | 46 | static const int kMicroSecondsPerSecond = 1000 * 1000; 47 | 48 | private: 49 | int64_t m_microSecondsSinceEpoch; 50 | }; 51 | 52 | inline bool operator<(TimeStamp lhs, TimeStamp rhs) 53 | { 54 | return lhs.microSecondsSinceEpoch() < rhs.microSecondsSinceEpoch(); 55 | } 56 | 57 | inline bool operator==(TimeStamp lhs, TimeStamp rhs) 58 | { 59 | return lhs.microSecondsSinceEpoch() == rhs.microSecondsSinceEpoch(); 60 | } 61 | 62 | #endif -------------------------------------------------------------------------------- /includes/muduo_logger/ptr_vector.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _PTR_VECTOR_HH 2 | #define _PTR_VECTOR_HH 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace myself{ 9 | 10 | #define ASSERT(If, Msg) \ 11 | if(!(If)) \ 12 | {\ 13 | fprintf(stderr, "Error/(%s, %d): %s, abort.\n", __FILE__, __LINE__, Msg); abort();\ 14 | } 15 | 16 | template 17 | class ptr_vector{ 18 | public: 19 | typedef unsigned int size_type; 20 | typedef std::vector vector; 21 | typedef T* value_type; 22 | typedef value_type& reference; 23 | 24 | explicit ptr_vector(){ 25 | } 26 | 27 | ~ptr_vector(){ 28 | clear(); 29 | } 30 | 31 | void clear(){ 32 | if(!m_vector.empty()) 33 | { 34 | //typename vector::iterator it; 35 | for(auto it = m_vector.begin(); it != m_vector.end(); ++it) 36 | { 37 | delete *it;//释放指针指向的内存. 38 | } 39 | } 40 | 41 | m_vector.clear();//释放指针本身. 42 | } 43 | 44 | void push_back(T* const &v){ 45 | ASSERT(v , "NULL point at ptr_vector push_back()"); 46 | std::unique_ptr tmp(v); 47 | m_vector.push_back(v); //使用 unique_ptr 保证push_back失败时,v也能正常释放. 48 | tmp.release(); 49 | } 50 | 51 | std::unique_ptr pop_back(){ 52 | ASSERT( !m_vector.empty(), "'pop_back()' on empty container"); 53 | std::unique_ptr tmp(m_vector.back()); 54 | m_vector.pop_back(); 55 | return std::move(tmp); 56 | } 57 | 58 | reference operator[](size_type n){ 59 | ASSERT(n < size(), "operator[] n out of the border") 60 | return m_vector[n]; 61 | } 62 | 63 | bool empty(){ 64 | return m_vector.empty(); 65 | } 66 | 67 | size_type size(){ 68 | return m_vector.size(); 69 | } 70 | 71 | void reserve(size_type n){ 72 | m_vector.reserve(n); 73 | } 74 | 75 | void resize(size_type s){ 76 | size_type size = this->size(); 77 | if(s < size) 78 | { 79 | for(auto it = m_vector.begin() + s; it != m_vector.end(); ++it) 80 | { 81 | delete *it;//释放指针指向的内存. 82 | } 83 | m_vector.resize(s); 84 | } 85 | else if(s > size) 86 | { 87 | for(; size != s; ++size) 88 | { 89 | push_back(new T); 90 | } 91 | } 92 | ASSERT(s == this->size(), "'resize' error size asymmetry"); 93 | } 94 | 95 | void swap(ptr_vector& v){ 96 | m_vector.swap(v.base()); 97 | } 98 | 99 | private: 100 | ptr_vector& operator=(const ptr_vector&); 101 | ptr_vector(ptr_vector&); 102 | 103 | vector& base(){ 104 | return m_vector; 105 | } 106 | 107 | vector m_vector; 108 | }; 109 | 110 | } 111 | 112 | #endif -------------------------------------------------------------------------------- /includes/muduo_logger/scoped_ptr.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _SCOPE_PTR_HH 2 | #define _SCOPE_PTR_HH 3 | // scoped_ptr mimics a built-in pointer except that it guarantees deletion 4 | // of the object pointed to, either on destruction of the scoped_ptr or via 5 | // an explicit reset(). scoped_ptr is a simple solution for simple needs; 6 | // use shared_ptr or std::auto_ptr if your needs are more complex. 7 | 8 | /* 9 | scoped_ptr 是局部智能指针 不允许转让所有权。 10 | */ 11 | template 12 | class scoped_ptr 13 | { 14 | public: 15 | scoped_ptr(T *p = 0) :m_ptr(p) { 16 | } 17 | 18 | ~scoped_ptr(){ 19 | delete m_ptr; 20 | } 21 | 22 | T&operator*() const { 23 | return *m_ptr; 24 | } 25 | 26 | T*operator->() const { 27 | return m_ptr; 28 | } 29 | 30 | void reset(T *p)//拥有权不允许转让 但是可以让智能指针指向另一个空间 31 | { 32 | if (p != m_ptr && m_ptr != 0) 33 | delete m_ptr; 34 | m_ptr = p; 35 | } 36 | 37 | T* get() const { 38 | return m_ptr; 39 | } 40 | 41 | operator bool() const { return get() != NULL; } 42 | 43 | private://将拷贝构造和赋值 以及判等判不等 都设置为私有方法 44 | //对象不再能调用,即不能拷贝构造和赋值 也就达到了不让转移拥有权的目的 45 | scoped_ptr(const scoped_ptr &y); 46 | const scoped_ptr operator=(const scoped_ptr &); 47 | void operator==(scoped_ptr const &) const; 48 | void operator!=(scoped_ptr const &) const; 49 | 50 | T* m_ptr; 51 | }; 52 | 53 | #endif -------------------------------------------------------------------------------- /includes/muduo_network/Acceptor.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _NET_ACCEPTOR_HH 2 | #define _NET_ACCEPTOR_HH 3 | #include 4 | 5 | #include "Channel.hpp" 6 | #include "Socket.hpp" 7 | 8 | class EventLoop; 9 | class InetAddress; 10 | 11 | namespace muduo{ 12 | 13 | class Acceptor{ 14 | public: 15 | typedef std::function NewConnectionCallBack; 16 | 17 | Acceptor(EventLoop* loop, const InetAddress& listenAddr, bool reuseport = true); 18 | ~Acceptor(); 19 | 20 | void listen(); 21 | bool listenning() const { return m_listenning; } // get listen status. 22 | 23 | void setNewConnectionCallBack(const NewConnectionCallBack& cb) { m_newConnectionCallBack = cb; } 24 | 25 | private: 26 | Acceptor& operator=(const Acceptor&); 27 | Acceptor(const Acceptor&); 28 | 29 | void handleRead(); 30 | 31 | EventLoop* p_loop; 32 | Socket m_acceptSocket; 33 | Channel m_acceptChannel; 34 | NewConnectionCallBack m_newConnectionCallBack; 35 | bool m_listenning; 36 | int m_idleFd; 37 | }; 38 | 39 | } 40 | 41 | #endif -------------------------------------------------------------------------------- /includes/muduo_network/Atomic.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _ATOMIC_HH 2 | #define _ATOMIC_HH 3 | 4 | #include 5 | 6 | template 7 | class AtomicIntegerT 8 | { 9 | public: 10 | AtomicIntegerT() 11 | :m_value(0) 12 | { 13 | 14 | } 15 | 16 | T get() 17 | { 18 | return __sync_val_compare_and_swap(&m_value, 0, 0); 19 | } 20 | 21 | T incrementAndGet() 22 | { 23 | return addAndGet(1); 24 | } 25 | 26 | T decrementAndGet() 27 | { 28 | return addAndGet(-1); 29 | } 30 | 31 | private: 32 | AtomicIntegerT& operator=(const AtomicIntegerT&); 33 | AtomicIntegerT(const AtomicIntegerT&); 34 | 35 | T getAndAdd(T x) 36 | { 37 | return __sync_fetch_and_add(&m_value, x); 38 | } 39 | 40 | T addAndGet(T x) 41 | { 42 | return getAndAdd(x) + x; 43 | } 44 | 45 | volatile T m_value; 46 | 47 | }; 48 | 49 | typedef AtomicIntegerT AtomicInt32; 50 | typedef AtomicIntegerT AtomicInt64; 51 | 52 | #endif -------------------------------------------------------------------------------- /includes/muduo_network/Buffer.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _NET_BUFFER_H 2 | #define _NET_BUFFER_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | namespace muduo { 12 | 13 | //#include // ssize_t 14 | 15 | /// A buffer class modeled after org.jboss.netty.buffer.ChannelBuffer 16 | /// 17 | /// @code 18 | /// +-------------------+------------------+------------------+ 19 | /// | prependable bytes | readable bytes | writable bytes | 20 | /// | | (CONTENT) | | 21 | /// +-------------------+------------------+------------------+ 22 | /// | | | | 23 | /// 0 <= readerIndex <= writerIndex <= size 24 | /// @endcode 25 | class Buffer 26 | { 27 | public: 28 | static const size_t kCheapPrepend = 8; 29 | static const size_t kInitialSize = 4096; 30 | 31 | explicit Buffer(size_t initialSize = kInitialSize) 32 | : m_buffer(kCheapPrepend + initialSize), 33 | m_readerIndex(kCheapPrepend), 34 | m_writerIndex(kCheapPrepend) 35 | { 36 | assert(readableBytes() == 0); 37 | assert(writableBytes() == initialSize); 38 | assert(prependableBytes() == kCheapPrepend); 39 | } 40 | 41 | size_t readableBytes() const 42 | { return m_writerIndex - m_readerIndex; } 43 | 44 | size_t writableBytes() const 45 | { return m_buffer.size() - m_writerIndex; } 46 | 47 | size_t prependableBytes() const //前面预留出来的字节数,(s-(s-rI)); 48 | { return m_readerIndex; } 49 | 50 | const char* peek() const 51 | { return begin() + m_readerIndex; } 52 | 53 | const char* beginWrite() const 54 | { return begin() + m_writerIndex; } 55 | 56 | char* beginWrite() 57 | { return begin() + m_writerIndex; } 58 | 59 | void hasWritten(size_t len) 60 | { 61 | assert(len <= writableBytes()); 62 | m_writerIndex += len; 63 | } 64 | 65 | const char* findCRLF() const 66 | { 67 | // FIXME: replace with memmem()? 68 | const char* crlf = std::search(peek(), beginWrite(), kCRLF, kCRLF+2); 69 | return crlf == beginWrite() ? NULL : crlf; 70 | } 71 | 72 | void unwrite(size_t len) 73 | { 74 | assert(len <= readableBytes()); 75 | m_writerIndex -= len; 76 | } 77 | 78 | // retrieve returns void, to prevent 79 | // string str(retrieve(readableBytes()), readableBytes()); 80 | // the evaluation of two functions are unspecified 81 | void retrieve(size_t len) 82 | { 83 | assert(len <= readableBytes()); 84 | if (len < readableBytes()) 85 | { 86 | m_readerIndex += len; 87 | } 88 | else 89 | { 90 | retrieveAll(); 91 | } 92 | } 93 | 94 | void retrieveUntil(const char* end) 95 | { 96 | assert(peek() <= end); 97 | assert(end <= beginWrite()); 98 | retrieve(end - peek()); 99 | } 100 | 101 | void retrieveAll() 102 | { 103 | m_readerIndex = kCheapPrepend; 104 | m_writerIndex = kCheapPrepend; 105 | } 106 | 107 | std::string retrieveAsString(size_t len) 108 | { 109 | assert(len <= readableBytes()); 110 | std::string result(peek(), len); 111 | retrieve(len); 112 | return result; 113 | } 114 | 115 | void makeSpace(int len) 116 | { 117 | if(writableBytes() + prependableBytes() < len + kCheapPrepend) 118 | { 119 | m_buffer.resize(m_writerIndex + len); 120 | } 121 | else 122 | { 123 | // move readable data to the front, make space inside buffer 124 | assert(kCheapPrepend < m_readerIndex); 125 | size_t readable = readableBytes(); 126 | std::copy(begin() + m_readerIndex, begin() + m_writerIndex, begin() + kCheapPrepend); 127 | m_readerIndex = kCheapPrepend; 128 | m_writerIndex = m_readerIndex + readable; 129 | assert(readable == readableBytes()); 130 | } 131 | } 132 | 133 | void append(const std::string& str) 134 | { 135 | append(str.c_str(), str.size()); 136 | } 137 | 138 | void append(const char* data/*restrict data*/, size_t len) 139 | { 140 | if (writableBytes() < len) 141 | { 142 | makeSpace(len); 143 | } 144 | assert(writableBytes() >= len); 145 | std::copy(data, data+len, beginWrite()); 146 | hasWritten(len); 147 | } 148 | 149 | ssize_t readFd(int fd, int* savedErrno); 150 | 151 | size_t internalCapacity() const 152 | { 153 | return m_buffer.capacity(); 154 | } 155 | 156 | private: 157 | char* begin() 158 | {return &*m_buffer.begin(); } 159 | 160 | const char* begin() const 161 | {return &*m_buffer.begin(); } 162 | 163 | private: 164 | static const char kCRLF[]; 165 | 166 | std::vector m_buffer; 167 | size_t m_readerIndex; 168 | size_t m_writerIndex; 169 | }; 170 | 171 | } 172 | 173 | #endif // _NET_BUFFER_H 174 | -------------------------------------------------------------------------------- /includes/muduo_network/CallBacks.hpp: -------------------------------------------------------------------------------- 1 | #ifndef NET_CALLBACKS_H 2 | #define NET_CALLBACKS_H 3 | 4 | #include 5 | #include 6 | 7 | #include "TimeStamp.hpp" 8 | 9 | namespace muduo { 10 | 11 | class Buffer; 12 | class TcpConnection; 13 | typedef std::shared_ptr TcpConnectionPtr; 14 | 15 | namespace NetCallBacks 16 | { 17 | 18 | // All client visible callbacks go here. 19 | 20 | typedef std::function TimerCallBack; 21 | typedef std::function ConnectionCallBack; 22 | typedef std::function MessageCallBack; 23 | typedef std::function CloseCallBack; 24 | 25 | void defaultConnectionCallback(); 26 | 27 | } 28 | 29 | }; 30 | 31 | #endif // NET_CALLBACKS_H 32 | -------------------------------------------------------------------------------- /includes/muduo_network/Channel.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _NET_CHANNEL_H 2 | #define _NET_CHANNEL_H 3 | 4 | #include 5 | 6 | namespace muduo { 7 | 8 | class EventLoop; 9 | 10 | /* 11 | *每个Channel对象自始至终只属于一个EventLoop, 12 | *因此每个Channel对象都只属于某一个IO线程。 每个Channel对象自始至 13 | *终只负责一个文件描述符(fd) 的IO事件分发, 但它并不拥有这个fd, 14 | *也不会在析构的时候关闭这个fd。 Channel会把不同的IO事件分发为不 15 | *同的回调, 例如ReadCallback、 WriteCallback等 16 | */ 17 | 18 | class Channel { 19 | public: 20 | typedef std::function EventCallBack; 21 | Channel(EventLoop* loop, int fd); 22 | ~Channel(); 23 | 24 | void handleEvent(); 25 | void setReadCallBack(const EventCallBack& cb) { m_readCallBack = cb; } 26 | void setWriteCallBack(const EventCallBack& cb) { m_writeCallBack = cb; } 27 | void setErrorCallBack(const EventCallBack& cb) { m_errorCallBack = cb; } 28 | void setCloseCallBack(const EventCallBack& cb) { m_closeCallBack = cb; } 29 | 30 | int fd() const { return m_fd; } 31 | uint32_t events() const { return m_events; } 32 | void set_revents(uint32_t revt) { m_revents = revt; } 33 | bool isNoneEvent() const { return m_events == kNoneEvent; } 34 | 35 | void enableReading() { m_events |= kReadEvent; update(); } 36 | void disableReading() { m_events &= ~kReadEvent; update(); } 37 | void enableWriting() { m_events |= kWriteEvent; update(); } 38 | bool isWriting() { return m_events &= kWriteEvent; } 39 | bool isReading() { return m_events &= kReadEvent; } 40 | void disableWriting() { m_events &= ~kWriteEvent; update(); } 41 | void disableAll() { m_events = kNoneEvent; update(); } 42 | 43 | int index() { return m_index; } 44 | void set_index(int idx) { m_index =idx; } 45 | 46 | // for debug 47 | std::string reventsToString() const; 48 | std::string eventsToString() const; 49 | 50 | EventLoop* ownerLoop() { return p_loop; } 51 | void remove(); 52 | 53 | private: 54 | Channel& operator=(const Channel&); 55 | Channel(const Channel&); 56 | 57 | void update(); 58 | 59 | //used for r/eventsToString() 60 | std::string eventsToString(int fd, int ev) const; 61 | 62 | static const uint32_t kNoneEvent; 63 | static const uint32_t kReadEvent; 64 | static const uint32_t kWriteEvent; 65 | 66 | EventLoop* p_loop; 67 | const int m_fd; 68 | uint32_t m_events; // 等待的事件 69 | uint32_t m_revents; // 实际发生了的事件 70 | int m_index; 71 | bool m_addedToLoop; 72 | 73 | EventCallBack m_readCallBack; 74 | EventCallBack m_writeCallBack; 75 | EventCallBack m_errorCallBack; 76 | EventCallBack m_closeCallBack; 77 | }; 78 | 79 | } 80 | 81 | #endif 82 | -------------------------------------------------------------------------------- /includes/muduo_network/CurrentThread.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _CURRENT_THREAD 2 | #define _CURRENT_THREAD 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace CurrentThread 11 | { 12 | // internal 13 | extern __thread int t_cachedTid; 14 | extern __thread char t_tidString[32]; 15 | extern __thread int t_tidStringLength; 16 | extern __thread const char* t_threadName; 17 | 18 | inline int tid() 19 | { 20 | if (__builtin_expect(t_cachedTid == 0, 0)) 21 | { 22 | if (t_cachedTid == 0) 23 | { 24 | t_cachedTid = static_cast(::syscall(SYS_gettid)); 25 | t_tidStringLength = snprintf(t_tidString, sizeof t_tidString, "%5d ", t_cachedTid); 26 | } 27 | } 28 | return t_cachedTid; 29 | } 30 | 31 | inline const char* tidString() // for logging 32 | { 33 | return t_tidString; 34 | } 35 | 36 | inline int tidStringLength() // for logging 37 | { 38 | return t_tidStringLength; 39 | } 40 | 41 | inline const char* name() 42 | { 43 | return t_threadName; 44 | } 45 | } 46 | 47 | #endif -------------------------------------------------------------------------------- /includes/muduo_network/Endian.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _NET_ENDIAN_HH 2 | #define _NET_ENDIAN_HH 3 | 4 | #include 5 | #include 6 | 7 | namespace sockets{ 8 | 9 | inline uint64_t hostToNetwork64(uint64_t host64) 10 | { 11 | return htobe64(host64); 12 | } 13 | 14 | inline uint32_t hostToNetwork32(uint32_t host32) 15 | { 16 | return htobe32(host32); 17 | } 18 | 19 | inline uint16_t hostToNetwork16(uint16_t host16) 20 | { 21 | return htobe16(host16); 22 | } 23 | 24 | inline uint64_t networkToHost64(uint64_t net64) 25 | { 26 | return be64toh(net64); 27 | } 28 | 29 | inline uint32_t networkToHost32(uint32_t net32) 30 | { 31 | return be32toh(net32); 32 | } 33 | 34 | inline uint16_t networkToHost16(uint16_t net16) 35 | { 36 | return be16toh(net16); 37 | } 38 | 39 | } 40 | #endif -------------------------------------------------------------------------------- /includes/muduo_network/Epoll.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _NET_EPOLL_HH 2 | #define _NET_EPOLL_HH 3 | 4 | #include 5 | #include 6 | 7 | #include "TimeStamp.hpp" 8 | #include "Poller.hpp" 9 | 10 | /* 11 | *#include 12 | *struct pollfd 13 | *{ 14 | *int fd; // 想查询的文件描述符. 15 | *short int events; // fd 上,我们感兴趣的事件 16 | *short int revents; /// 实际发生了的事件. 17 | *}; 18 | */ 19 | 20 | struct epoll_event; 21 | 22 | namespace muduo { 23 | 24 | class Channel; 25 | class EventLoop; 26 | 27 | class Epoll : public Poller { 28 | public: 29 | Epoll(EventLoop* loop); 30 | ~Epoll(); 31 | 32 | TimeStamp poll(int timeoutMs, ChannelList* activeChannels); 33 | 34 | void updateChannel(Channel* channel); 35 | void removeChannel(Channel* channel); 36 | 37 | private: 38 | const Epoll& operator=(const Epoll&); 39 | Epoll(const Epoll&); 40 | 41 | static const int kMaxEpollConcurrencySize; 42 | static const int kInitEpollEventsSize; 43 | 44 | void fillActiveChannels(int numEvents, ChannelList* activeChannels) const; 45 | 46 | typedef std::vector EpollFdList; 47 | 48 | int m_epfd; 49 | std::size_t m_maxEventsSize; 50 | EpollFdList m_epollEvents; 51 | }; 52 | 53 | } 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /includes/muduo_network/EventLoop.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _NET_EVENTLOOP_H 2 | #define _NET_EVENTLOOP_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "TimerId.hpp" 10 | #include "TimeStamp.hpp" 11 | #include "TimerQueue.hpp" 12 | #include "CallBacks.hpp" 13 | #include "CurrentThread.hpp" 14 | #include "Channel.hpp" 15 | 16 | namespace muduo { 17 | 18 | class Poller; 19 | 20 | class EventLoop 21 | { 22 | public: 23 | typedef std::function Functor; 24 | 25 | EventLoop(); 26 | ~EventLoop(); 27 | void loop(); 28 | void quit(); 29 | 30 | void assertInLoopThread(); 31 | bool isInloopThread() const; 32 | 33 | void updateChannel(Channel* channel); 34 | void removeChannel(Channel* channel); 35 | 36 | TimerId runAt(const TimeStamp& time, const NetCallBacks::TimerCallBack& cb); 37 | TimerId runAfter(double delay, const NetCallBacks::TimerCallBack& cb); 38 | TimerId runEvery(double interval, const NetCallBacks::TimerCallBack& cb); 39 | 40 | void runInLoop(const Functor& cb); 41 | void wakeup(); 42 | void queueInLoop(const Functor& cb); 43 | 44 | static EventLoop* getEventLoopOfCurrentThread(); 45 | 46 | private: 47 | EventLoop& operator=(const EventLoop&); 48 | EventLoop(const EventLoop&); 49 | 50 | void abortNotInLoopThread(); 51 | 52 | //used to waked up 53 | void handleRead(); 54 | void doPendingFunctors(); 55 | 56 | //used for loop to debug. 57 | void printActiveChannels() const; 58 | 59 | typedef std::vector ChannelList; 60 | 61 | bool m_looping; 62 | bool m_quit; 63 | const pid_t m_threadId; 64 | std::unique_ptr m_poller; 65 | std::unique_ptr m_timerQueue; 66 | ChannelList m_activeChannels; 67 | 68 | int m_wakeupFd;//... 放p_wakeupChannel 后面会出错,一定要按顺序来. 69 | std::unique_ptr p_wakeupChannel; 70 | mutable std::mutex m_mutex; 71 | bool m_callingPendingFunctors; /* atomic */ 72 | std::vector m_pendingFunctors; // @GuardedBy mutex_ 73 | 74 | }; 75 | 76 | } 77 | 78 | #endif -------------------------------------------------------------------------------- /includes/muduo_network/EventLoopThread.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _NET_EVENTLOOPTHREAD_HH 2 | #define _NET_EVENTLOOPTHREAD_HH 3 | 4 | #include 5 | #include 6 | 7 | #include "Condition.hpp" 8 | #include "Thread.hpp" 9 | 10 | namespace muduo { 11 | 12 | class EventLoop; 13 | 14 | class EventLoopThread{ 15 | public: 16 | typedef std::function ThreadInitCallBack; 17 | 18 | EventLoopThread(); 19 | ~EventLoopThread(); 20 | 21 | EventLoop* startLoop(); 22 | 23 | private: 24 | const EventLoopThread& operator=(const EventLoopThread&); 25 | EventLoopThread(const EventLoopThread&); 26 | 27 | void threadFunc(); 28 | 29 | EventLoop* p_loop; 30 | bool m_exiting; 31 | Thread m_thread; 32 | std::mutex m_mutex; 33 | Condition m_cond; 34 | ThreadInitCallBack m_threadInitCallBack; 35 | 36 | }; 37 | 38 | } 39 | 40 | #endif -------------------------------------------------------------------------------- /includes/muduo_network/EventLoopThreadPool.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _EVENTLOOPTHREADPOOL_H 2 | #define _EVENTLOOPTHREADPOOL_H 3 | 4 | #include 5 | #include 6 | #include "ptr_vector.hpp" 7 | 8 | namespace muduo 9 | { 10 | 11 | class EventLoop; 12 | class EventLoopThread; 13 | 14 | class EventLoopThreadPool 15 | { 16 | public: 17 | //typedef std::function ThreadInitCallback; 18 | 19 | EventLoopThreadPool(EventLoop* m_baseLoop, const std::string& nameArg, int numThreads = 3); 20 | ~EventLoopThreadPool(); 21 | void setThreadNum(int numThreads) { m_numThreads = numThreads; } 22 | void start(); 23 | 24 | // valid after calling start() 25 | /// round-robin 26 | EventLoop* getNextLoop(); 27 | 28 | /// with the same hash code, it will always return the same EventLoop 29 | EventLoop* getLoopForHash(size_t hashCode); 30 | 31 | std::vector getAllLoops(); 32 | 33 | bool started() const 34 | { return m_started; } 35 | 36 | const std::string& name() const 37 | { return m_name; } 38 | 39 | private: 40 | 41 | EventLoop* m_baseLoop; 42 | std::string m_name; 43 | bool m_started; 44 | int m_numThreads; 45 | int m_next; 46 | myself::ptr_vector m_threads; 47 | std::vector m_loops; 48 | }; 49 | 50 | } 51 | 52 | #endif // MUDUO_NET_EVENTLOOPTHREADPOOL_H 53 | -------------------------------------------------------------------------------- /includes/muduo_network/InetAddress.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _NET_ADDRESS_HH 2 | #define _NET_ADDRESS_HH 3 | 4 | #include 5 | #include 6 | 7 | class InetAddress 8 | { 9 | public: 10 | /// Constructs an endpoint with given port number. 11 | /// Mostly used in TcpServer listening. 12 | explicit InetAddress(uint16_t port = 0, bool loopbackOnly = false, bool ipv6 = false); 13 | 14 | /// Constructs an endpoint with given ip and port. 15 | /// @c ip should be "1.2.3.4" 16 | InetAddress(std::string ip, uint16_t port, bool ipv6 = false); 17 | 18 | /// Constructs an endpoint with given struct @c sockaddr_in 19 | /// Mostly used when accepting new connections 20 | explicit InetAddress(const struct sockaddr_in& addr) 21 | : m_addr(addr) 22 | { } 23 | 24 | explicit InetAddress(const struct sockaddr_in6& addr) 25 | : m_addr6(addr) 26 | { } 27 | 28 | sa_family_t family() const { return m_addr.sin_family; } 29 | 30 | const struct sockaddr* getSockAddr() const { return (struct sockaddr*)(&m_addr6); } 31 | void setSockAddrInet6(const struct sockaddr_in6& addr6) { m_addr6 = addr6; } 32 | 33 | std::string toIp() const; 34 | uint16_t toPort() const; 35 | std::string toIpPort() const; 36 | 37 | uint32_t ipNetEndian() const; 38 | 39 | // resolve hostname to IP address, not changing port or sin_family 40 | // return true on success. 41 | // thread safe 42 | // static bool resolve(StringArg hostname, StringArg* ip); 43 | // static std::vector resolveAll(const char* hostname, uint16_t port = 0); 44 | 45 | private: 46 | union{ 47 | struct sockaddr_in m_addr; 48 | struct sockaddr_in6 m_addr6; 49 | }; 50 | }; 51 | 52 | #endif -------------------------------------------------------------------------------- /includes/muduo_network/Poll.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _NET_POLL_HH 2 | #define _NET_POLL_HH 3 | 4 | #include 5 | #include 6 | 7 | #include "TimeStamp.hpp" 8 | #include "Poller.hpp" 9 | 10 | /* 11 | *#include 12 | *struct pollfd 13 | *{ 14 | *int fd; // 想查询的文件描述符. 15 | *short int events; // fd 上,我们感兴趣的事件 16 | *short int revents; /// 实际发生了的事件. 17 | *}; 18 | */ 19 | 20 | struct pollfd; 21 | 22 | namespace muduo { 23 | 24 | class Channel; 25 | class EventLoop; 26 | 27 | class Poll : public Poller { 28 | public: 29 | Poll(EventLoop* loop); 30 | ~Poll(); 31 | 32 | TimeStamp poll(int timeoutMs, ChannelList* activeChannels); 33 | 34 | void updateChannel(Channel* channel); 35 | void removeChannel(Channel* channel); 36 | 37 | private: 38 | const Poll& operator=(const Poll&); 39 | Poll(const Poll&); 40 | 41 | void fillActiveChannels(int numEvents, ChannelList* activeChannels) const; 42 | 43 | typedef std::vector PollFdList; 44 | 45 | PollFdList m_pollfds; 46 | }; 47 | 48 | } 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /includes/muduo_network/Poller.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _NET_POLLER_HH 2 | #define _NET_POLLER_HH 3 | 4 | #include 5 | #include 6 | 7 | #include "TimeStamp.hpp" 8 | 9 | namespace muduo { 10 | 11 | class EventLoop; 12 | class Channel; 13 | 14 | /// 15 | /// Base class for IO Multiplexing 16 | /// 17 | /// This class doesn't own the Channel objects. 18 | class Poller 19 | { 20 | public: 21 | typedef std::vector ChannelList; 22 | 23 | Poller(EventLoop* loop); 24 | virtual ~Poller(); 25 | 26 | /// Polls the I/O events. 27 | /// Must be called in the loop thread. 28 | virtual TimeStamp poll(int timeoutMs, ChannelList* activeChannels) = 0; 29 | 30 | /// Changes the interested I/O events. 31 | /// Must be called in the loop thread. 32 | virtual void updateChannel(Channel* channel) = 0; 33 | 34 | /// Remove the channel, when it destructs. 35 | /// Must be called in the loop thread. 36 | virtual void removeChannel(Channel* channel) = 0; 37 | 38 | virtual bool hasChannel(Channel* channel) const; 39 | 40 | static Poller* newDefaultPoller(EventLoop* loop); 41 | 42 | void assertInLoopThread() const; 43 | 44 | protected: 45 | Poller(const Poller&); 46 | const Poller& operator=(const Poller&); 47 | 48 | typedef std::map ChannelMap; 49 | ChannelMap m_channels; 50 | 51 | private: 52 | EventLoop* p_Loop; 53 | }; 54 | 55 | } 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /includes/muduo_network/Socket.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _NET_SOCKET_HH 2 | #define _NET_SOCKET_HH 3 | 4 | // struct tcp_info is in 5 | struct tcp_info; 6 | 7 | class InetAddress; 8 | 9 | class Socket{ 10 | public: 11 | explicit Socket(int sockfd) : m_sockfd(sockfd) { } 12 | ~Socket(); 13 | 14 | int fd() const { return m_sockfd; } 15 | //return true if success. 16 | bool getTcpInfo(struct tcp_info* ) const; 17 | bool getTcpInfoString(char* buf, int len) const; 18 | 19 | void bindAddress(const InetAddress& localaddr); 20 | void listen(); 21 | int accept(int sockfd, struct sockaddr_in6* addr); 22 | 23 | int accept(InetAddress* peeraddr); 24 | void shutdownWrite(); 25 | 26 | void setTcpNoDelay(bool on); 27 | 28 | void setReuseAddr(bool on); 29 | 30 | void setReusePort(bool on); 31 | 32 | void setKeepAlive(bool on); 33 | 34 | private: 35 | const int m_sockfd; 36 | 37 | }; 38 | 39 | #endif -------------------------------------------------------------------------------- /includes/muduo_network/SocketHelp.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _NET_SOCKETHELP_HH 2 | #define _NET_SOCKETHELP_HH 3 | 4 | #include 5 | 6 | namespace sockets 7 | { 8 | 9 | /// 10 | /// Creates a non-blocking socket file descriptor, 11 | /// abort if any error. 12 | int createSocket(sa_family_t family); 13 | int createNonblockingOrDie(sa_family_t); 14 | int connect(int sockfd, const struct sockaddr* addr); 15 | void bindOrDie(int sockfd, const struct sockaddr* addr); 16 | void listenOrDie(int sockfd); 17 | int accept(int sockfd, struct sockaddr_in6* addr); 18 | 19 | ssize_t read(int sockfd, void *buf, size_t count); 20 | ssize_t readv(int sockfd, const struct iovec *iov, int iovcnt); 21 | ssize_t write(int sockfd, const void *buf, size_t count); 22 | void close(int sockfd); 23 | void shutdownWrite(int sockfd); 24 | 25 | void fromIpPort(const char* ip, uint16_t port, 26 | struct sockaddr_in* addr); 27 | 28 | void toIpPort(char* buf, size_t size, 29 | const struct sockaddr* addr); 30 | void toIp(char* buf, size_t size, 31 | const struct sockaddr* addr); 32 | int getSocketError(int sockfd); 33 | struct sockaddr_in6 getLocalAddr(int sockfd); 34 | struct sockaddr_in6 getPeerAddr(int sockfd); 35 | void delaySecond(int sec); 36 | //const struct sockaddr* sockaddr_cast(const struct sockaddr_in* addr) 37 | //const struct sockaddr_in* sockaddr_in_cast(const struct sockaddr* addr); 38 | 39 | } 40 | 41 | #endif -------------------------------------------------------------------------------- /includes/muduo_network/TcpConnection.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _NET_TCPCONNECTION_HH 2 | #define _NET_TCPCONNECTION_HH 3 | 4 | #include 5 | #include 6 | 7 | #include "InetAddress.hpp" 8 | #include "Socket.hpp" 9 | #include "CallBacks.hpp" 10 | #include "Channel.hpp" 11 | #include "Buffer.hpp" 12 | 13 | namespace muduo { 14 | 15 | class TcpConnection : public std::enable_shared_from_this 16 | { 17 | public: 18 | TcpConnection(EventLoop* loop, 19 | const std::string& name, 20 | int sockfd, 21 | const InetAddress& localAddr, 22 | const InetAddress& peerAddr); 23 | ~TcpConnection(); 24 | 25 | EventLoop* getLoop() const { return p_loop; } 26 | const std::string& name() const { return m_name; } 27 | void setConnectionName(const std::string& name) { m_name = name; } 28 | void setConnectionCallBack(const NetCallBacks::ConnectionCallBack& cb) { m_connectionCallBack = cb; } 29 | void setMessageCallBack(const NetCallBacks::MessageCallBack& cb) { m_messageCallBack = cb; } 30 | void setCloseCallBack(const NetCallBacks::CloseCallBack& cb) { m_closeCallBack = cb; } 31 | 32 | const InetAddress& localAddress() const { return m_localAddr; } 33 | const InetAddress& peerAddress() const { return m_peerAddr; } 34 | 35 | // called when TcpServer accepts a new connection 36 | void connectEstablished(); // should be called only once 37 | // called when TcpServer has removed me from its map 38 | void connectDestroyed(); // should be called only once 39 | 40 | // void send(string&& message); // C++11 41 | void send(const void* message, size_t len); 42 | void send(const std::string& message); 43 | // void send(Buffer&& message); // C++11 44 | void send(Buffer* message); // this one will swap data 45 | 46 | void shutdown(); 47 | void forceClose(); 48 | 49 | bool isConnected() const { return m_state == kConnected; } 50 | bool isDisConnected() const { return m_state == kDisConnected; } 51 | const char* stateToString() const; 52 | 53 | private: 54 | enum StateE { kDisConnected, kConnecting, kDisConnecting, kConnected, }; 55 | 56 | void setState(StateE s) { m_state = s; } 57 | void handleRead(); 58 | void handleWrite(); 59 | void handleError(); 60 | void handleClose(); 61 | void sendInLoop(const void* data, size_t len); 62 | void shutdownInLoop(); 63 | void forceCloseInLoop(); 64 | 65 | EventLoop* p_loop; 66 | std::string m_name; 67 | StateE m_state; 68 | std::unique_ptr p_socket; 69 | std::unique_ptr p_channel; 70 | InetAddress m_localAddr; 71 | InetAddress m_peerAddr; 72 | 73 | NetCallBacks::ConnectionCallBack m_connectionCallBack; 74 | NetCallBacks::MessageCallBack m_messageCallBack; 75 | NetCallBacks::CloseCallBack m_closeCallBack; 76 | 77 | Buffer m_inputBuffer; 78 | Buffer m_outputBuffer; 79 | }; 80 | 81 | } 82 | 83 | #endif -------------------------------------------------------------------------------- /includes/muduo_network/TcpServer.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _NET_TCPSERVER_HH 2 | #define _NET_TCPSERVER_HH 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "CallBacks.hpp" 9 | #include "Acceptor.hpp" 10 | #include "TcpConnection.hpp" 11 | #include "EventLoopThreadPool.hpp" 12 | 13 | namespace muduo{ 14 | 15 | class EventLoop; 16 | 17 | extern std::unique_ptr ex_event_loop_thread_pool; 18 | 19 | class TcpServer 20 | { 21 | public: 22 | TcpServer(EventLoop* loop, const InetAddress& listenAddr, const std::string& name = "Serv "); 23 | ~TcpServer(); 24 | 25 | void start(); 26 | 27 | void setConnectionCallBack(const NetCallBacks::ConnectionCallBack& cb) { m_connectionCallBack = cb; } 28 | void setMessageCallBack(const NetCallBacks::MessageCallBack& cb) { m_messageCallBack = cb; } 29 | void setCloseCallBack(const NetCallBacks::CloseCallBack& cb) { m_closeCallBack = cb; } 30 | 31 | private: 32 | TcpServer& operator=(const TcpServer&); 33 | TcpServer(const TcpServer&); 34 | 35 | void newConnetion(int sockfd, const InetAddress& peerAddr); 36 | void removeConnection(const TcpConnectionPtr& conn); 37 | void removeConnectionInLoop(const TcpConnectionPtr& conn); 38 | 39 | //typedef std::map ConnectionMap; 40 | typedef std::set ConnectionsSet_t; 41 | 42 | EventLoop* p_loop; 43 | std::string m_name; 44 | std::unique_ptr p_acceptor; 45 | //ConnectionMap m_connectionsMap; 46 | ConnectionsSet_t m_connectionsSet; 47 | NetCallBacks::ConnectionCallBack m_connectionCallBack; 48 | NetCallBacks::MessageCallBack m_messageCallBack; 49 | NetCallBacks::CloseCallBack m_closeCallBack; 50 | int m_nextConnId; 51 | }; 52 | 53 | } 54 | 55 | #endif -------------------------------------------------------------------------------- /includes/muduo_network/Timer.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _NET_TIMER_HH 2 | #define _NET_TIMER_HH 3 | 4 | #include "CallBacks.hpp" 5 | #include "TimeStamp.hpp" 6 | #include "Atomic.hpp" 7 | 8 | namespace muduo { 9 | 10 | class Timer{ 11 | public: 12 | Timer(const NetCallBacks::TimerCallBack& cb, TimeStamp when, double interval) 13 | :m_callBack(cb), 14 | m_expiration(when), 15 | m_interval(interval), 16 | m_repeat(interval > 0.0), 17 | m_sequence(s_numCreated.incrementAndGet()) 18 | { 19 | 20 | } 21 | 22 | void run() const 23 | { 24 | m_callBack(); 25 | } 26 | 27 | TimeStamp expiration() const { return m_expiration; } 28 | bool repeat() const { return m_repeat; } 29 | int64_t sequence() const { return m_sequence; } 30 | void restart(TimeStamp now); 31 | 32 | static int64_t numCreated(){ return s_numCreated.get(); } 33 | 34 | private: 35 | Timer& operator=(const Timer&); 36 | Timer(const Timer&); 37 | 38 | const NetCallBacks::TimerCallBack m_callBack; 39 | TimeStamp m_expiration; 40 | const double m_interval; 41 | const bool m_repeat; 42 | const int64_t m_sequence; 43 | 44 | static AtomicInt64 s_numCreated; 45 | 46 | }; 47 | 48 | } 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /includes/muduo_network/TimerId.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _TIMER_ID_HH 2 | #define _TIMER_ID_HH 3 | #include 4 | 5 | namespace muduo { 6 | 7 | class Timer; 8 | 9 | /// 10 | /// An opaque identifier, for canceling Timer. 11 | /// 12 | class TimerId 13 | { 14 | public: 15 | TimerId() 16 | : m_timer(NULL), 17 | m_sequence(0) 18 | { 19 | } 20 | 21 | TimerId(Timer* timer, int64_t seq) 22 | : m_timer(timer), 23 | m_sequence(seq) 24 | { 25 | } 26 | 27 | // default copy-ctor, dtor and assignment are okay 28 | 29 | friend class TimerQueue; 30 | 31 | private: 32 | //TimerId& operator=(const TimerId&); 33 | //TimerId(const TimerId&); 34 | 35 | Timer* m_timer; 36 | int64_t m_sequence; 37 | }; 38 | 39 | } 40 | 41 | #endif -------------------------------------------------------------------------------- /includes/muduo_network/TimerQueue.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _NET_TIMERQUEUE_HH 2 | #define _NET_TIMERQUEUE_HH 3 | #include "TimerId.hpp" 4 | #include "CallBacks.hpp" 5 | #include "TimeStamp.hpp" 6 | #include "Channel.hpp" 7 | #include 8 | #include 9 | 10 | namespace muduo { 11 | 12 | class EventLoop; 13 | 14 | class TimerQueue 15 | { 16 | public: 17 | TimerQueue(EventLoop* loop); 18 | ~TimerQueue(); 19 | 20 | // Schedules the callback to be run at given time, 21 | 22 | TimerId addTimer(const NetCallBacks::TimerCallBack& cb, TimeStamp when, double interval = 0.0); 23 | 24 | void cancel(TimerId timerId); 25 | 26 | private: 27 | typedef std::pair Entry; 28 | typedef std::set TimerList; 29 | typedef std::pair ActiveTimer; 30 | typedef std::set ActiveTimerSet; 31 | 32 | void addTimerInLoop(Timer* timer); 33 | void cancelInLoop(TimerId timerId); 34 | //called when timerfd alarms 35 | void handleRead(); 36 | //move out all expired timers and return they. 37 | std::vector getExpired(TimeStamp now); 38 | bool insert(Timer* timer); 39 | void reset(const std::vector& expired, TimeStamp now); 40 | 41 | EventLoop* p_loop; 42 | const int m_timerfd; 43 | Channel m_timerfdChannel; 44 | 45 | //Timer List sorted by expiration 46 | TimerList m_timers; 47 | ActiveTimerSet m_activeTimers; 48 | 49 | bool m_callingExpiredTimers; /*atomic*/ 50 | ActiveTimerSet m_cancelingTimers; 51 | 52 | }; 53 | 54 | } 55 | 56 | #endif 57 | 58 | -------------------------------------------------------------------------------- /includes/muduo_server: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include -------------------------------------------------------------------------------- /sources/muduo_logger/AsyncLogging.cpp: -------------------------------------------------------------------------------- 1 | #include "AsyncLogging.hpp" 2 | #include "LogFile.hpp" 3 | #include 4 | #include 5 | 6 | AsyncLogging::AsyncLogging(const std::string filePath, off_t rollSize, double flushInterval) 7 | :m_filePath(filePath), 8 | m_rollSize(rollSize), 9 | m_flushInterval(flushInterval), 10 | m_isRunning(false), 11 | m_thread(std::bind(&AsyncLogging::threadRoutine, this)), 12 | m_mutex(), 13 | m_cond(), 14 | m_currentBuffer(new Buffer), 15 | m_nextBuffer(new Buffer), 16 | m_buffers() 17 | { 18 | } 19 | 20 | AsyncLogging::~AsyncLogging(){ 21 | if(m_isRunning) stop(); 22 | } 23 | 24 | void AsyncLogging::append(const char* logline, std::size_t len){ 25 | std::lock_guard lock(m_mutex); 26 | if(m_currentBuffer->avail() > len){ 27 | m_currentBuffer->append(logline, len); 28 | } 29 | else{ 30 | m_buffers.push_back(m_currentBuffer.release()); 31 | 32 | if(m_nextBuffer){ 33 | m_currentBuffer = std::move(m_nextBuffer); 34 | } 35 | else{ 36 | m_currentBuffer.reset(new Buffer); 37 | } 38 | 39 | m_currentBuffer->append(logline, len); 40 | m_cond.notify(); 41 | } 42 | } 43 | 44 | void AsyncLogging::threadRoutine(){ 45 | assert(m_isRunning == true); 46 | LogFile output(m_filePath, m_rollSize, false); 47 | BufferPtr backupBuffer1(new Buffer); 48 | BufferPtr backupBuffer2(new Buffer); 49 | BufferVector buffersToWrite; 50 | buffersToWrite.reserve(8); 51 | 52 | while(m_isRunning){ 53 | assert(buffersToWrite.empty()); 54 | { 55 | std::unique_lock lock(m_mutex); 56 | if(m_buffers.empty()){ 57 | m_cond.waitForSeconds(lock, m_flushInterval); 58 | } 59 | m_buffers.push_back(m_currentBuffer.release()); 60 | m_currentBuffer = std::move(backupBuffer1); 61 | m_buffers.swap(buffersToWrite); 62 | if(!m_nextBuffer) 63 | m_nextBuffer = std::move(backupBuffer2); 64 | } 65 | 66 | assert(!buffersToWrite.empty()); 67 | 68 | for(size_t i = 0; i < buffersToWrite.size(); ++i){ 69 | output.append(buffersToWrite[i]->data(), buffersToWrite[i]->length()); 70 | } 71 | 72 | if(buffersToWrite.size() > 2) 73 | { 74 | // drop non-bzero-ed buffers, avoid trashing 75 | buffersToWrite.resize(2); 76 | } 77 | 78 | if(!backupBuffer1) 79 | { 80 | assert(!buffersToWrite.empty()); 81 | backupBuffer1 = std::move(buffersToWrite.pop_back()); 82 | backupBuffer1->reset(); 83 | } 84 | 85 | if(!backupBuffer2) 86 | { 87 | assert(!buffersToWrite.empty()); 88 | backupBuffer2 = std::move(buffersToWrite.pop_back()); 89 | backupBuffer2->reset(); 90 | } 91 | 92 | buffersToWrite.clear(); 93 | output.flush(); 94 | } 95 | 96 | output.flush(); 97 | } 98 | -------------------------------------------------------------------------------- /sources/muduo_logger/FileUtil.cpp: -------------------------------------------------------------------------------- 1 | #include "FileUtil.hpp" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | static off_t fileSize(const std::string& path); 9 | 10 | FileUtil::AppendFile::AppendFile(StringArg filePath) 11 | :m_fp(::fopen(filePath.c_str(), "ae")), // 'e' for O_CLOEXEC 12 | m_writtenBytes(fileSize(filePath.c_str())) 13 | { 14 | assert(m_fp); 15 | ::setbuffer(m_fp, m_buffer, sizeof(m_buffer)); 16 | } 17 | 18 | FileUtil::AppendFile::~AppendFile(){ 19 | ::fclose(m_fp); 20 | } 21 | 22 | void FileUtil::AppendFile::append(const char* logline, const size_t len){ 23 | size_t nread = write(logline, len); 24 | size_t remain = len - nread; 25 | while(remain > 0){ 26 | size_t n = write(logline + nread, remain); 27 | if(0 == n){ 28 | int err = ferror(m_fp); 29 | if(err){ 30 | fprintf(stderr, "AppendFile::append failed : %s\n", strerror(err)); 31 | } 32 | break; 33 | } 34 | nread += n; 35 | remain = len - nread; 36 | } 37 | 38 | m_writtenBytes += len; 39 | } 40 | 41 | size_t FileUtil::AppendFile::write(const char* logline, const size_t len){ 42 | return ::fwrite_unlocked(logline, 1, len, m_fp); 43 | } 44 | 45 | void FileUtil::AppendFile::flush(){ 46 | ::fflush(m_fp); 47 | } 48 | 49 | static off_t fileSize(const std::string& path) // get file size 50 | { 51 | struct stat fileInfo; 52 | if (stat(path.c_str(), &fileInfo) < 0) 53 | { 54 | switch(errno) 55 | { 56 | case ENOENT: 57 | return 0; 58 | default: 59 | fprintf(stderr, "stat fileInfo failed : %s\n", strerror(errno)); 60 | abort(); 61 | } 62 | } 63 | else 64 | { 65 | return fileInfo.st_size; 66 | } 67 | } -------------------------------------------------------------------------------- /sources/muduo_logger/LogFile.cpp: -------------------------------------------------------------------------------- 1 | #include "LogFile.hpp" 2 | #include "FileUtil.hpp" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | LogFile::LogFile(const std::string& filePath, off_t rollSize, bool threadSafe, int flushInterval) 10 | :m_filePath(filePath), 11 | m_flushInterval(flushInterval), 12 | m_rollCnt(-1), 13 | m_roolSize(rollSize), 14 | m_mutex(threadSafe ? new std::mutex : NULL), 15 | m_file(new FileUtil::AppendFile(m_filePath)){ 16 | //assert(filePath.find('/') == std::string::npos); 17 | } 18 | 19 | LogFile::~LogFile(){ 20 | } 21 | 22 | void LogFile::append(const char* logline, int len){ 23 | if(m_mutex){ 24 | std::lock_guard lock(*m_mutex); 25 | append_unlocked(logline, len); 26 | } 27 | else{ 28 | append_unlocked(logline, len); 29 | } 30 | } 31 | 32 | void LogFile::append_unlocked(const char* logline, int len){ 33 | m_file->append(logline, len); 34 | 35 | if(m_file->writtenBytes() > m_roolSize){ 36 | rollFile(); 37 | } 38 | } 39 | 40 | void LogFile::flush(){ 41 | if(m_mutex){ 42 | std::lock_guard lock(*m_mutex); 43 | m_file->flush(); 44 | } 45 | else{ 46 | m_file->flush(); 47 | } 48 | } 49 | 50 | bool LogFile::rollFile(){ 51 | //std::string fileNameNew = m_filePath; 52 | //fileNameNew = getlogFileName(m_filePath); 53 | 54 | if(m_file->writtenBytes() < m_roolSize) 55 | m_file.reset(new FileUtil::AppendFile(m_filePath)); 56 | else 57 | { 58 | assert(remove(m_filePath.c_str()) == 0); 59 | m_file.reset(new FileUtil::AppendFile(m_filePath)); 60 | } 61 | //checkLogNum(); 62 | 63 | return true; 64 | } 65 | 66 | std::string LogFile::getlogFileName(const std::string& baseName){ 67 | std::string fileName; 68 | fileName.reserve(baseName.size() + 32); 69 | fileName = baseName.substr(0, baseName.rfind(".")); 70 | 71 | char timebuf[24]; 72 | struct tm tm; 73 | time_t now = time(NULL); 74 | gmtime_r(&now, &tm); 75 | strftime(timebuf, sizeof(timebuf), ".%Y%m%d-%H%M%S", &tm); 76 | fileName += timebuf; 77 | fileName += ".log"; 78 | 79 | return fileName; 80 | } 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /sources/muduo_logger/LogStream.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "LogStream.hpp" 5 | 6 | 7 | LogStream::LogStream(){ 8 | } 9 | 10 | LogStream::~LogStream(){ 11 | } 12 | 13 | LogStream& LogStream::operator<<(bool v){ 14 | m_buffer.append(v ? "1" : "0", 1); 15 | return *this; 16 | } 17 | 18 | 19 | LogStream& LogStream::operator<<(short v){ 20 | *this << static_cast(v); 21 | return *this; 22 | } 23 | 24 | LogStream& LogStream::operator<<(unsigned short v) 25 | { 26 | *this << static_cast(v); 27 | return *this; 28 | } 29 | 30 | LogStream& LogStream::operator<<(int v) 31 | { 32 | formatInteger(v); 33 | return *this; 34 | } 35 | 36 | LogStream& LogStream::operator<<(unsigned int v) 37 | { 38 | formatInteger(v); 39 | return *this; 40 | } 41 | 42 | LogStream& LogStream::operator<<(long v) 43 | { 44 | formatInteger(v); 45 | return *this; 46 | } 47 | 48 | LogStream& LogStream::operator<<(unsigned long v) 49 | { 50 | formatInteger(v); 51 | return *this; 52 | } 53 | 54 | LogStream& LogStream::operator<<(long long v) 55 | { 56 | formatInteger(v); 57 | return *this; 58 | } 59 | 60 | LogStream& LogStream::operator<<(unsigned long long v) 61 | { 62 | formatInteger(v); 63 | return *this; 64 | } 65 | 66 | const char digitsHex[] = "0123456789ABCDEF"; 67 | 68 | size_t convertHex(char buf[], uintptr_t value) 69 | { 70 | uintptr_t i = value; 71 | char* p = buf; 72 | 73 | do 74 | { 75 | int lsd = static_cast(i % 16); 76 | i /= 16; 77 | *p++ = digitsHex[lsd]; 78 | } while (i != 0); 79 | 80 | *p = '\0'; 81 | std::reverse(buf, p); 82 | 83 | return p - buf; 84 | } 85 | 86 | LogStream& LogStream::operator<<(const void* p){ 87 | uintptr_t v = reinterpret_cast(p); 88 | if (m_buffer.avail() >= kMaxNumericSize) 89 | { 90 | char* buf = m_buffer.current(); 91 | buf[0] = '0'; 92 | buf[1] = 'x'; 93 | size_t len = convertHex(buf+2, v); 94 | m_buffer.add(len+2); 95 | } 96 | return *this; 97 | } 98 | 99 | LogStream& LogStream::operator<<(float v) 100 | { 101 | *this << static_cast(v); 102 | return *this; 103 | } 104 | 105 | LogStream& LogStream::operator<<(double v){ 106 | if(m_buffer.avail() >= kMaxNumericSize){ 107 | int len = snprintf(m_buffer.current(), kMaxNumericSize, "%.12g", v); 108 | m_buffer.add(len); 109 | } 110 | return *this; 111 | } 112 | 113 | LogStream& LogStream::operator<<(char v){ 114 | m_buffer.append(&v, 1); 115 | return *this; 116 | } 117 | 118 | LogStream& LogStream::operator<<(const char *str){ 119 | if(str){ 120 | m_buffer.append(str, strlen(str)); 121 | }else{ 122 | m_buffer.append("(NULL)", 6); 123 | } 124 | 125 | return *this; 126 | } 127 | 128 | LogStream& LogStream::operator<<(const std::string& s){ 129 | if(!s.empty()){ 130 | m_buffer.append(s.c_str(), s.size()); 131 | }else{ 132 | m_buffer.append("(NULL)", 6); 133 | } 134 | 135 | return *this; 136 | } 137 | 138 | 139 | const char digits[] = "9876543210123456789"; 140 | const char* zero = digits + 9; 141 | 142 | //convert to str 143 | template 144 | size_t convert(char buf[], T value){ 145 | T i = value; 146 | char *p = buf; 147 | 148 | do{ 149 | int lsd = static_cast(i % 10); 150 | i /= 10; 151 | *p++ = zero[lsd]; 152 | } while(i != 0); 153 | 154 | if(value < 0){ 155 | *p++ = '-'; 156 | } 157 | 158 | *p = '\0'; 159 | std::reverse(buf, p); 160 | 161 | return p - buf; 162 | } 163 | 164 | template 165 | void LogStream::formatInteger(T v) 166 | { 167 | if(m_buffer.avail() >= kMaxNumericSize){ 168 | size_t len = convert(m_buffer.current(), v); 169 | m_buffer.add(len); 170 | } 171 | } 172 | 173 | template 174 | Fmt::Fmt(const char* fmt, T val) 175 | { 176 | m_length = snprintf(m_buf, sizeof(m_buf), fmt, val); 177 | assert(static_cast(m_length) < sizeof(m_buf)); 178 | } 179 | 180 | // Explicit instantiations 181 | 182 | template Fmt::Fmt(const char* fmt, char); 183 | 184 | template Fmt::Fmt(const char* fmt, short); 185 | template Fmt::Fmt(const char* fmt, unsigned short); 186 | template Fmt::Fmt(const char* fmt, int); 187 | template Fmt::Fmt(const char* fmt, unsigned int); 188 | template Fmt::Fmt(const char* fmt, long); 189 | template Fmt::Fmt(const char* fmt, unsigned long); 190 | template Fmt::Fmt(const char* fmt, long long); 191 | template Fmt::Fmt(const char* fmt, unsigned long long); 192 | 193 | template Fmt::Fmt(const char* fmt, float); 194 | template Fmt::Fmt(const char* fmt, double); -------------------------------------------------------------------------------- /sources/muduo_logger/Logger.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "TimeStamp.hpp" 9 | #include "Logger.hpp" 10 | 11 | __thread char t_time[64]; 12 | __thread time_t t_lastSecond; 13 | __thread char t_errnobuf[512]; 14 | 15 | static const char black[] = {0x1b, '[', '1', ';', '3', '0', 'm', 0}; 16 | static const char red[] = {0x1b, '[', '1', ';', '3', '1', 'm', 0}; 17 | static const char green[] = {0x1b, '[', '1', ';', '3', '2', 'm', 0}; 18 | static const char yellow[] = {0x1b, '[', '1', ';', '3', '3', 'm', 0}; 19 | static const char blue[] = {0x1b, '[', '1', ';', '3', '4', 'm', 0}; 20 | static const char purple[] = {0x1b, '[', '1', ';', '3', '5', 'm', 0}; 21 | static const char normal[] = {0x1b, '[', '0', ';', '3', '9', 'm', 0}; 22 | 23 | const char* strerror_tl(int savedErrno) 24 | { 25 | return strerror_r(savedErrno, t_errnobuf, sizeof(t_errnobuf)); 26 | } 27 | 28 | Logger::LogLevel g_logLevel = Logger::TRACE; 29 | 30 | void Logger::setLogLevel(LogLevel level){ 31 | g_logLevel = level; 32 | } 33 | 34 | Logger::LogLevel Logger::logLevel(){ 35 | return g_logLevel; 36 | } 37 | 38 | const char* LogLevelName[Logger::NUM_LOG_LEVELS] = 39 | { 40 | "[TRACE]", 41 | "[DEBUG]", 42 | "[INFO ]", 43 | "[WARN ]", 44 | "[ERROR]", 45 | "[FATAL]", 46 | }; 47 | 48 | // helper class for known string length at compile time 49 | class T 50 | { 51 | public: 52 | T(const char* str, unsigned len) 53 | :m_str(str), 54 | m_len(len) 55 | { 56 | assert(strlen(str) == m_len); 57 | } 58 | 59 | const char* m_str; 60 | const unsigned m_len; 61 | }; 62 | 63 | void defaultOutput(const char *msg, int len){ 64 | size_t n = fwrite(msg, 1, len, stdout); 65 | (void)n; 66 | } 67 | 68 | void defaultFlush(){ 69 | fflush(stdout); 70 | } 71 | 72 | Logger::outputFunc g_output = defaultOutput; 73 | Logger::flushFunc g_flush = defaultFlush; 74 | 75 | void Logger::setOutput(outputFunc out){ 76 | g_output = out; 77 | } 78 | 79 | void Logger::setFlush(flushFunc flush){ 80 | g_flush = flush; 81 | } 82 | 83 | Logger::Logger(SourceFile file, int line) 84 | : m_impl(INFO, 0, file, line){ 85 | } 86 | 87 | Logger::Logger(SourceFile file, int line, LogLevel level) 88 | : m_impl(level, 0, file, line){ 89 | } 90 | 91 | Logger::Logger(SourceFile file, int line, bool toAbort) 92 | : m_impl(toAbort? FATAL:ERROR, errno, file, line){ 93 | } 94 | 95 | Logger::Logger(SourceFile file, int line, LogLevel level, const char* func) 96 | : m_impl(level, 0, file, line){ 97 | m_impl.m_stream << '[' << func << "] "; 98 | } 99 | 100 | Logger::~Logger(){ 101 | m_impl.finish(); 102 | const LogStream::Buffer& buf(stream().buffer()); 103 | g_output(buf.data(), buf.length()); 104 | if (m_impl.m_level == FATAL) 105 | { 106 | g_flush(); 107 | abort(); 108 | } 109 | } 110 | 111 | Logger::Impl::Impl(LogLevel level, int savedErrno, const SourceFile& file, int line) 112 | : m_time(TimeStamp::now()), 113 | m_stream(), 114 | m_level(level), 115 | m_line(line), 116 | m_fileBaseName(file) 117 | { 118 | formatTime(); 119 | 120 | switch(level){ 121 | case TRACE: 122 | m_stream << green << LogLevelName[level] << normal << ' '; 123 | break; 124 | case DEBUG: 125 | m_stream << blue << LogLevelName[level] << normal << ' '; 126 | break; 127 | case INFO: 128 | m_stream << black << LogLevelName[level] << normal << ' '; 129 | break; 130 | case WARN: 131 | m_stream << yellow << LogLevelName[level] << normal << ' '; 132 | break; 133 | case ERROR: 134 | m_stream << purple << LogLevelName[level] << normal << ' '; 135 | break; 136 | case FATAL: 137 | m_stream << red << LogLevelName[level] << normal << ' '; 138 | break; 139 | default: 140 | m_stream << LogLevelName[level] << ' '; 141 | break; 142 | } 143 | 144 | //m_stream << LogLevelName[level] << ' '; 145 | m_stream << '[' << m_fileBaseName.m_data << ':' << m_line << "] "; 146 | if (savedErrno != 0) 147 | { 148 | m_stream << strerror_tl(savedErrno) << " (errno=" << savedErrno << ") "; 149 | } 150 | } 151 | 152 | void Logger::Impl::finish() 153 | { 154 | m_stream<< '\n'; 155 | } 156 | 157 | void Logger::Impl::formatTime() 158 | { 159 | int64_t microSecondsSinceEpoch = m_time.microSecondsSinceEpoch(); 160 | time_t seconds = static_cast(microSecondsSinceEpoch / TimeStamp::kMicroSecondsPerSecond); 161 | int microseconds = static_cast(microSecondsSinceEpoch % TimeStamp::kMicroSecondsPerSecond); 162 | if (seconds != t_lastSecond){ 163 | t_lastSecond = seconds; 164 | struct tm tm_time; 165 | 166 | ::gmtime_r(&seconds, &tm_time); // FIXME TimeZone::fromUtcTime 167 | 168 | int len = snprintf(t_time, sizeof(t_time), "%4d-%02d-%02d %02d:%02d:%02d", 169 | tm_time.tm_year + 1900, tm_time.tm_mon + 1, tm_time.tm_mday, 170 | tm_time.tm_hour + 8, tm_time.tm_min, tm_time.tm_sec); 171 | assert(len == 19); (void)len; 172 | } 173 | 174 | Fmt us(".%06d ", microseconds); 175 | assert(us.length() == 8); 176 | m_stream << t_time << us.data(); 177 | } 178 | 179 | -------------------------------------------------------------------------------- /sources/muduo_logger/Thread.cpp: -------------------------------------------------------------------------------- 1 | #include "Thread.hpp" 2 | 3 | Thread::Thread(const ThreadFunc& threadRoutine) 4 | :m_isStarted(false), 5 | m_isJoined(false), 6 | m_threadRoutine(threadRoutine) 7 | { 8 | 9 | } 10 | 11 | Thread::~Thread() 12 | { 13 | if(m_isStarted && !m_isJoined) 14 | { 15 | p_thread->detach(); 16 | } 17 | } 18 | 19 | void Thread::join() 20 | { 21 | assert(m_isStarted); 22 | assert(!m_isJoined); 23 | m_isJoined = true; 24 | p_thread->join(); 25 | } 26 | 27 | void Thread::detach() 28 | { 29 | assert(m_isStarted); 30 | assert(!m_isJoined); 31 | p_thread->detach(); 32 | } 33 | 34 | void Thread::start() 35 | { 36 | assert(!m_isStarted); 37 | assert(!p_thread); 38 | p_thread.reset(new std::thread(m_threadRoutine)); 39 | m_isStarted = true; 40 | } 41 | -------------------------------------------------------------------------------- /sources/muduo_logger/TimeStamp.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "TimeStamp.hpp" 3 | #include 4 | 5 | TimeStamp TimeStamp::now(){ 6 | struct timeval tv; 7 | gettimeofday(&tv, 0); 8 | int64_t seconds = tv.tv_sec; 9 | return TimeStamp(seconds * kMicroSecondsPerSecond + tv.tv_usec); 10 | } 11 | 12 | 13 | std::string TimeStamp::toString() const 14 | { 15 | char buf[32] = {0}; 16 | int64_t seconds = m_microSecondsSinceEpoch / kMicroSecondsPerSecond; 17 | int64_t microseconds = m_microSecondsSinceEpoch % kMicroSecondsPerSecond; 18 | snprintf(buf, sizeof(buf)-1, "%" PRId64 ".%06" PRId64 "", seconds, microseconds); 19 | return buf; 20 | } 21 | -------------------------------------------------------------------------------- /sources/muduo_network/Acceptor.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "SocketHelp.hpp" 8 | #include "InetAddress.hpp" 9 | #include "EventLoop.hpp" 10 | #include "Logger.hpp" 11 | #include "Acceptor.hpp" 12 | 13 | using namespace muduo; 14 | 15 | Acceptor::Acceptor(EventLoop* loop, const InetAddress& listenAddr, bool reuseport) 16 | :p_loop(loop), 17 | m_acceptSocket(sockets::createNonblockingOrDie(listenAddr.family())), 18 | m_acceptChannel(loop, m_acceptSocket.fd()), 19 | m_listenning(false), 20 | m_idleFd(::open("/dev/null", O_RDONLY | O_CLOEXEC)) 21 | { 22 | assert(m_idleFd >= 0); 23 | m_acceptSocket.setReuseAddr(reuseport); 24 | m_acceptSocket.bindAddress(listenAddr); 25 | m_acceptChannel.setReadCallBack( 26 | std::bind(&Acceptor::handleRead, this)); 27 | } 28 | 29 | Acceptor::~Acceptor() 30 | { 31 | m_acceptChannel.disableAll(); 32 | m_acceptChannel.remove(); 33 | ::close(m_idleFd); 34 | } 35 | 36 | void Acceptor::listen() 37 | { 38 | p_loop->assertInLoopThread(); 39 | m_listenning = true; 40 | m_acceptSocket.listen(); 41 | m_acceptChannel.enableReading(); 42 | } 43 | 44 | void Acceptor::handleRead() 45 | { 46 | LOG_TRACE << "Acceptor::handleRead()"; 47 | p_loop->assertInLoopThread(); 48 | InetAddress peerAddr; 49 | int connfd = m_acceptSocket.accept(&peerAddr); 50 | if(connfd >= 0) 51 | { 52 | if(m_newConnectionCallBack) 53 | { 54 | m_newConnectionCallBack(connfd, peerAddr); 55 | } 56 | else 57 | { 58 | sockets::close(connfd); 59 | } 60 | } 61 | else 62 | { 63 | LOG_SYSERR << "in Acceptor::handleRead"; 64 | if(errno == EMFILE) 65 | { 66 | ::close(m_idleFd); 67 | m_idleFd = ::accept(m_acceptSocket.fd(), NULL, NULL); 68 | ::close(m_idleFd); 69 | m_idleFd = ::open("/dev/null", O_RDONLY | O_CLOEXEC); 70 | } 71 | } 72 | } -------------------------------------------------------------------------------- /sources/muduo_network/Buffer.cpp: -------------------------------------------------------------------------------- 1 | #include "Buffer.hpp" 2 | #include "SocketHelp.hpp" 3 | 4 | /*#include 5 | #include */ 6 | 7 | using namespace muduo; 8 | 9 | const ssize_t kExtraBufferSize = 10240; 10 | 11 | const char Buffer::kCRLF[] = "\r\n"; 12 | 13 | const size_t Buffer::kCheapPrepend; 14 | const size_t Buffer::kInitialSize; 15 | 16 | ssize_t Buffer::readFd(int fd, int* savedErrno) 17 | { 18 | // saved an ioctl()/FIONREAD call to tell how much to read 19 | char extrabuf[kExtraBufferSize]; 20 | struct iovec vec[2]; 21 | const size_t writable = writableBytes(); 22 | vec[0].iov_base = begin() + m_writerIndex; 23 | vec[0].iov_len = writable; 24 | vec[1].iov_base = extrabuf; 25 | vec[1].iov_len = sizeof extrabuf; 26 | // when there is enough space in this buffer, don't read into extrabuf. 27 | // when extrabuf is used, we read 128k-1 bytes at most. 28 | const int iovcnt = (writable < sizeof extrabuf) ? 2 : 1; 29 | const ssize_t n = sockets::readv(fd, vec, iovcnt); 30 | //printf("Buffer::readFd() : len writable %d len %d capcity %d\n", writable, n - writable, internalCapacity()); 31 | if (n < 0) 32 | { 33 | *savedErrno = errno; 34 | } 35 | else if (static_cast(n) <= writable) 36 | { 37 | m_writerIndex += n; 38 | } 39 | else 40 | { 41 | m_writerIndex = m_buffer.size(); 42 | append(extrabuf, n - writable); 43 | } 44 | // if (n == writable + sizeof extrabuf) 45 | // { 46 | // goto line_30; 47 | // } 48 | return n; 49 | } 50 | 51 | /* 52 | int main() 53 | { 54 | Buffer buffer; 55 | 56 | std::cout << buffer.writableBytes() << std::endl; 57 | strcpy(buffer.beginWrite(), "123456789"); 58 | std::cout << buffer.writableBytes() << std::endl; 59 | buffer.hasWritten(9); 60 | std::cout << buffer.writableBytes() << std::endl; 61 | buffer.unwrite(4); 62 | std::cout << buffer.writableBytes() << std::endl; 63 | strcpy(buffer.beginWrite(), "123456789"); 64 | std::cout << buffer.writableBytes() << std::endl; 65 | std::cout << buffer.peek() << std::endl; 66 | 67 | buffer.retrieveAll(); 68 | std::cout << buffer.writableBytes() << std::endl; 69 | 70 | buffer.append("123456789", 9); 71 | std::cout << buffer.writableBytes() << std::endl; 72 | std::cout << buffer.peek() << std::endl; 73 | 74 | while(1) 75 | { 76 | int err = 0; 77 | buffer.readFd(0, &err); 78 | std::cout << buffer.writableBytes() << std::endl; 79 | std::cout << buffer.peek() << std::endl; 80 | std::cout << buffer.internalCapacity() << std::endl; 81 | } 82 | }*/ -------------------------------------------------------------------------------- /sources/muduo_network/Channel.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "Channel.hpp" 7 | #include "EventLoop.hpp" 8 | #include "Logger.hpp" 9 | 10 | using namespace muduo; 11 | 12 | #define _EPOLL_METHOD 13 | 14 | #ifdef _EPOLL_METHOD 15 | enum EventType 16 | { 17 | EVENTIN = EPOLLIN, 18 | EVENTPRI = EPOLLPRI, 19 | EVENTOUT = EPOLLOUT, 20 | EVENTHUP = EPOLLHUP, 21 | EVENTRDHUP = EPOLLRDHUP, 22 | EVENTERR = EPOLLERR, 23 | EVENTET = EPOLLET, 24 | }; 25 | #else 26 | enum EventType 27 | { 28 | EVENTIN = POLLIN, 29 | EVENTPRI = POLLPRI, 30 | EVENTOUT = POLLOUT, 31 | EVENTHUP = POLLHUP, 32 | EVENTRDHUP = POLLRDHUP, 33 | EVENTERR = POLLERR, 34 | EVENTNVAL = POLLNVAL, 35 | }; 36 | #endif 37 | 38 | const uint32_t Channel::kNoneEvent = 0; 39 | const uint32_t Channel::kReadEvent = EVENTIN | EVENTPRI; 40 | const uint32_t Channel::kWriteEvent = EVENTOUT; 41 | 42 | Channel::Channel(EventLoop* loop, int fd) 43 | : p_loop(loop), 44 | m_fd(fd), 45 | m_events(0), 46 | m_revents(0), 47 | m_index(-1), 48 | m_addedToLoop(false) 49 | { 50 | 51 | } 52 | 53 | Channel::~Channel() 54 | { 55 | 56 | } 57 | 58 | void Channel::update() 59 | { 60 | m_addedToLoop = true; 61 | p_loop->updateChannel(this); 62 | } 63 | 64 | void Channel::remove() 65 | { 66 | assert(isNoneEvent()); 67 | m_addedToLoop = false; 68 | p_loop->removeChannel(this); 69 | } 70 | 71 | void Channel::handleEvent() 72 | { 73 | LOG_TRACE << "Channel::handleEvent() "; 74 | #ifndef _EPOLL_METHOD 75 | if(m_revents & EVENTNVAL) 76 | { 77 | LOG_WARN << "Channel::handleEvent() EVENTNVAL"; 78 | if(m_errorCallBack) m_errorCallBack(); 79 | } 80 | #endif 81 | 82 | if ((m_revents & EVENTHUP) && !(m_revents & EVENTIN)) 83 | { 84 | LOG_WARN << "fd = " << m_fd << " Channel::handle_event() EVENTHUP"; 85 | if (m_closeCallBack) m_closeCallBack(); 86 | } 87 | 88 | if(m_revents & (EVENTERR)){ 89 | if(m_errorCallBack) m_errorCallBack(); 90 | } 91 | 92 | if(m_revents & (EVENTIN | EVENTPRI | EVENTRDHUP)){ 93 | if(m_readCallBack) m_readCallBack(); 94 | } 95 | 96 | if(m_revents & EVENTOUT){ 97 | if(m_writeCallBack) m_writeCallBack(); 98 | } 99 | 100 | } 101 | 102 | std::string Channel::reventsToString() const 103 | { 104 | return eventsToString(m_fd, m_revents); 105 | } 106 | 107 | std::string Channel::eventsToString() const 108 | { 109 | return eventsToString(m_fd, m_events); 110 | } 111 | 112 | std::string Channel::eventsToString(int fd, int ev) const 113 | { 114 | std::ostringstream oss; 115 | oss << fd << ": "; 116 | if (ev & EVENTIN) 117 | oss << "IN "; 118 | if (ev & EVENTPRI) 119 | oss << "PRI "; 120 | if (ev & EVENTOUT) 121 | oss << "OUT "; 122 | if (ev & EVENTHUP) 123 | oss << "HUP "; 124 | if (ev & EVENTRDHUP) 125 | oss << "RDHUP "; 126 | if (ev & EVENTERR) 127 | oss << "ERR "; 128 | #ifndef _EPOLL_METHOD 129 | if (ev & EVENTNVAL) 130 | oss << "NVAL "; 131 | #endif 132 | 133 | return oss.str().c_str(); 134 | } 135 | -------------------------------------------------------------------------------- /sources/muduo_network/CurrentThread.cpp: -------------------------------------------------------------------------------- 1 | #include "CurrentThread.hpp" 2 | 3 | namespace CurrentThread 4 | { 5 | 6 | __thread int t_cachedTid = 0; 7 | __thread char t_tidString[32]; 8 | __thread int t_tidStringLength = 6; 9 | __thread const char* t_threadName = "unknown"; 10 | 11 | } -------------------------------------------------------------------------------- /sources/muduo_network/Epoll.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "EventLoop.hpp" 5 | #include "Channel.hpp" 6 | #include "Logger.hpp" 7 | #include "Epoll.hpp" 8 | 9 | using namespace muduo; 10 | 11 | namespace EventFd{ 12 | 13 | int createEpollFd() 14 | { 15 | int epfd = epoll_create1(EPOLL_CLOEXEC); 16 | if(epfd < 0) 17 | { 18 | LOG_SYSFATAL << "createEpollFd() Failed."; 19 | } 20 | 21 | return epfd; 22 | } 23 | 24 | void epollRegister(int epfd, int fd, struct epoll_event* ev) 25 | { 26 | int ret = epoll_ctl(epfd, EPOLL_CTL_ADD, fd, ev); 27 | if(ret < 0) 28 | { 29 | LOG_SYSFATAL << "epollRegister() Failed."; 30 | } 31 | } 32 | 33 | void epollUpdate(int epfd, int fd, struct epoll_event* ev) 34 | { 35 | int ret = epoll_ctl(epfd, EPOLL_CTL_MOD, fd, ev); 36 | if(ret < 0) 37 | { 38 | LOG_SYSFATAL << "epollUpdate() Failed."; 39 | } 40 | } 41 | 42 | void epollDelete(int epfd, int fd, struct epoll_event* ev) 43 | { 44 | int ret = epoll_ctl(epfd, EPOLL_CTL_DEL, fd, ev); 45 | if(ret < 0) 46 | { 47 | LOG_SYSFATAL << "epollDelete() Failed."; 48 | } 49 | } 50 | 51 | } 52 | 53 | const int Epoll::kMaxEpollConcurrencySize = 10000; 54 | const int Epoll::kInitEpollEventsSize = 1024; 55 | 56 | Epoll::Epoll(EventLoop* loop) 57 | : Poller(loop), 58 | m_epfd(EventFd::createEpollFd()), 59 | m_maxEventsSize(0), 60 | m_epollEvents(kInitEpollEventsSize) 61 | { 62 | 63 | } 64 | 65 | Epoll::~Epoll() 66 | { 67 | 68 | } 69 | 70 | TimeStamp Epoll::poll(int timeoutMs, ChannelList* activeChannels) 71 | { 72 | LOG_TRACE << "Epoll::poll() maxConcurrencySize " << m_maxEventsSize; 73 | assert(m_epollEvents.size() > 0); 74 | int numEvents = ::epoll_wait(m_epfd, m_epollEvents.data(), m_maxEventsSize, timeoutMs); 75 | TimeStamp now(TimeStamp::now()); 76 | if(numEvents > 0){ 77 | LOG_TRACE << numEvents << " events happended"; 78 | fillActiveChannels(numEvents, activeChannels); 79 | } 80 | else if(numEvents == 0){ 81 | LOG_TRACE << " nothing happended"; 82 | } 83 | else{ 84 | LOG_SYSERR << "Epoll::epoll_wait()"; 85 | } 86 | 87 | return now; 88 | } 89 | 90 | /* 91 | *fillActiveChannels() m_epollEvents 填充活动事件的fd, 把它对应 92 | *的Channel填入activeChannels。 93 | */ 94 | 95 | void Epoll::fillActiveChannels(int numEvents, ChannelList* activeChannels) const 96 | { 97 | for(EpollFdList::const_iterator it = m_epollEvents.begin(); 98 | it != m_epollEvents.end() && numEvents > 0; ++it) 99 | { 100 | assert(it->events > 0); 101 | --numEvents; 102 | ChannelMap::const_iterator ch = m_channels.find(it->data.fd); 103 | assert(ch != m_channels.end()); 104 | Channel* channel = ch->second; 105 | assert(channel->fd() == it->data.fd); 106 | channel->set_revents(it->events); 107 | activeChannels->push_back(channel); 108 | } 109 | } 110 | 111 | 112 | void Epoll::updateChannel(Channel* channel) 113 | { 114 | assertInLoopThread(); 115 | LOG_TRACE << "fd= " << channel->fd() << " events " << channel->events(); 116 | if(channel->index() < 0){ 117 | //a new one , add to epollEvents 118 | assert(m_channels.find(channel->fd()) == m_channels.end()); 119 | struct epoll_event ev; 120 | ev.data.fd = channel->fd(); 121 | ev.events = static_cast(channel->events()); 122 | EventFd::epollRegister(m_epfd, channel->fd(), &ev); 123 | m_maxEventsSize++; 124 | int idx = m_maxEventsSize; //poll used, epoll not have significance, just a tag. 125 | channel->set_index(idx); 126 | m_channels[channel->fd()] = channel; 127 | } 128 | else{ 129 | //update existing one 130 | assert(m_channels.find(channel->fd()) != m_channels.end()); 131 | assert(m_channels[channel->fd()] == channel); 132 | struct epoll_event ev; 133 | ev.data.fd = channel->fd(); 134 | ev.events = static_cast(channel->events()); 135 | EventFd::epollUpdate(m_epfd, channel->fd(), &ev); 136 | } 137 | 138 | if(m_maxEventsSize + 1 == m_epollEvents.capacity()) 139 | { 140 | int size = m_epollEvents.capacity(); 141 | size = std::min(2*size, kMaxEpollConcurrencySize); 142 | m_epollEvents.reserve(size); 143 | } 144 | 145 | } 146 | 147 | 148 | void Epoll::removeChannel(Channel* channel) 149 | { 150 | assertInLoopThread(); 151 | LOG_TRACE << "fd = " << channel->fd(); 152 | assert(m_channels.find(channel->fd()) != m_channels.end()); 153 | assert(m_channels[channel->fd()] == channel); 154 | assert(channel->isNoneEvent()); 155 | struct epoll_event ev; 156 | ev.data.fd = channel->fd(); 157 | LOG_TRACE << "Epoll::removeChannel() fd " << channel->fd() << " events " << channel->events(); 158 | EventFd::epollDelete(m_epfd, channel->fd(), &ev); 159 | size_t n = m_channels.erase(channel->fd()); 160 | assert(n == 1); (void)n; 161 | 162 | m_maxEventsSize--; 163 | } 164 | 165 | 166 | -------------------------------------------------------------------------------- /sources/muduo_network/EventLoop.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "EventLoop.hpp" 8 | #include "Poller.hpp" 9 | #include "Epoll.hpp" 10 | #include "Logger.hpp" 11 | #include "SocketHelp.hpp" 12 | 13 | using namespace muduo; 14 | 15 | __thread EventLoop* t_loopInThisThread = 0; 16 | 17 | const int kPollTimeMs = -1; 18 | 19 | int createEventfd() 20 | { 21 | int evtfd = ::eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); 22 | 23 | LOG_TRACE << "createEventfd() fd : " << evtfd; 24 | 25 | if (evtfd < 0) 26 | { 27 | LOG_SYSERR << "Failed in eventfd"; 28 | abort(); 29 | } 30 | 31 | return evtfd; 32 | } 33 | 34 | EventLoop::EventLoop() 35 | :m_looping(false), 36 | m_threadId(CurrentThread::tid()), 37 | m_poller(new Epoll(this)), 38 | m_timerQueue(new TimerQueue(this)), 39 | m_wakeupFd(createEventfd()), 40 | p_wakeupChannel(new Channel(this, m_wakeupFd)), 41 | m_callingPendingFunctors(false) 42 | { 43 | LOG_INFO << "EventLoop Create " << this << " in thread " << m_threadId; 44 | if(t_loopInThisThread) 45 | { //每个线程只有一个EventLoop对象 , 如果当前线程创建了其他 EventLoop对象,则终止程序. 46 | LOG_FATAL << "Anthor EventLoop " << t_loopInThisThread 47 | << " exists in this thread " << m_threadId; 48 | } 49 | else 50 | { 51 | t_loopInThisThread = this; 52 | } 53 | p_wakeupChannel->setReadCallBack(std::bind(&EventLoop::handleRead, this)); 54 | p_wakeupChannel->enableReading(); 55 | } 56 | 57 | EventLoop::~EventLoop() 58 | { 59 | LOG_TRACE << "EventLoop::~EventLoop()"; 60 | assert(!m_looping); 61 | p_wakeupChannel->disableAll(); 62 | p_wakeupChannel->remove(); 63 | ::close(m_wakeupFd); 64 | t_loopInThisThread = NULL; 65 | } 66 | 67 | void EventLoop::loop() 68 | { 69 | assert(!m_looping); 70 | assertInLoopThread(); 71 | m_quit = false; 72 | m_looping = true; 73 | 74 | LOG_DEBUG << "EventLoop " << this << " start loopig"; 75 | 76 | while(!m_quit) 77 | { 78 | m_activeChannels.clear(); 79 | m_poller->poll(kPollTimeMs, &m_activeChannels); 80 | 81 | printActiveChannels(); 82 | 83 | for(ChannelList::iterator it = m_activeChannels.begin(); 84 | it != m_activeChannels.end(); ++it) 85 | { 86 | (*it)->handleEvent(); 87 | } 88 | doPendingFunctors(); 89 | } 90 | 91 | LOG_DEBUG << "EventLoop " << this << " stop loopig"; 92 | m_looping = false; 93 | 94 | } 95 | 96 | bool EventLoop::isInloopThread() const 97 | { 98 | return m_threadId == CurrentThread::tid(); 99 | } 100 | 101 | void EventLoop::assertInLoopThread() 102 | { 103 | if(!isInloopThread()) 104 | { 105 | abortNotInLoopThread(); 106 | } 107 | } 108 | 109 | void EventLoop::runInLoop(const Functor& cb) 110 | { 111 | if(isInloopThread()) 112 | { 113 | cb(); 114 | } 115 | else 116 | { 117 | queueInLoop(cb); 118 | } 119 | } 120 | 121 | void EventLoop::queueInLoop(const Functor& cb) 122 | { 123 | LOG_TRACE << "EventLoop::queueInLoop()"; 124 | { 125 | std::lock_guard lock(m_mutex); 126 | m_pendingFunctors.push_back(std::move(cb)); 127 | } 128 | 129 | if(!isInloopThread() || m_callingPendingFunctors) 130 | { 131 | wakeup(); 132 | } 133 | } 134 | 135 | void EventLoop::wakeup() 136 | { 137 | uint64_t one = 1; 138 | ssize_t n = sockets::write(m_wakeupFd, &one, sizeof one); 139 | if(n != sizeof one) 140 | { 141 | LOG_ERROR << "EventLoop::wakeup() writes " << n << " bytes instead of 8"; 142 | } 143 | } 144 | 145 | void EventLoop::handleRead() //handle wakeup Fd 146 | { 147 | LOG_TRACE << "EventLoop::handleRead() handle wakeup Fd"; 148 | uint64_t one = 1; 149 | ssize_t n = sockets::read(m_wakeupFd, &one, sizeof one); 150 | if(n != sizeof one) 151 | { 152 | LOG_ERROR << "EventLoop::handleRead() reads " << n << "bytes instead of 8"; 153 | } 154 | } 155 | 156 | void EventLoop::doPendingFunctors() 157 | { 158 | //LOG_TRACE << ""; 159 | std::vector functors; 160 | m_callingPendingFunctors = true; 161 | 162 | { 163 | std::lock_guard lock(m_mutex); 164 | functors.swap(m_pendingFunctors); 165 | } 166 | 167 | for(size_t i = 0; i < functors.size(); ++i) 168 | { 169 | functors[i](); 170 | } 171 | 172 | m_callingPendingFunctors = false; 173 | 174 | } 175 | 176 | void EventLoop::abortNotInLoopThread() 177 | { 178 | LOG_FATAL << "EventLoop::abortNotInLoopThread - EventLoop " << this 179 | << " was created in threadId_ = " << m_threadId 180 | << ", current thread id = " << CurrentThread::tid(); 181 | } 182 | 183 | EventLoop* EventLoop::getEventLoopOfCurrentThread() 184 | { 185 | return t_loopInThisThread; 186 | } 187 | 188 | void EventLoop::quit() 189 | { 190 | LOG_TRACE << "EventLoop::quit()"; 191 | assert(m_looping == true); 192 | 193 | m_quit = true; 194 | 195 | if(!isInloopThread()) 196 | { 197 | wakeup(); 198 | } 199 | } 200 | 201 | void EventLoop::updateChannel(Channel* channel) 202 | { 203 | assert(channel->ownerLoop() == this); 204 | assertInLoopThread(); 205 | m_poller->updateChannel(channel); 206 | } 207 | 208 | void EventLoop::removeChannel(Channel* channel) 209 | { 210 | assert(channel->ownerLoop() == this); 211 | assertInLoopThread(); 212 | if(0) 213 | { 214 | 215 | } 216 | 217 | m_poller->removeChannel(channel); 218 | } 219 | 220 | 221 | TimerId EventLoop::runAt(const TimeStamp& time, const NetCallBacks::TimerCallBack& cb) 222 | { 223 | return m_timerQueue->addTimer(cb, time, 0.0); 224 | } 225 | 226 | TimerId EventLoop::runAfter(double delay, const NetCallBacks::TimerCallBack& cb) 227 | { 228 | TimeStamp time(TimeStamp::addTime(TimeStamp::now(), delay)); 229 | return runAt(time, cb); 230 | } 231 | 232 | TimerId EventLoop::runEvery(double interval, const NetCallBacks::TimerCallBack& cb) 233 | { 234 | TimeStamp time(TimeStamp::addTime(TimeStamp::now(), interval)); 235 | return m_timerQueue->addTimer(cb, time, interval); 236 | } 237 | 238 | void EventLoop::printActiveChannels() const 239 | { 240 | for (ChannelList::const_iterator it = m_activeChannels.begin(); 241 | it != m_activeChannels.end(); ++it) 242 | { 243 | const Channel* ch = *it; 244 | LOG_TRACE << "{" << ch->reventsToString() << "} "; 245 | } 246 | } 247 | -------------------------------------------------------------------------------- /sources/muduo_network/EventLoopThread.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "Logger.hpp" 4 | #include "EventLoop.hpp" 5 | #include "EventLoopThread.hpp" 6 | 7 | using namespace muduo; 8 | 9 | EventLoopThread::EventLoopThread() 10 | :p_loop(NULL), 11 | m_exiting(false), 12 | m_thread(std::bind(&EventLoopThread::threadFunc, this)), 13 | m_mutex(), 14 | m_cond() 15 | { 16 | 17 | } 18 | 19 | EventLoopThread::~EventLoopThread() 20 | { 21 | LOG_TRACE << "EventLoopThread::~EventLoopThread()"; 22 | 23 | m_exiting = true; 24 | if(p_loop != NULL) 25 | { 26 | p_loop->quit(); 27 | m_thread.join(); 28 | } 29 | } 30 | 31 | 32 | EventLoop* EventLoopThread::startLoop() 33 | { 34 | assert(!m_thread.isStarted()); 35 | m_thread.start(); 36 | 37 | { 38 | std::unique_lock lock(m_mutex); 39 | while(p_loop == NULL) 40 | { 41 | LOG_TRACE << "EventLoopThread::startLoop() wait()"; 42 | m_cond.wait(lock); 43 | } 44 | } 45 | 46 | LOG_TRACE << "EventLoopThread::startLoop() wakeup"; 47 | 48 | return p_loop; 49 | } 50 | 51 | 52 | void EventLoopThread::threadFunc() 53 | { 54 | EventLoop loop; 55 | 56 | if(m_threadInitCallBack) 57 | { 58 | m_threadInitCallBack(&loop); 59 | } 60 | 61 | { 62 | std::lock_guard lock(m_mutex); 63 | p_loop = &loop; 64 | m_cond.notify(); 65 | LOG_TRACE << "EventLoopThread::threadFunc() notify()"; 66 | } 67 | 68 | loop.loop(); 69 | 70 | p_loop = NULL; 71 | 72 | } -------------------------------------------------------------------------------- /sources/muduo_network/EventLoopThreadPool.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2010, Shuo Chen. All rights reserved. 2 | // http://code.google.com/p/muduo/ 3 | // 4 | // Use of this source code is governed by a BSD-style license 5 | // that can be found in the License file. 6 | 7 | // Author: Shuo Chen (chenshuo at chenshuo dot com) 8 | 9 | #include "EventLoopThreadPool.hpp" 10 | #include "EventLoop.hpp" 11 | #include "EventLoopThread.hpp" 12 | #include "Logger.hpp" 13 | 14 | #include 15 | 16 | using namespace muduo; 17 | 18 | EventLoopThreadPool::EventLoopThreadPool(EventLoop* baseLoop, const std::string& nameArg, int numThreads) 19 | : m_baseLoop(baseLoop), 20 | m_name(nameArg), 21 | m_started(false), 22 | m_numThreads(numThreads), 23 | m_next(0) 24 | { 25 | } 26 | 27 | EventLoopThreadPool::~EventLoopThreadPool() 28 | { 29 | // Don't delete loop, it's stack variable 30 | } 31 | 32 | void EventLoopThreadPool::start() 33 | { 34 | assert(!m_started); 35 | m_baseLoop->assertInLoopThread(); 36 | 37 | m_started = true; 38 | 39 | for (int i = 0; i < m_numThreads; ++i) 40 | { 41 | char buf[m_name.size() + 32]; 42 | snprintf(buf, sizeof buf, "%s%d", m_name.c_str(), i); 43 | EventLoopThread* t = new EventLoopThread(); 44 | m_threads.push_back(t); 45 | m_loops.push_back(t->startLoop()); 46 | } 47 | 48 | } 49 | 50 | EventLoop* EventLoopThreadPool::getNextLoop() 51 | { 52 | m_baseLoop->assertInLoopThread(); 53 | assert(m_started); 54 | EventLoop* loop = m_baseLoop; 55 | 56 | if (!m_loops.empty()) 57 | { 58 | // round-robin 59 | loop = m_loops[m_next]; 60 | ++m_next; 61 | if (static_cast(m_next) >= m_loops.size()) 62 | { 63 | m_next = 0; 64 | } 65 | } 66 | return loop; 67 | } 68 | 69 | EventLoop* EventLoopThreadPool::getLoopForHash(size_t hashCode) 70 | { 71 | m_baseLoop->assertInLoopThread(); 72 | EventLoop* loop = m_baseLoop; 73 | 74 | if (!m_loops.empty()) 75 | { 76 | loop = m_loops[hashCode % m_loops.size()]; 77 | } 78 | return loop; 79 | } 80 | 81 | std::vector EventLoopThreadPool::getAllLoops() 82 | { 83 | m_baseLoop->assertInLoopThread(); 84 | assert(m_started); 85 | if (m_loops.empty()) 86 | { 87 | return std::vector(1, m_baseLoop); 88 | } 89 | else 90 | { 91 | return m_loops; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /sources/muduo_network/InetAddress.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include // bzero 3 | #include 4 | #include 5 | #include 6 | 7 | #include "InetAddress.hpp" 8 | #include "SocketHelp.hpp" 9 | #include "Endian.hpp" 10 | 11 | 12 | // INADDR_ANY use (type)value casting. 13 | #pragma GCC diagnostic ignored "-Wold-style-cast" 14 | static const in_addr_t kInaddrAny = INADDR_ANY; 15 | static const in_addr_t kInaddrLoopback = INADDR_LOOPBACK; 16 | #pragma GCC diagnostic error "-Wold-style-cast" 17 | 18 | // /* Structure describing an Internet socket address. */ 19 | // struct sockaddr_in { 20 | // sa_family_t sin_family; /* address family: AF_INET */ 21 | // uint16_t sin_port; /* port in network byte order */ 22 | // struct in_addr sin_addr; /* internet address */ 23 | // }; 24 | 25 | // /* Internet address. */ 26 | // typedef uint32_t in_addr_t; 27 | // struct in_addr { 28 | // in_addr_t s_addr; /* address in network byte order */ 29 | // }; 30 | 31 | // struct sockaddr_in6 { 32 | // sa_family_t sin6_family; /* address family: AF_INET6 */ 33 | // uint16_t sin6_port; /* port in network byte order */ 34 | // uint32_t sin6_flowinfo; /* IPv6 flow information */ 35 | // struct in6_addr sin6_addr; /* IPv6 address */ 36 | // uint32_t sin6_scope_id; /* IPv6 scope-id */ 37 | // }; 38 | 39 | InetAddress::InetAddress(uint16_t port, bool loopbackOnly, bool ipv6) 40 | { 41 | assert(offsetof(InetAddress, m_addr6) == 0); 42 | assert(offsetof(InetAddress, m_addr) == 0); 43 | if (ipv6) 44 | { 45 | bzero(&m_addr6, sizeof m_addr6); 46 | m_addr6.sin6_family = AF_INET6; 47 | in6_addr ip = loopbackOnly ? in6addr_loopback : in6addr_any; 48 | m_addr6.sin6_addr = ip; 49 | m_addr6.sin6_port = sockets::hostToNetwork16(port); 50 | } 51 | else 52 | { 53 | bzero(&m_addr, sizeof m_addr); 54 | m_addr.sin_family = AF_INET; 55 | in_addr_t ip = loopbackOnly ? kInaddrLoopback : kInaddrAny; 56 | m_addr.sin_addr.s_addr = sockets::hostToNetwork32(ip); 57 | m_addr.sin_port = sockets::hostToNetwork16(port); 58 | } 59 | } 60 | 61 | InetAddress::InetAddress(std::string ip, uint16_t port, bool ipv6) 62 | { 63 | if(ipv6) { //now no unsed 64 | 65 | } else { 66 | ::bzero(&m_addr, sizeof m_addr); 67 | sockets::fromIpPort(ip.c_str(), port, &m_addr); 68 | } 69 | } 70 | 71 | /*string InetAddress::toIpPort() const 72 | { 73 | char buf[64] = ""; 74 | sockets::toIpPort(buf, sizeof buf, getSockAddr()); 75 | return buf; 76 | } 77 | 78 | string InetAddress::toIp() const 79 | { 80 | char buf[64] = ""; 81 | sockets::toIp(buf, sizeof buf, getSockAddr()); 82 | return buf; 83 | }*/ 84 | 85 | uint32_t InetAddress::ipNetEndian() const 86 | { 87 | assert(family() == AF_INET); 88 | return m_addr.sin_addr.s_addr; 89 | } 90 | 91 | 92 | std::string InetAddress::toIpPort() const 93 | { 94 | char buf[64] = ""; 95 | sockets::toIpPort(buf, sizeof buf, getSockAddr()); 96 | return buf; 97 | } 98 | 99 | std::string InetAddress::toIp() const 100 | { 101 | char buf[64] = ""; 102 | sockets::toIp(buf, sizeof buf, getSockAddr()); 103 | return buf; 104 | } 105 | 106 | uint16_t InetAddress::toPort() const 107 | { 108 | //port net endian 109 | return sockets::networkToHost16(m_addr.sin_port); 110 | } -------------------------------------------------------------------------------- /sources/muduo_network/Poll.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "EventLoop.hpp" 6 | #include "Channel.hpp" 7 | #include "Logger.hpp" 8 | #include "Poll.hpp" 9 | 10 | using namespace muduo; 11 | 12 | Poll::Poll(EventLoop* loop) 13 | : Poller(loop) 14 | { 15 | 16 | } 17 | 18 | Poll::~Poll() 19 | { 20 | 21 | } 22 | 23 | TimeStamp Poll::poll(int timeoutMs, ChannelList* activeChannels) 24 | { 25 | LOG_TRACE << "Poll::poll()"; 26 | int numEvents = ::poll(/*&*m_pollfds.begin()*/m_pollfds.data(), m_pollfds.size(), timeoutMs); 27 | TimeStamp now(TimeStamp::now()); 28 | if(numEvents > 0){ 29 | LOG_TRACE << numEvents << " events happended"; 30 | fillActiveChannels(numEvents, activeChannels); 31 | } 32 | else if(numEvents == 0){ 33 | LOG_TRACE << " nothing happended"; 34 | } 35 | else{ 36 | LOG_SYSERR << "Poll::poll()"; 37 | } 38 | 39 | return now; 40 | } 41 | 42 | /* 43 | *fillActiveChannels()遍历m_pollfds, 找出有活动事件的fd, 把它对应 44 | *的Channel填入activeChannels。 45 | */ 46 | 47 | void Poll::fillActiveChannels(int numEvents, ChannelList* activeChannels) const 48 | { 49 | for(PollFdList::const_iterator pfd = m_pollfds.begin(); 50 | pfd != m_pollfds.end() && numEvents > 0; ++pfd) 51 | { 52 | if(pfd->revents > 0) 53 | { 54 | --numEvents; 55 | ChannelMap::const_iterator ch = m_channels.find(pfd->fd); 56 | assert(ch != m_channels.end()); 57 | Channel* channel = ch->second; 58 | assert(channel->fd() == pfd->fd); 59 | channel->set_revents(pfd->revents); 60 | activeChannels->push_back(channel); 61 | } 62 | } 63 | } 64 | 65 | 66 | void Poll::updateChannel(Channel* channel) 67 | { 68 | assertInLoopThread(); 69 | LOG_TRACE << "fd= " << channel->fd() << " events " << channel->events(); 70 | if(channel->index() < 0){ 71 | //a new one , add to pollfds 72 | assert(m_channels.find(channel->fd()) == m_channels.end()); 73 | struct pollfd pfd; 74 | pfd.fd = channel->fd(); 75 | pfd.events = static_cast(channel->events()); 76 | pfd.revents = 0; 77 | m_pollfds.push_back(pfd); 78 | int idx = static_cast(m_pollfds.size()) - 1; 79 | channel->set_index(idx); 80 | m_channels[pfd.fd] = channel; 81 | 82 | } 83 | else{ 84 | //update existing one 85 | assert(m_channels.find(channel->fd()) != m_channels.end()); 86 | assert(m_channels[channel->fd()] == channel); 87 | int idx = channel->index(); 88 | assert(0 <= idx && idx < static_cast(m_pollfds.size())); 89 | struct pollfd& pfd = m_pollfds[idx]; 90 | assert(pfd.fd == channel->fd() || pfd.fd == -1); 91 | pfd.events = static_cast(channel->events()); 92 | pfd.revents = 0; 93 | if(channel->isNoneEvent()){ 94 | LOG_TRACE << "Poll::updateChannel() Ignore This Pollfd"; 95 | pfd.fd = -1; 96 | } 97 | } 98 | 99 | } 100 | 101 | 102 | void Poll::removeChannel(Channel* channel) 103 | { 104 | assertInLoopThread(); 105 | LOG_TRACE << "fd = " << channel->fd(); 106 | assert(m_channels.find(channel->fd()) != m_channels.end()); 107 | assert(m_channels[channel->fd()] == channel); 108 | assert(channel->isNoneEvent()); 109 | int idx = channel->index(); 110 | assert(0 <= idx && idx < static_cast(m_pollfds.size())); 111 | const struct pollfd& pfd = m_pollfds[idx]; 112 | (void)pfd; 113 | LOG_TRACE << "Poll::removeChannel() idx " << idx << " pfd.fd " << pfd.fd << " pfd.events " << pfd.events; 114 | assert(pfd.fd == - 1 && pfd.events == static_cast(channel->events())); 115 | size_t n = m_channels.erase(channel->fd()); 116 | assert(n == 1); (void)n; 117 | if(static_cast(m_pollfds.size() - 1) == idx) 118 | { 119 | m_pollfds.pop_back(); 120 | } 121 | else 122 | { 123 | int channelAtEnd = m_pollfds.back().fd; 124 | iter_swap(m_pollfds.begin() + idx, m_pollfds.end() - 1); 125 | if(channelAtEnd < 0) 126 | { 127 | channelAtEnd = -channelAtEnd - 1; 128 | } 129 | m_channels[channelAtEnd]->set_index(idx); 130 | m_pollfds.pop_back(); 131 | } 132 | 133 | } 134 | 135 | 136 | -------------------------------------------------------------------------------- /sources/muduo_network/Poller.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "Poller.hpp" 4 | #include "Channel.hpp" 5 | #include "EventLoop.hpp" 6 | 7 | using namespace muduo; 8 | 9 | Poller::Poller(EventLoop* loop) 10 | : p_Loop(loop) 11 | { 12 | } 13 | 14 | Poller::~Poller() 15 | { 16 | } 17 | 18 | bool Poller::hasChannel(Channel* channel) const 19 | { 20 | assertInLoopThread(); 21 | ChannelMap::const_iterator it = m_channels.find(channel->fd()); 22 | return it != m_channels.end() && it->second == channel; 23 | } 24 | 25 | void Poller::assertInLoopThread() const 26 | { 27 | p_Loop->assertInLoopThread(); 28 | } -------------------------------------------------------------------------------- /sources/muduo_network/Socket.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "InetAddress.hpp" 7 | #include "Socket.hpp" 8 | #include "Logger.hpp" 9 | #include "SocketHelp.hpp" 10 | 11 | Socket::~Socket() 12 | { 13 | sockets::close(m_sockfd); 14 | } 15 | 16 | bool Socket::getTcpInfo(struct tcp_info* tcpi) const 17 | { 18 | socklen_t len = sizeof(*tcpi); 19 | bzero(tcpi, len); 20 | return ::getsockopt(m_sockfd, SOL_TCP, TCP_INFO, tcpi, &len) == 0; 21 | } 22 | 23 | bool Socket::getTcpInfoString(char* buf, int len) const 24 | { 25 | struct tcp_info tcpi; 26 | bool ok = getTcpInfo(&tcpi); 27 | if (ok) 28 | { 29 | snprintf(buf, len, "unrecovered=%u " 30 | "rto=%u ato=%u snd_mss=%u rcv_mss=%u " 31 | "lost=%u retrans=%u rtt=%u rttvar=%u " 32 | "sshthresh=%u cwnd=%u total_retrans=%u", 33 | tcpi.tcpi_retransmits, // Number of unrecovered [RTO] timeouts 34 | tcpi.tcpi_rto, // Retransmit timeout in usec 35 | tcpi.tcpi_ato, // Predicted tick of soft clock in usec 36 | tcpi.tcpi_snd_mss, 37 | tcpi.tcpi_rcv_mss, 38 | tcpi.tcpi_lost, // Lost packets 39 | tcpi.tcpi_retrans, // Retransmitted packets out 40 | tcpi.tcpi_rtt, // Smoothed round trip time in usec 41 | tcpi.tcpi_rttvar, // Medium deviation 42 | tcpi.tcpi_snd_ssthresh, 43 | tcpi.tcpi_snd_cwnd, 44 | tcpi.tcpi_total_retrans); // Total retransmits for entire connection 45 | } 46 | return ok; 47 | } 48 | 49 | void Socket::bindAddress(const InetAddress& addr) 50 | { 51 | sockets::bindOrDie(m_sockfd, addr.getSockAddr()); 52 | } 53 | 54 | void Socket::listen() 55 | { 56 | sockets::listenOrDie(m_sockfd); 57 | } 58 | 59 | int Socket::accept(InetAddress* peeraddr) 60 | { 61 | struct sockaddr_in6 addr; 62 | bzero(&addr, sizeof addr); 63 | int connfd = sockets::accept(m_sockfd, &addr); 64 | if(connfd >= 0) 65 | { 66 | peeraddr->setSockAddrInet6(addr); 67 | } 68 | return connfd; 69 | } 70 | 71 | void Socket::shutdownWrite() 72 | { 73 | sockets::shutdownWrite(m_sockfd); 74 | } 75 | 76 | void Socket::setTcpNoDelay(bool on) 77 | { 78 | int optval = on ? 1 : 0; 79 | int ret = ::setsockopt(m_sockfd, IPPROTO_TCP, TCP_NODELAY, &optval, static_cast(sizeof optval)); 80 | if(ret < 0) 81 | { 82 | LOG_SYSERR << "Socket::setTcpNoDelay"; 83 | } 84 | } 85 | 86 | void Socket::setReuseAddr(bool on) 87 | { 88 | int optval = on ? 1 : 0; 89 | int ret = ::setsockopt(m_sockfd, SOL_SOCKET, SO_REUSEADDR, 90 | &optval, static_cast(sizeof optval)); 91 | if(ret < 0) 92 | { 93 | LOG_SYSERR << "Socket::setReuseAddr"; 94 | } 95 | } 96 | 97 | void Socket::setReusePort(bool on) 98 | { 99 | #ifdef SO_REUSEPORT 100 | int optval = on ? 1 : 0; 101 | int ret = ::setsockopt(m_sockfd, SOL_SOCKET, SO_REUSEPORT, 102 | &optval, static_cast(sizeof optval)); 103 | if (ret < 0 && on) 104 | { 105 | LOG_SYSERR << "SO_REUSEPORT failed."; 106 | } 107 | #else 108 | if (on) 109 | { 110 | LOG_ERROR << "SO_REUSEPORT is not supported."; 111 | } 112 | #endif 113 | } 114 | 115 | void Socket::setKeepAlive(bool on) 116 | { 117 | int optval = on ? 1 : 0; 118 | int ret = ::setsockopt(m_sockfd, SOL_SOCKET, SO_KEEPALIVE, 119 | &optval, static_cast(sizeof optval)); 120 | 121 | int keepidle = 30; // 如该连接在60秒内没有任何数据往来,则进行探测 122 | int keepinterval = 5; // 探测时发包的时间间隔为5 秒 123 | int keepcount = 3; // 探测尝试的次数.如果第1次探测包就收到响应了,则后2次的不再发. 124 | setsockopt(m_sockfd, SOL_TCP, TCP_KEEPIDLE, (void*)&keepidle , sizeof(keepidle)); 125 | setsockopt(m_sockfd, SOL_TCP, TCP_KEEPINTVL, (void *)&keepinterval , sizeof(keepinterval)); 126 | setsockopt(m_sockfd, SOL_TCP, TCP_KEEPCNT, (void *)&keepcount , sizeof(keepcount)); 127 | 128 | if(ret < 0) 129 | { 130 | LOG_SYSERR << "Socket::setKeepAlive"; 131 | } 132 | } -------------------------------------------------------------------------------- /sources/muduo_network/SocketHelp.cpp: -------------------------------------------------------------------------------- 1 | #include "SocketHelp.hpp" 2 | #include "Logger.hpp" 3 | #include "Endian.hpp" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include // readv 9 | 10 | int sockets::createSocket(sa_family_t family){ 11 | // Call "socket()" to create a (family) socket of the specified type. 12 | // But also set it to have the 'close on exec' property (if we can) 13 | 14 | int sock; 15 | 16 | //CLOEXEC,即当调用exec()函数成功后,文件描述符会自动关闭。 17 | //在以往的内核版本(2.6.23以前)中,需要调用 fcntl(fd, F_SETFD, FD_CLOEXEC) 来设置这个属性。 18 | //而新版本(2.6.23开始)中,可以在调用open函数的时候,通过 flags 参数设置 CLOEXEC 功能, 19 | #ifdef SOCK_CLOEXEC 20 | sock = socket(family, SOCK_STREAM|SOCK_CLOEXEC, 0); 21 | if (sock != -1 || errno != EINVAL) return sock; 22 | // An "errno" of EINVAL likely means that the system wasn't happy with the SOCK_CLOEXEC; fall through and try again without it: 23 | #endif 24 | 25 | sock = socket(family, SOCK_STREAM, 0); 26 | 27 | #ifdef FD_CLOEXEC 28 | if (sock != -1) fcntl(sock, F_SETFD, FD_CLOEXEC); 29 | #endif 30 | return sock; 31 | } 32 | 33 | int sockets::connect(int sockfd, const struct sockaddr* addr) 34 | { 35 | return ::connect(sockfd, addr, sizeof(struct sockaddr)); 36 | } 37 | 38 | void sockets::fromIpPort(const char* ip, uint16_t port, 39 | struct sockaddr_in* addr) 40 | { 41 | addr->sin_family = AF_INET; 42 | addr->sin_port = hostToNetwork16(port); 43 | if (::inet_pton(AF_INET, ip, &addr->sin_addr) <= 0) 44 | { 45 | LOG_SYSERR << "sockets::fromIpPort"; 46 | } 47 | } 48 | 49 | ssize_t sockets::read(int sockfd, void *buf, size_t count) 50 | { 51 | return ::read(sockfd, buf, count); 52 | } 53 | 54 | ssize_t sockets::readv(int sockfd, const struct iovec *iov, int iovcnt) 55 | { 56 | return ::readv(sockfd, iov, iovcnt); 57 | } 58 | 59 | ssize_t sockets::write(int sockfd, const void *buf, size_t count) 60 | { 61 | return ::write(sockfd, buf, count); 62 | } 63 | 64 | void sockets::close(int sockfd) 65 | { 66 | if (::close(sockfd) < 0) 67 | { 68 | LOG_SYSERR << "sockets::close"; 69 | } 70 | } 71 | 72 | void sockets::shutdownWrite(int sockfd) 73 | { 74 | if(::shutdown(sockfd, SHUT_WR) < 0) 75 | { 76 | LOG_SYSERR << "sockets::shutdownWrite"; 77 | } 78 | } 79 | 80 | void sockets::delaySecond(int sec) 81 | { 82 | struct timeval tv; 83 | tv.tv_sec = sec; 84 | tv.tv_usec = 0; 85 | select(0, NULL, NULL, NULL, &tv); 86 | } 87 | 88 | int sockets::createNonblockingOrDie(sa_family_t family) 89 | { 90 | int sockfd = ::socket(family, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, IPPROTO_TCP); 91 | if (sockfd < 0) 92 | { 93 | LOG_SYSFATAL << "sockets::createNonblockingOrDie"; 94 | } 95 | 96 | return sockfd; 97 | } 98 | 99 | void sockets::bindOrDie(int sockfd, const struct sockaddr* addr) 100 | { 101 | int ret = ::bind(sockfd, addr, static_cast(sizeof(struct sockaddr))); 102 | if(ret < 0) 103 | { 104 | LOG_SYSFATAL << "sockets::bindOrDie"; 105 | } 106 | } 107 | 108 | void sockets::listenOrDie(int sockfd) 109 | { 110 | int ret = ::listen(sockfd, SOMAXCONN); 111 | if(ret < 0) 112 | { 113 | LOG_SYSFATAL << "sockets::listenOrDie"; 114 | } 115 | } 116 | 117 | int sockets::accept(int sockfd, struct sockaddr_in6* addr) 118 | { 119 | socklen_t addrlen = static_cast(sizeof *addr); 120 | #if defined (NO_ACCEPT4) 121 | int connfd = ::accept(sockfd, (struct sockaddr *)(addr), &addrlen); 122 | setNonBlockAndCloseOnExec(connfd); 123 | #else 124 | int connfd = ::accept4(sockfd, (struct sockaddr *)(addr), 125 | &addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC); 126 | #endif 127 | if (connfd < 0) 128 | { 129 | int savedErrno = errno; 130 | LOG_SYSERR << "Socket::accept"; 131 | switch (savedErrno) 132 | { 133 | case EAGAIN: 134 | case ECONNABORTED: 135 | case EINTR: 136 | case EPROTO: // ??? 137 | case EPERM: 138 | case EMFILE: // per-process lmit of open file desctiptor ??? 139 | // expected errors 140 | errno = savedErrno; 141 | break; 142 | case EBADF: 143 | case EFAULT: 144 | case EINVAL: 145 | case ENFILE: 146 | case ENOBUFS: 147 | case ENOMEM: 148 | case ENOTSOCK: 149 | case EOPNOTSUPP: 150 | // unexpected errors 151 | LOG_FATAL << "unexpected error of ::accept " << savedErrno; 152 | break; 153 | default: 154 | LOG_FATAL << "unknown error of ::accept " << savedErrno; 155 | break; 156 | } 157 | } 158 | return connfd; 159 | } 160 | 161 | void sockets::toIpPort(char* buf, size_t size, 162 | const struct sockaddr* addr) 163 | { 164 | toIp(buf, size, addr); 165 | size_t end = ::strlen(buf); 166 | const struct sockaddr_in* addr4 = (const struct sockaddr_in* )(addr); 167 | uint16_t port = sockets::networkToHost16(addr4->sin_port); 168 | assert(size > end); 169 | snprintf(buf+end, size-end, ":%u", port); 170 | } 171 | 172 | void sockets::toIp(char* buf, size_t size, 173 | const struct sockaddr* addr) 174 | { 175 | if (addr->sa_family == AF_INET) 176 | { 177 | assert(size >= INET_ADDRSTRLEN); 178 | const struct sockaddr_in* addr4 = (const struct sockaddr_in* )(addr); 179 | ::inet_ntop(AF_INET, &addr4->sin_addr, buf, static_cast(size)); 180 | } 181 | else if (addr->sa_family == AF_INET6) 182 | { 183 | assert(size >= INET6_ADDRSTRLEN); 184 | const struct sockaddr_in6* addr6 = (const struct sockaddr_in6* )(addr); 185 | ::inet_ntop(AF_INET6, &addr6->sin6_addr, buf, static_cast(size)); 186 | } 187 | } 188 | 189 | struct sockaddr_in6 sockets::getLocalAddr(int sockfd) 190 | { 191 | struct sockaddr_in6 localaddr; 192 | ::bzero(&localaddr, sizeof localaddr); 193 | socklen_t addrlen = static_cast(sizeof localaddr); 194 | if(::getsockname(sockfd, reinterpret_cast(&localaddr), &addrlen) < 0) 195 | { 196 | LOG_SYSERR << "sockets::getLocalAddr"; 197 | } 198 | 199 | return localaddr; 200 | } 201 | 202 | struct sockaddr_in6 sockets::getPeerAddr(int sockfd) 203 | { 204 | struct sockaddr_in6 peeraddr; 205 | bzero(&peeraddr, sizeof peeraddr); 206 | socklen_t addrlen = static_cast(sizeof peeraddr); 207 | if (::getpeername(sockfd, reinterpret_cast(&peeraddr), &addrlen) < 0) 208 | { 209 | LOG_SYSERR << "sockets::getPeerAddr"; 210 | } 211 | return peeraddr; 212 | } 213 | 214 | int sockets::getSocketError(int sockfd) 215 | { 216 | int optval; 217 | 218 | socklen_t optlen = static_cast(sizeof optval); 219 | 220 | if(::getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, &optlen) < 0) 221 | { 222 | return errno; 223 | } 224 | else 225 | { 226 | return optval; 227 | } 228 | } 229 | 230 | /* 231 | const struct sockaddr* sockets::sockaddr_cast(const struct sockaddr_in* addr) 232 | { 233 | return static_cast(implicit_cast(addr)); 234 | } 235 | */ 236 | -------------------------------------------------------------------------------- /sources/muduo_network/TcpConnection.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "TcpConnection.hpp" 4 | #include "EventLoop.hpp" 5 | #include "Logger.hpp" 6 | #include "SocketHelp.hpp" 7 | 8 | using namespace muduo; 9 | 10 | TcpConnection::TcpConnection(EventLoop* loop, 11 | const std::string& name, 12 | int sockfd, 13 | const InetAddress& localAddr, 14 | const InetAddress& peerAddr) 15 | :p_loop(loop), 16 | m_name(name), 17 | m_state(kConnecting), 18 | p_socket(new Socket(sockfd)), 19 | p_channel(new Channel(p_loop, sockfd)), 20 | m_localAddr(localAddr), 21 | m_peerAddr(peerAddr) 22 | { 23 | 24 | p_channel->setReadCallBack(std::bind(&TcpConnection::handleRead, this)); 25 | p_channel->setCloseCallBack(std::bind(&TcpConnection::handleClose, this)); 26 | 27 | LOG_DEBUG << "TcpConnection::ctor[" << m_name << "] at " << this 28 | << " fd=" << sockfd; 29 | 30 | p_socket->setKeepAlive(true); 31 | //connectEstablished(); do not in Constructor call shared_from_this(); 32 | } 33 | 34 | TcpConnection::~TcpConnection() 35 | { 36 | LOG_DEBUG << "TcpConnection::dtor[" << m_name << "] at " 37 | << this << " fd=" << p_channel->fd() 38 | << " state=" << stateToString(); 39 | 40 | assert(m_state == kDisConnected); 41 | 42 | } 43 | 44 | void TcpConnection::connectEstablished() 45 | { 46 | LOG_TRACE << "TcpConnection::connectEstablished()"; 47 | p_loop->assertInLoopThread(); 48 | assert(m_state == kConnecting); 49 | setState(kConnected); 50 | 51 | p_channel->enableReading(); 52 | 53 | LOG_TRACE << m_localAddr.toIpPort() << " -> " 54 | << m_peerAddr.toIpPort() << " is " 55 | << (isConnected() ? "UP" : "DOWN"); 56 | 57 | if(m_connectionCallBack) m_connectionCallBack(shared_from_this()); 58 | 59 | } 60 | 61 | void TcpConnection::send(const void* message, size_t len) 62 | { 63 | if(m_state == kConnected) 64 | { 65 | if(p_loop->isInloopThread()) 66 | { 67 | sendInLoop(message, len); 68 | } 69 | else 70 | { 71 | p_loop->runInLoop(std::bind(&TcpConnection::sendInLoop, this, message, len)); 72 | } 73 | } 74 | } 75 | 76 | void TcpConnection::send(const std::string& message) 77 | { 78 | if(m_state == kConnected) 79 | { 80 | if(p_loop->isInloopThread()) 81 | { 82 | sendInLoop(message.data(), message.size()); 83 | } 84 | else 85 | { 86 | p_loop->runInLoop(std::bind(&TcpConnection::sendInLoop, this, message.data(), message.size())); 87 | } 88 | } 89 | } 90 | 91 | void TcpConnection::send(Buffer* message) 92 | { 93 | if(m_state == kConnected) 94 | { 95 | if(p_loop->isInloopThread()) 96 | { 97 | sendInLoop(message->peek(), message->readableBytes()); 98 | message->retrieveAll(); 99 | } 100 | else 101 | { 102 | p_loop->runInLoop(std::bind(&TcpConnection::sendInLoop, this, message->peek(), message->readableBytes())); 103 | message->retrieveAll(); 104 | } 105 | } 106 | } 107 | 108 | void TcpConnection::sendInLoop(const void* data, size_t len) 109 | { 110 | p_loop->assertInLoopThread(); 111 | ssize_t nwrote = 0; 112 | size_t remaining = len; 113 | bool faultError = false; 114 | 115 | if(m_state == kDisConnected) 116 | { 117 | LOG_WARN << "disconnected, give up writing."; 118 | return ; 119 | } 120 | 121 | //if nothing in output Buffer, try writing directly. 122 | if(!p_channel->isWriting() && m_outputBuffer.readableBytes() == 0) 123 | { 124 | nwrote = sockets::write(p_channel->fd(), data, len); 125 | if(nwrote >= 0) 126 | { 127 | remaining = len - nwrote; 128 | if(remaining == 0 )//&& m_writeCompleteCallBack) 129 | { 130 | LOG_TRACE << "TcpConnection::sendInLoop() writeCompleteCallBack()"; 131 | //fixd need 132 | //p_loop->queueInLoop(std::bind()) 133 | } 134 | } 135 | else // nwrote < 0 136 | { 137 | nwrote = 0; 138 | if(errno != EWOULDBLOCK) // EAGIN 139 | { 140 | LOG_SYSERR << "TcpConnection::sendInLoop()"; 141 | if(errno == EPIPE || errno == ECONNRESET) 142 | { 143 | faultError = true; 144 | } 145 | } 146 | } 147 | } 148 | 149 | assert(remaining <= len); 150 | if(!faultError && remaining > 0) 151 | { 152 | /*size_t oldLen = m_outputBuffer.readableBytes(); 153 | if(oldLen + remaining >= ) 154 | { 155 | //fixd need 156 | }*/ 157 | 158 | m_outputBuffer.append(static_cast(data) + nwrote, remaining); 159 | if(!p_channel->isWriting()) 160 | { 161 | p_channel->enableWriting(); 162 | } 163 | } 164 | } 165 | 166 | void TcpConnection::shutdown() 167 | { 168 | if(m_state == kConnected) 169 | { 170 | setState(kDisConnecting); 171 | p_loop->runInLoop(std::bind(&TcpConnection::shutdownInLoop, this)); 172 | } 173 | } 174 | 175 | void TcpConnection::shutdownInLoop() 176 | { 177 | p_loop->assertInLoopThread(); 178 | if(!p_channel->isWriting()) 179 | { 180 | p_socket->shutdownWrite(); 181 | } 182 | } 183 | 184 | 185 | void TcpConnection::handleRead() 186 | { 187 | //LOG_TRACE << "TcpConnection::handleRead()"; 188 | 189 | int savedErrno = 0; 190 | 191 | ssize_t n = m_inputBuffer.readFd(p_channel->fd(), &savedErrno); 192 | if(n > 0){ 193 | m_messageCallBack(shared_from_this(), &m_inputBuffer, n); 194 | } 195 | else if ( n==0 ){ 196 | handleClose(); 197 | } 198 | else 199 | { 200 | errno = savedErrno; 201 | LOG_SYSERR << "TcpConnection::handleRead()"; 202 | handleError(); 203 | } 204 | } 205 | 206 | void TcpConnection::handleWrite() 207 | { 208 | LOG_TRACE << "TcpConnection::handleWrite()"; 209 | p_loop->assertInLoopThread(); 210 | if(p_channel->isWriting()) 211 | { 212 | ssize_t n = sockets::write(p_channel->fd(), m_outputBuffer.peek(), m_outputBuffer.readableBytes()); 213 | 214 | if(n > 0) 215 | { 216 | m_outputBuffer.retrieve(n); 217 | if(m_outputBuffer.readableBytes() == 0) 218 | { 219 | p_channel->disableWriting(); 220 | if(0)//m_writeCompleteCallback) 221 | { 222 | 223 | } 224 | if(0)//m_state == kDisConnecting) 225 | { 226 | 227 | } 228 | } 229 | else 230 | { 231 | LOG_SYSERR << "TcpConnection::handleWrite"; 232 | } 233 | } 234 | } 235 | else 236 | { 237 | LOG_ERROR << "Connection fd = " << p_channel->fd() 238 | << " is down, no more writing"; 239 | } 240 | } 241 | 242 | void TcpConnection::handleError() 243 | { 244 | int err = sockets::getSocketError(p_channel->fd()); 245 | LOG_ERROR << "TcpConnection::handleError [" << m_name 246 | << "] - SO_ERROR = " << err << " " << strerror_tl(err); 247 | } 248 | 249 | void TcpConnection::handleClose() 250 | { 251 | LOG_TRACE << "TcpConnection::handleClose()"; 252 | p_loop->assertInLoopThread(); 253 | LOG_TRACE << "fd = " << p_channel->fd() << " state = " << stateToString(); 254 | assert(m_state == kConnected || m_state == kDisConnecting); 255 | 256 | setState(kDisConnected); 257 | p_channel->disableAll(); 258 | 259 | TcpConnectionPtr guardThis(shared_from_this()); 260 | //LOG_TRACE << "trace conn use " << name() << " used count " << guardThis.use_count(); 261 | 262 | m_closeCallBack(guardThis); // to Tcpserver ConnSet resource. 263 | //LOG_TRACE << "trace conn use " << name() << " used count " << guardThis.use_count(); 264 | 265 | } 266 | 267 | void TcpConnection::connectDestroyed() 268 | { 269 | LOG_TRACE << "TcpConnection::connectDestroyed()"; 270 | p_loop->assertInLoopThread(); 271 | 272 | if (m_state == kConnected) 273 | { 274 | setState(kDisConnected); 275 | p_channel->disableAll(); 276 | 277 | LOG_TRACE << m_localAddr.toIpPort() << " -> " 278 | << m_peerAddr.toIpPort() << " is " 279 | << (isConnected() ? "UP" : "DOWN"); 280 | } 281 | 282 | p_channel->remove(); 283 | } 284 | 285 | void TcpConnection::forceClose() 286 | { 287 | LOG_TRACE << "TcpConnection::forceClose()"; 288 | // FIXME: use compare and swap 289 | if (m_state == kConnected || m_state == kDisConnecting) 290 | { 291 | setState(kDisConnecting); 292 | p_loop->queueInLoop(std::bind(&TcpConnection::forceCloseInLoop, shared_from_this())); 293 | } 294 | } 295 | 296 | void TcpConnection::forceCloseInLoop() 297 | { 298 | p_loop->assertInLoopThread(); 299 | if (m_state == kConnected || m_state == kDisConnecting) 300 | { 301 | // as if we received 0 byte in handleRead(); 302 | handleClose(); 303 | } 304 | } 305 | 306 | const char* TcpConnection::stateToString() const 307 | { 308 | switch (m_state) 309 | { 310 | case kDisConnected: 311 | return "kDisConnected"; 312 | case kConnecting: 313 | return "kConnecting"; 314 | case kConnected: 315 | return "kConnected"; 316 | case kDisConnecting: 317 | return "kDisConnecting"; 318 | default: 319 | return "Unknown State"; 320 | } 321 | } -------------------------------------------------------------------------------- /sources/muduo_network/TcpServer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "Acceptor.hpp" 4 | #include "TcpServer.hpp" 5 | #include "EventLoop.hpp" 6 | #include "Logger.hpp" 7 | #include "SocketHelp.hpp" 8 | 9 | using namespace muduo; 10 | 11 | std::unique_ptr muduo::ex_event_loop_thread_pool = nullptr; 12 | 13 | void NetCallBacks::defaultConnectionCallback() 14 | { 15 | LOG_TRACE << "defaultConnectionCallback "; 16 | } 17 | 18 | TcpServer::TcpServer(EventLoop* loop, const InetAddress& listenAddr, const std::string& name) 19 | :p_loop(loop), 20 | m_name(name), 21 | p_acceptor(new Acceptor(loop, listenAddr)), 22 | m_nextConnId(1) 23 | { 24 | p_acceptor->setNewConnectionCallBack( 25 | std::bind(&TcpServer::newConnetion, this, std::placeholders::_1, std::placeholders::_2)); 26 | 27 | } 28 | 29 | TcpServer::~TcpServer() 30 | { 31 | 32 | } 33 | 34 | void TcpServer::start() 35 | { 36 | assert(!p_acceptor->listenning()); 37 | p_loop->runInLoop( 38 | std::bind(&Acceptor::listen, p_acceptor.get())); 39 | } 40 | 41 | 42 | void TcpServer::newConnetion(int sockfd, const InetAddress& peerAddr) 43 | { 44 | LOG_TRACE << "TcpServer::newConnetion() "; 45 | p_loop->assertInLoopThread(); 46 | 47 | char buf[64]; 48 | snprintf(buf, sizeof buf, "#%d", m_nextConnId); 49 | ++m_nextConnId; 50 | std::string connName = m_name + buf; 51 | 52 | LOG_INFO << "TcpServer::newConnetion() [" << m_name 53 | << "] - new connection [" << connName 54 | << "] from " << peerAddr.toIpPort(); 55 | 56 | InetAddress localAddr(sockets::getLocalAddr(sockfd)); 57 | 58 | if(ex_event_loop_thread_pool){ 59 | EventLoop* loop; 60 | loop = ex_event_loop_thread_pool->getNextLoop(); 61 | LOG_INFO << "Loop " << loop; 62 | TcpConnectionPtr conn(new TcpConnection(loop, 63 | connName, sockfd, localAddr, peerAddr)); 64 | //m_connectionsMap[connName] = conn; 65 | m_connectionsSet.insert(conn); 66 | conn->setConnectionCallBack(m_connectionCallBack); 67 | conn->setMessageCallBack(m_messageCallBack); 68 | conn->setCloseCallBack(std::bind(&TcpServer::removeConnection, this, std::placeholders::_1)); 69 | loop->runInLoop(std::bind(&TcpConnection::connectEstablished, conn)); 70 | }else{ 71 | TcpConnectionPtr conn(new TcpConnection(p_loop, 72 | connName, sockfd, localAddr, peerAddr)); 73 | //m_connectionsMap[connName] = conn; 74 | m_connectionsSet.insert(conn); 75 | conn->setConnectionCallBack(m_connectionCallBack); 76 | conn->setMessageCallBack(m_messageCallBack); 77 | conn->setCloseCallBack(std::bind(&TcpServer::removeConnection, this, std::placeholders::_1)); 78 | conn->connectEstablished(); 79 | } 80 | 81 | } 82 | 83 | void TcpServer::removeConnection(const TcpConnectionPtr& conn) 84 | { 85 | // FIXME: unsafe 86 | //LOG_TRACE << "trace conn use " << conn->name() << " used count " << conn.use_count(); 87 | p_loop->runInLoop(std::bind(&TcpServer::removeConnectionInLoop, this, conn)); 88 | //LOG_TRACE << "trace conn use " << conn->name() << " used count " << conn.use_count(); 89 | 90 | } 91 | 92 | void TcpServer::removeConnectionInLoop(const TcpConnectionPtr& conn) 93 | { 94 | p_loop->assertInLoopThread(); 95 | LOG_INFO << "TcpServer::removeConnectionInLoop [" << m_name 96 | << "] - connection " << conn->name(); 97 | 98 | //LOG_TRACE << "trace conn use " << conn->name() << " used count " << conn.use_count(); 99 | size_t n = m_connectionsSet.erase(conn); 100 | (void)n; 101 | assert(n == 1); 102 | //LOG_TRACE << "trace conn use " << conn->name() << " used count " << conn.use_count(); 103 | 104 | if(m_closeCallBack){ 105 | m_closeCallBack(conn); 106 | } 107 | 108 | //LOG_TRACE << "trace conn use " << conn->name() << " used count " << conn.use_count(); 109 | 110 | //assert(conn.use_count() == 2); 111 | 112 | EventLoop* ioLoop = conn->getLoop(); 113 | ioLoop->queueInLoop(//´ËʱµÄConnΪ×îºóÒ»¸öshared_ptr.À뿪×÷ÓÃÓÚºóÎö¹¹´ËTcpConnection. 114 | std::bind(&TcpConnection::connectDestroyed, conn)); 115 | } 116 | -------------------------------------------------------------------------------- /sources/muduo_network/Timer.cpp: -------------------------------------------------------------------------------- 1 | #include "Timer.hpp" 2 | 3 | using namespace muduo; 4 | 5 | AtomicInt64 Timer::s_numCreated; 6 | 7 | void Timer::restart(TimeStamp now) 8 | { 9 | if(m_repeat) 10 | { 11 | m_expiration = TimeStamp::addTime(now, m_interval); 12 | } 13 | else 14 | { 15 | m_expiration = TimeStamp::invalid(); 16 | } 17 | 18 | } -------------------------------------------------------------------------------- /sources/muduo_network/TimerQueue.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "Logger.hpp" 7 | #include "EventLoop.hpp" 8 | #include "Timer.hpp" 9 | #include "TimerQueue.hpp" 10 | 11 | using namespace muduo; 12 | 13 | namespace TimerFd 14 | { 15 | 16 | int createTimerfd() 17 | { 18 | int timerfd = ::timerfd_create(CLOCK_MONOTONIC, 19 | TFD_NONBLOCK | TFD_CLOEXEC); 20 | LOG_TRACE << "createTimerfd() fd : " << timerfd; 21 | if (timerfd < 0) 22 | { 23 | LOG_SYSFATAL << "Failed in timerfd_create"; 24 | } 25 | return timerfd; 26 | } 27 | 28 | struct timespec howMuchTimeFromNow(TimeStamp when) 29 | { 30 | int64_t microseconds = when.microSecondsSinceEpoch() 31 | - TimeStamp::now().microSecondsSinceEpoch(); 32 | if (microseconds < 100) 33 | { 34 | microseconds = 100; 35 | } 36 | struct timespec ts; 37 | ts.tv_sec = static_cast( 38 | microseconds / TimeStamp::kMicroSecondsPerSecond); 39 | ts.tv_nsec = static_cast( 40 | (microseconds % TimeStamp::kMicroSecondsPerSecond) * 1000); 41 | return ts; 42 | } 43 | 44 | void readTimerfd(int timerfd, TimeStamp now) 45 | { 46 | uint64_t howmany; 47 | ssize_t n = ::read(timerfd, &howmany, sizeof howmany); 48 | LOG_TRACE << "TimerQueue::handleRead() " << howmany << " at " << now.toString(); 49 | if (n != sizeof howmany) 50 | { 51 | LOG_ERROR << "TimerQueue::handleRead() reads " << n << " bytes instead of 8"; 52 | } 53 | } 54 | 55 | void resetTimerfd(int timerfd, TimeStamp expiration) 56 | { 57 | // wake up loop by timerfd_settime() 58 | LOG_TRACE << "resetTimerfd()"; 59 | struct itimerspec newValue; 60 | struct itimerspec oldValue; 61 | bzero(&newValue, sizeof newValue); 62 | bzero(&oldValue, sizeof oldValue); 63 | newValue.it_value = howMuchTimeFromNow(expiration); 64 | int ret = ::timerfd_settime(timerfd, 0, &newValue, &oldValue); 65 | if (ret) 66 | { 67 | LOG_SYSERR << "timerfd_settime()"; 68 | } 69 | } 70 | 71 | }; 72 | 73 | using namespace TimerFd; 74 | 75 | TimerQueue::TimerQueue(EventLoop* loop) 76 | :p_loop(loop), 77 | m_timerfd(createTimerfd()), 78 | m_timerfdChannel(p_loop, m_timerfd), 79 | m_timers(), 80 | m_callingExpiredTimers(false) 81 | { 82 | m_timerfdChannel.setReadCallBack(std::bind(&TimerQueue::handleRead, this)); 83 | m_timerfdChannel.enableReading(); 84 | } 85 | 86 | TimerQueue::~TimerQueue() 87 | { 88 | m_timerfdChannel.disableAll(); 89 | m_timerfdChannel.remove(); 90 | ::close(m_timerfd); 91 | for (TimerList::iterator it = m_timers.begin(); 92 | it != m_timers.end(); ++it) 93 | { 94 | delete it->second; 95 | } 96 | } 97 | 98 | std::vector TimerQueue::getExpired(TimeStamp now) 99 | { 100 | std::vector expired; 101 | Entry sentry = std::make_pair(now, reinterpret_castUINTPTR_MAX); 102 | TimerList::iterator it = m_timers.lower_bound(sentry); 103 | assert(it == m_timers.end() || now < it->first); 104 | std::copy(m_timers.begin(), it, back_inserter(expired)); 105 | m_timers.erase(m_timers.begin(), it); 106 | 107 | for(std::vector::iterator it = expired.begin(); 108 | it != expired.end(); ++it) 109 | { 110 | ActiveTimer timer(it->second, it->second->sequence()); 111 | size_t n = m_activeTimers.erase(timer); 112 | assert(n == 1); (void)n; 113 | } 114 | 115 | assert(m_timers.size() == m_activeTimers.size()); 116 | 117 | return expired; 118 | } 119 | 120 | 121 | TimerId TimerQueue::addTimer(const NetCallBacks::TimerCallBack& cb, TimeStamp when, double interval) 122 | { 123 | Timer* timer = new Timer(cb, when, interval); 124 | p_loop->runInLoop(std::bind(&TimerQueue::addTimerInLoop, this, timer)); 125 | return TimerId(timer, timer->sequence()); 126 | } 127 | 128 | void TimerQueue::addTimerInLoop(Timer* timer) 129 | { 130 | p_loop->assertInLoopThread(); 131 | bool earliestChanged = insert(timer); 132 | 133 | if (earliestChanged) 134 | { 135 | resetTimerfd(m_timerfd, timer->expiration()); 136 | } 137 | } 138 | 139 | void TimerQueue::cancel(TimerId timerId) 140 | { 141 | p_loop->runInLoop(std::bind(&TimerQueue::cancelInLoop, this, timerId)); 142 | } 143 | 144 | void TimerQueue::cancelInLoop(TimerId timerId) 145 | { 146 | p_loop->assertInLoopThread(); 147 | assert(m_timers.size() == m_activeTimers.size()); 148 | ActiveTimer timer(timerId.m_timer, timerId.m_sequence); 149 | ActiveTimerSet::iterator it = m_activeTimers.find(timer); 150 | if(it != m_activeTimers.end()) 151 | { 152 | size_t n = m_timers.erase(Entry(it->first->expiration(), it->first)); 153 | assert(n == 1); 154 | delete it->first; 155 | } 156 | else if (m_callingExpiredTimers) 157 | { 158 | m_cancelingTimers.insert(timer); 159 | } 160 | assert(m_timers.size() == m_activeTimers.size()); 161 | } 162 | 163 | bool TimerQueue::insert(Timer* timer) 164 | { 165 | p_loop->assertInLoopThread(); 166 | assert(m_timers.size() == m_activeTimers.size()); 167 | bool earliestChanged = false; 168 | TimeStamp when = timer->expiration(); 169 | TimerList::iterator it = m_timers.begin(); 170 | if (it == m_timers.end() || when < it->first) 171 | { 172 | earliestChanged = true; 173 | } 174 | { 175 | std::pair result 176 | = m_timers.insert(Entry(when, timer)); 177 | assert(result.second); (void)result; 178 | } 179 | { 180 | std::pair result 181 | = m_activeTimers.insert(ActiveTimer(timer, timer->sequence())); 182 | assert(result.second); (void)result; 183 | } 184 | 185 | LOG_TRACE << "TimerQueue::insert() " << "m_timers.size() : " 186 | << m_timers.size() << " m_activeTimers.size() : " << m_activeTimers.size(); 187 | 188 | assert(m_timers.size() == m_activeTimers.size()); 189 | return earliestChanged; 190 | } 191 | 192 | 193 | void TimerQueue::handleRead() 194 | { 195 | p_loop->assertInLoopThread(); 196 | TimeStamp now(TimeStamp::now()); 197 | readTimerfd(m_timerfd, now); 198 | 199 | std::vector expired = getExpired(now); 200 | 201 | LOG_TRACE << "Expired Timer size " << expired.size() << " "; 202 | 203 | m_callingExpiredTimers = true; 204 | m_cancelingTimers.clear(); 205 | 206 | for(std::vector::iterator it = expired.begin(); 207 | it != expired.end(); ++it ) 208 | { 209 | it->second->run(); 210 | } 211 | 212 | m_callingExpiredTimers = false; 213 | 214 | reset(expired, now); 215 | } 216 | 217 | 218 | void TimerQueue::reset(const std::vector& expired, TimeStamp now) 219 | { 220 | TimeStamp nextExpire; 221 | 222 | for(std::vector::const_iterator it = expired.begin(); 223 | it != expired.end(); ++it) 224 | { 225 | ActiveTimer timer(it->second, it->second->sequence()); 226 | if(it->second->repeat() 227 | && m_cancelingTimers.find(timer) == m_cancelingTimers.end()) 228 | {//如果是周期定时器则重新设定时间插入. 否则delete. 229 | it->second->restart(now); 230 | insert(it->second); 231 | } 232 | else 233 | {// FIXME move to a free list no delete please 234 | delete it->second; 235 | } 236 | } 237 | 238 | if (!m_timers.empty()) 239 | { 240 | nextExpire = m_timers.begin()->second->expiration(); 241 | } 242 | 243 | if (nextExpire.valid()) 244 | { 245 | resetTimerfd(m_timerfd, nextExpire); 246 | } 247 | } --------------------------------------------------------------------------------