├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── Makefile ├── README.md ├── TODO ├── examples ├── test_client.cpp ├── test_echo.cpp ├── test_hsha.cpp ├── test_logger.cpp └── test_timer.cpp └── luves ├── buffer.cpp ├── buffer.h ├── channel.cpp ├── channel.h ├── connection.cpp ├── connection.h ├── epoll.cpp ├── epoll.h ├── eventhandle.cpp ├── eventhandle.h ├── hshaserver.cpp ├── hshaserver.h ├── kqueue.cpp ├── kqueue.h ├── logger.cpp ├── logger.h ├── luves.h ├── net.cpp ├── net.h ├── tcpserver.cpp ├── tcpserver.h ├── threadpool.cpp ├── threadpool.h ├── timer.cpp └── timer.h /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Compiled Dynamic libraries 12 | *.so 13 | *.dylib 14 | *.dll 15 | 16 | # Fortran module files 17 | *.mod 18 | *.smod 19 | 20 | # Compiled Static libraries 21 | *.lai 22 | *.la 23 | *.a 24 | *.lib 25 | 26 | # Executables 27 | *.exe 28 | *.out 29 | *.app 30 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.6) 2 | project(Luves) 3 | 4 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -pthread") 5 | 6 | set(SOURCE_FILES 7 | examples/test_client.cpp 8 | examples/test_echo.cpp 9 | luves/test_hsha.cpp 10 | examples/test_logger.cpp 11 | examples/test_timer.cpp 12 | luves/buffer.cpp 13 | luves/buffer.h 14 | luves/channel.cpp 15 | luves/channel.h 16 | luves/epoll.cpp 17 | luves/epoll.h 18 | luves/eventhandle.cpp 19 | luves/eventhandle.h 20 | luves/hshaserver.cpp 21 | luves/hshaserver.h 22 | luves/kqueue.cpp 23 | luves/kqueue.h 24 | luves/logger.cpp 25 | luves/logger.h 26 | luves/luves.h 27 | luves/net.cpp 28 | luves/net.h 29 | luves/tcpconnection.cpp 30 | luves/tcpconnection.h 31 | luves/tcpserver.cpp 32 | luves/tcpserver.h 33 | luves/test_hsha.cpp 34 | luves/threadpool.cpp 35 | luves/threadpool.h 36 | luves/timer.cpp 37 | luves/timer.h) 38 | 39 | add_executable(Luves ${SOURCE_FILES}) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Leviathan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC=g++ 2 | CFLAGS=-std=c++11 -fPIC -c 3 | DFLAGS=-std=c++11 -shared 4 | LIBLUVES=libluves.so 5 | 6 | SOURCES=$(shell find luves -name "*.cpp") 7 | OBJ=$(SOURCES:%.cpp=%.o) 8 | PREFIX=luves 9 | 10 | build:$(LIBLUVES) 11 | cp -fr luves /usr/local/include 12 | cp $(LIBLUVES) /usr/local/lib 13 | rm $(PREFIX)/*.o $(LIBLUVES) 14 | 15 | $(LIBLUVES):$(OBJ) 16 | $(CC) $(DFLAGS) -o $@ $(OBJ) 17 | 18 | $(PREFIX)/%.o: $(PREFIX)/%.cpp $(PREFIX)/%.h 19 | $(CC) $(CFLAGS) -c $< -o $@ 20 | 21 | clean: 22 | rm $(LIBLUVES) 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Luves 2 | 3 | 4 | [![Build Status](https://travis-ci.org/Leviathan1995/Luves.svg?branch=master)](https://travis-ci.org/Leviathan1995/Luves) 5 | 6 | Luves是一个轻量级的事件触发网络库,封装了Socket,简化基于Socket程序开发。目标是封装了以下三种事件的响应:IO事件,定时器事件,信号事件。支持跨平台,OS X环境使用kqueue模型,Linux环境使用Epoll模型,实现半同步/半异步(HSHA)服务器框架模型。 7 | 8 | - [写在前面][0] 9 | - [安装][1] 10 | - [编译][2] 11 | - [示例][3] 12 | - [测试结果][4] 13 | - [版本更新日志][5] 14 | - [License][6] 15 | 16 | 17 | 18 | ## 写在前面 19 | 20 | 将自己理解的网络框架以"学习"的标准实现,简化复杂网络库的细节部分,实现网络库的本质,必要的地方注释了代码实现思路,欢迎提PR或更好的建议。 21 | 22 | 23 | 24 | ## 安装 25 | 26 | make 27 | 28 | 29 | ## 编译 30 | g++ -std=c++11 test_echo.cpp -L/usr/local/lib -lluves 31 | 32 | ## 示例 33 | 简单的Echo服务器 34 | 35 | #include "luves/luves.h" 36 | using namespace luves; 37 | 38 | Buffer GetInput(const TcpConnectionPtr & conn) 39 | { 40 | return conn->GetInputBuffer(); 41 | } 42 | 43 | int main() 44 | { 45 | EventLoop loop; 46 | Ip4Addr server_addr("0.0.0.0", 6543); 47 | TcpServer server(&loop, server_addr); 48 | server.SetReadCb(GetInput); 49 | 50 | server.SetWriteCb([](const TcpConnectionPtr & conn) 51 | {conn->Send(conn->GetInputBuffer());}); 52 | 53 | server.RunServer(); 54 | loop.loop(); 55 | } 56 | 57 | ## Echo测试结果 58 | 59 | - 使用ApacheBench测试: 60 | 61 | @ubuntu:~$ ab -n 10000 -c 10 -k http://0.0.0.0:6543/ 62 | - 测试结果: 63 | 64 | Server Software: 65 | Server Hostname: 0.0.0.0 66 | Server Port: 6543 67 | 68 | Document Path: / 69 | Document Length: 0 bytes 70 | 71 | Concurrency Level: 10 72 | Time taken for tests: 2.998 seconds 73 | Complete requests: 10000 74 | Failed requests: 0 75 | Keep-Alive requests: 0 76 | Total transferred: 0 bytes 77 | HTML transferred: 0 bytes 78 | Requests per second: 3335.80 [#/sec] (mean) 79 | Time per request: 2.998 [ms] (mean) 80 | Time per request: 0.300 [ms] (mean, across all concurrent requests) 81 | Transfer rate: 0.00 [Kbytes/sec] received 82 | 83 | Connection Times (ms) 84 | min mean[+/-sd] median max 85 | Connect: 0 0 1.2 0 77 86 | Processing: 0 3 4.6 2 78 87 | Waiting: 0 0 0.0 0 0 88 | Total: 1 3 4.7 2 79 89 | 90 | ## 版本更新日志 91 | Version 0.01 92 | 93 | - 原型开发,目前使用kqueue,暂支持OS X系统,实现半同步半异步服务器框架.封装了IO事件与定时事件。 94 | - 实现跨平台,添加Linux平台的Epoll模块。 95 | - 修复多线程日志bug 96 | - 修复Hsha模式下kqueue模块bug 97 | 98 | 99 | ## License 100 | MIT 101 | 102 | [0]:#title00 103 | [1]:#title01 104 | [2]:#title02 105 | [3]:#title03 106 | [4]:#title04 107 | [5]:#title05 108 | [6]:#title06 109 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /examples/test_client.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // echo_client.cpp 3 | // Luves 4 | // 5 | // Created by leviathan on 16/5/26. 6 | // Copyright © 2016年 leviathan. All rights reserved. 7 | // 8 | 9 | /* 10 | #include "luves.h" 11 | 12 | using namespace luves; 13 | 14 | int main() 15 | { 16 | EventLoop * loop; 17 | Ip4Addr server_addr("127.0.0.1",1234); 18 | TcpClient client(loop,server_addr); 19 | client.SetReadCb([](const TcpConnectionPtr & conn) 20 | {conn->Send(conn->GetInputBuffer());}); 21 | loop->loop(); 22 | return 0; 23 | } 24 | */ 25 | -------------------------------------------------------------------------------- /examples/test_echo.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // echo.cpp 3 | // Luves 4 | // 5 | // Created by leviathan on 16/5/19. 6 | // Copyright © 2016年 leviathan. All rights reserved. 7 | // 8 | 9 | 10 | #include "luves/luves.h" 11 | 12 | using namespace luves; 13 | 14 | Buffer GetInput(const TcpConnectionPtr & conn) 15 | { 16 | return conn->GetInputBuffer(); 17 | } 18 | 19 | int main() 20 | { 21 | EventLoop loop; 22 | Ip4Addr server_addr("0.0.0.0", 6543); 23 | TcpServer server(&loop, server_addr); 24 | server.SetReadCb(GetInput); 25 | 26 | 27 | /* 28 | server.SetWriteCb([](const TcpConnectionPtr & conn) 29 | {conn->Send("HTTP/1.1 200 OK\r\n" 30 | "Content-Type:text/html;charset=utf-8\r\n" 31 | "Content-Length:18\r\n" 32 | "\r\n" 33 | "Welcome to tinyweb");}); 34 | */ 35 | server.SetWriteCb([](const TcpConnectionPtr & conn) 36 | {conn->Send(conn->GetInputBuffer());}); 37 | 38 | server.RunServer(); 39 | loop.loop(); 40 | } 41 | 42 | -------------------------------------------------------------------------------- /examples/test_hsha.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // test_hsha.cpp 3 | // Luves 4 | // 5 | // Created by leviathan on 16/6/28. 6 | // Copyright © 2016年 leviathan. All rights reserved. 7 | // 8 | 9 | /* 10 | #include "luves.h" 11 | 12 | using namespace luves; 13 | 14 | Buffer GetInput(const TcpConnectionPtr & conn) 15 | { 16 | return conn->GetInputBuffer(); 17 | } 18 | 19 | int main() 20 | { 21 | EventLoop loop; 22 | Ip4Addr server_addr("0.0.0.0", 6543); 23 | 24 | HshaServer server(&loop, server_addr, 2); 25 | server.SetReadCb(GetInput); 26 | 27 | 28 | server.SetWriteCb([](const TcpConnectionPtr & conn) 29 | {conn->Send(conn->GetInputBuffer());}); 30 | 31 | server.RunServer(); 32 | loop.loop(); 33 | } 34 | */ 35 | -------------------------------------------------------------------------------- /examples/test_logger.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // log_test.cpp 3 | // Luves 4 | // 5 | // Created by leviathan on 16/6/20. 6 | // Copyright © 2016年 leviathan. All rights reserved. 7 | // 8 | 9 | /* 10 | #include 11 | #include "luves.h" 12 | 13 | using namespace luves; 14 | 15 | int main() 16 | { 17 | trace("trace test %d%s%s",22,"s","w"); 18 | fatal("fatal test"); 19 | fatalif(1,"fataif test"); 20 | check(1, "check test"); 21 | //exitif(1, "exitif test"); 22 | fatalif(-1,"-1"); 23 | fatalif(0,"0"); 24 | } 25 | */ 26 | -------------------------------------------------------------------------------- /examples/test_timer.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // timer.cpp 3 | // Luves 4 | // 5 | // Created by leviathan on 16/6/11. 6 | // Copyright © 2016年 leviathan. All rights reserved. 7 | // 8 | 9 | /* 10 | #include "luves.h" 11 | 12 | using namespace luves; 13 | 14 | void TimerFunc() 15 | { 16 | std::cout<<"hello world! 10s"<0) 41 | read_index_ += n; 42 | 43 | return n; 44 | } 45 | 46 | int Buffer::WriteImp(int fd) // out 47 | { 48 | int n = int(write(fd, buffer_.data(), write_index_)); 49 | INFO_LOG("Write %d bytes.", n); 50 | buffer_.clear(); 51 | write_index_ = 0; 52 | return n; 53 | } 54 | 55 | std::ostream & operator <<(std::ostream & os, Buffer & buffer) 56 | { 57 | for (auto data:buffer.buffer_) 58 | os< 13 | #include 14 | #include 15 | #include 16 | 17 | #include "logger.h" 18 | 19 | namespace luves { 20 | 21 | // 22 | //buffer 23 | // 24 | class Buffer 25 | { 26 | 27 | public: 28 | Buffer():read_index_(0),write_index_(0){buffer_.resize(1024);}; 29 | ~Buffer(){}; 30 | 31 | void Swap(Buffer & rhs) 32 | { 33 | buffer_.swap(rhs.buffer_); 34 | std::swap(read_index_, rhs.read_index_); 35 | std::swap(write_index_,rhs.write_index_); 36 | } 37 | 38 | size_t Capacity(){return buffer_.capacity();} 39 | 40 | size_t Size(){return buffer_.size();} 41 | 42 | void Append(Buffer & buffer); 43 | void Append(const std::string & msg); 44 | 45 | int ReadImp(int fd); 46 | int WriteImp(int fd); 47 | 48 | void Clear(){buffer_.clear();} 49 | 50 | friend std::ostream & operator <<(std::ostream & os,Buffer &buffer); 51 | 52 | std::vector & GetData(){return buffer_;} 53 | 54 | size_t GetWriteIndex(){return write_index_;} 55 | size_t GetReadIndex() {return read_index_;} 56 | private: 57 | size_t read_index_; 58 | size_t write_index_; 59 | std::vector buffer_; 60 | }; 61 | 62 | } 63 | #endif /* Buffer_h */ 64 | -------------------------------------------------------------------------------- /luves/channel.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // channel.cpp 3 | // Luves 4 | // 5 | // Created by hashdata on 16/9/30. 6 | // Copyright © 2016年 hashdata. All rights reserved. 7 | // 8 | 9 | #include "channel.h" 10 | 11 | // 12 | //事件通道 13 | // 14 | namespace luves { 15 | 16 | Channel::Channel(EventLoop * loop,int fd, bool is_listen) 17 | { 18 | loop_ = loop; 19 | fd_ = fd; 20 | is_listen_ = is_listen; 21 | 22 | if(!is_listen) 23 | { 24 | sockaddr_in local,peer; 25 | socklen_t len=sizeof(local); 26 | int ret=getsockname(fd_, (struct sockaddr*)&local, &len); 27 | if (ret<0) 28 | ERROR_LOG("get local addr failed! %d %s", errno, strerror(errno)); 29 | ret=getpeername(fd_, (struct sockaddr*)&peer, &len); 30 | if (ret<0) 31 | ERROR_LOG("get peer addr failed! %d %s", errno, strerror(errno)); 32 | 33 | Ip4Addr local_addr(local), peer_addr(peer); 34 | connection_ = TcpConnectionPtr(new TcpConnection(loop_, fd_)); 35 | SocketOp::SetNonblock(fd_); //设置fd为非阻塞 36 | TRACE_LOG("TCP服务创建成功:%s--%s:%d",local_addr.ToString().c_str(), peer_addr.ToString().c_str(),fd_); 37 | 38 | SetReadCb([this]{GetConnectionPtr()->HandleRead();}); 39 | SetWriteCb([this]{GetConnectionPtr()->HandleWrite();}); 40 | 41 | } 42 | }; 43 | 44 | //关闭通道 45 | void Channel::Close() 46 | { 47 | //清理缓冲区 48 | this->connection_->GetInputBuffer().Clear(); 49 | this->connection_->GetOutputBuffer().Clear(); 50 | loop_->DeleteChannel(this); 51 | } 52 | 53 | void Channel::HandleEvent() 54 | { 55 | //listen管道 56 | if (is_listen_) 57 | { 58 | if (read_cb_) 59 | { 60 | read_cb_(); 61 | return; 62 | } 63 | } 64 | 65 | //非listen管道 66 | if(!is_listen_) 67 | { 68 | if (read_cb_) 69 | read_cb_(); 70 | if (write_cb_) 71 | write_cb_(); 72 | } 73 | if(connection_->IsClose()) 74 | Close(); 75 | else 76 | { 77 | INFO_LOG("Try to re-add %d to kqueue.", this->GetFd()); 78 | loop_->AddChannel(this); 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /luves/channel.h: -------------------------------------------------------------------------------- 1 | // 2 | // channel.h 3 | // Luves 4 | // 5 | // Created by hashdata on 16/9/30. 6 | // Copyright © 2016年 hashdata. All rights reserved. 7 | // 8 | 9 | #ifndef CHANNEL_H_ 10 | #define CHANNEL_H_ 11 | 12 | #include 13 | #include "eventhandle.h" 14 | #include "net.h" 15 | #include "connection.h" 16 | 17 | // 18 | //事件通道,接管一个fd 19 | // 20 | 21 | namespace luves { 22 | 23 | class EventLoop; 24 | class TcpConnection; 25 | 26 | typedef std::shared_ptr TcpConnectionPtr; 27 | 28 | class Channel 29 | { 30 | public: 31 | Channel(EventLoop * loop, int fd, bool is_listen); 32 | ~Channel(){}; 33 | 34 | //处理事件 35 | void HandleEvent(); 36 | 37 | //设置回调函数 38 | void SetReadCb(const std::function & cb){read_cb_ = cb;} 39 | void SetWriteCb(const std::function & cb){write_cb_ = cb;} 40 | //关闭通道 41 | void Close(); 42 | 43 | //获取事件描述符 44 | int GetFd(){return fd_;} 45 | 46 | bool GetIsListen(){return is_listen_;} 47 | 48 | TcpConnectionPtr GetConnectionPtr(){return connection_;} 49 | private: 50 | bool is_listen_; //是否为listen监听套接字的channel 51 | EventLoop * loop_; 52 | int fd_; //事件描述符 53 | std::function read_cb_, write_cb_; //读写回调函数 54 | TcpConnectionPtr connection_; //channel管理的连接 55 | 56 | }; 57 | 58 | } 59 | #endif /* channel_hpp */ 60 | -------------------------------------------------------------------------------- /luves/connection.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // tcp_connection.cpp 3 | // Luves 4 | // 5 | // Created by leviathan on 16/6/21. 6 | // Copyright © 2016年 leviathan. All rights reserved. 7 | // 8 | 9 | #include "connection.h" 10 | 11 | namespace luves { 12 | 13 | 14 | // 15 | //TCP连接模块 16 | // 17 | 18 | //写入消息至缓冲区 19 | void TcpConnection::Send(Buffer & msg) 20 | { 21 | output_.Append(msg); 22 | output_.WriteImp(fd_); 23 | } 24 | 25 | void TcpConnection::Send(const std::string & msg) 26 | { 27 | output_.Append(msg); 28 | output_.WriteImp(fd_); 29 | } 30 | 31 | //接收消息 32 | void TcpConnection::HandleRead() 33 | { 34 | 35 | while (1) 36 | { 37 | int n=input_.ReadImp(fd_); 38 | if (n>0) 39 | { 40 | if (readcb_) 41 | readcb_(shared_from_this()); 42 | } 43 | else 44 | { 45 | close(fd_); 46 | INFO_LOG("Close %d socket.", fd_); 47 | is_close_ = true; 48 | break; 49 | } 50 | } 51 | } 52 | 53 | //发送消息 54 | void TcpConnection::HandleWrite() 55 | { 56 | if (writecb_) 57 | writecb_(shared_from_this()); 58 | } 59 | 60 | void TcpConnection::HandleClose(const TcpConnectionPtr & conn) 61 | { 62 | if (closecb_) 63 | closecb_(shared_from_this()); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /luves/connection.h: -------------------------------------------------------------------------------- 1 | // 2 | // tcp_connection.h 3 | // Luves 4 | // 5 | // Created by leviathan on 16/6/21. 6 | // Copyright © 2016年 leviathan. All rights reserved. 7 | // 8 | 9 | #ifndef TCP_CONNECTION_H_ 10 | #define TCP_CONNECTION_H_ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include "net.h" 18 | #include "buffer.h" 19 | #include "eventhandle.h" 20 | #include "channel.h" 21 | #include "logger.h" 22 | 23 | namespace luves { 24 | 25 | class TcpConnection; 26 | class EventLoop; 27 | class Channel; 28 | 29 | typedef std::shared_ptr TcpConnectionPtr; 30 | typedef std::function TcpCallBack; 31 | 32 | // 33 | //TCP连接服务 34 | // 35 | class TcpConnection:public std::enable_shared_from_this 36 | { 37 | public: 38 | 39 | TcpConnection(EventLoop *loop, int fd):loop_(loop), fd_(fd), is_close_(false){}; 40 | ~TcpConnection(){}; 41 | 42 | //设置回调函数 43 | void SetReadCb(const TcpCallBack & cb){readcb_=cb;} 44 | void SetWriteCb(const TcpCallBack & cb){writecb_=cb;} 45 | void SetCloseCb(const TcpCallBack & cb){closecb_=cb;} 46 | 47 | //处理读写回调 48 | void HandleRead(); 49 | void HandleWrite(); 50 | void HandleClose(const TcpConnectionPtr & conn); 51 | //发送数据 52 | void Send(Buffer & msg); 53 | void Send(const std::string & msg); 54 | 55 | //获取读写缓冲区 56 | Buffer & GetInputBuffer(){return input_;} 57 | Buffer & GetOutputBuffer(){return output_;} 58 | 59 | //断开连接 60 | void Close(); 61 | 62 | //获取事件循环 63 | EventLoop * GetLoop(){return loop_;}; 64 | 65 | bool IsClose(){return is_close_;} 66 | private: 67 | bool is_close_; //连接是否已经断开 68 | int fd_; 69 | TcpCallBack readcb_,writecb_,closecb_; 70 | EventLoop * loop_; 71 | Buffer input_,output_; 72 | }; 73 | 74 | } 75 | #endif /* tcp_connection_h */ 76 | -------------------------------------------------------------------------------- /luves/epoll.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // epoll.cpp 3 | // Luves 4 | // 5 | // Created by leviathan on 16/10/2 6 | // Copyright @ 2016 leviathan. All rights reserved 7 | // 8 | 9 | #ifdef __linux__ 10 | 11 | #include "epoll.h" 12 | 13 | namespace luves{ 14 | 15 | // 16 | // IO复用模型-Epoll 17 | // 18 | 19 | 20 | EpollModel::EpollModel() 21 | { 22 | ep_ = epoll_create(1024); 23 | max_events_ = 1024; 24 | } 25 | 26 | void EpollModel::AddChannel(Channel * channel) 27 | { 28 | struct epoll_event event; 29 | event.data.fd = channel->GetFd(); 30 | if(channel->GetIsListen()) 31 | { 32 | event.events = EPOLLIN |EPOLLET; 33 | 34 | listen_fd_ = channel->GetFd(); 35 | int ret = epoll_ctl(ep_, EPOLL_CTL_ADD, channel->GetFd(), &event); 36 | if(ret == -1) 37 | { 38 | ERROR_LOG("Epoll add file description failed."); 39 | } 40 | } 41 | else 42 | { 43 | event.events = EPOLLIN|EPOLLOUT|EPOLLET; 44 | int ret = epoll_ctl(ep_, EPOLL_CTL_ADD, channel->GetFd(), &event); 45 | if(ret == -1) 46 | { 47 | ERROR_LOG("Epoll add file description failed."); 48 | } 49 | 50 | } 51 | } 52 | 53 | void EpollModel::DeleteChannel(Channel * channel) 54 | { 55 | int ret = epoll_ctl(ep_, EPOLL_CTL_DEL, channel->GetFd(), NULL); 56 | if(ret == -1) 57 | { 58 | ERROR_LOG("Epoll delete file description failed."); 59 | } 60 | } 61 | 62 | void EpollModel::UpdateChannel(Channel * channel) 63 | { 64 | 65 | } 66 | 67 | void EpollModel::RunModel(int64_t wait_time) 68 | { 69 | int nfds = epoll_wait(ep_, trigger_events_, max_events_, -1); 70 | trigger_channel_.clear(); 71 | for (int i = 0; i < nfds; ++i) 72 | { 73 | if ((trigger_events_[i].events & EPOLLERR) || 74 | (trigger_events_[i].events & EPOLLHUP) || 75 | (!(trigger_events_[i].events & EPOLLIN))) 76 | { 77 | ERROR_LOG("Epoll return error %d %s",errno, strerror(errno)); 78 | exit(1); 79 | } 80 | else if((listen_fd_ == trigger_events_[i].data.fd) || 81 | ((trigger_events_[i].events & EPOLLIN) && (is_hsha_ == false))) 82 | { 83 | trigger_channel_.push_back(channel_fd_->find(int(trigger_events_[i].data.fd))->second); 84 | } 85 | else if(trigger_events_[i].events & EPOLLIN && is_hsha_) 86 | { 87 | ThreadsPool::AddTask(int(trigger_events_[i].data.fd)); 88 | } 89 | } 90 | } 91 | 92 | ChannelList & EpollModel::GetTriggerPtr() 93 | { 94 | return trigger_channel_; 95 | } 96 | } 97 | 98 | #endif /* LINUX */ 99 | -------------------------------------------------------------------------------- /luves/epoll.h: -------------------------------------------------------------------------------- 1 | // 2 | // kqueue.h 3 | // Luves 4 | // 5 | // Created by hashdata on 16/9/30. 6 | // Copyright © 2016年 hashdata. All rights reserved. 7 | // 8 | 9 | #ifdef __linux__ 10 | 11 | #ifndef EPOLL_H_ 12 | #define EPOLL_H_ 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include "channel.h" 19 | #include "eventhandle.h" 20 | #include "threadpool.h" 21 | 22 | 23 | namespace luves 24 | { 25 | class Channel; 26 | 27 | typedef std::vector ChannelList; 28 | typedef std::map ChannelMap; 29 | 30 | class EpollModel 31 | { 32 | public: 33 | EpollModel(); 34 | ~EpollModel(){}; 35 | 36 | //事件通道操作,只暴露给事件循环EventLoop模块操作 37 | void AddChannel(Channel * channel); 38 | void DeleteChannel(Channel * channel); 39 | void UpdateChannel(Channel * channel); 40 | 41 | //启动事件模型 42 | void RunModel(int64_t wait_time); 43 | 44 | void SetChannelPtr(std::map * channel_fd){ channel_fd_= channel_fd; } 45 | ChannelList & GetTriggerPtr(); 46 | 47 | void SetHsha(bool is_hsha){is_hsha = is_hsha_;} 48 | private: 49 | bool is_hsha_; 50 | struct epoll_event trigger_events_[1024]; 51 | std::map * channel_fd_; //channel与fd映射 52 | ChannelList channel_list_; //channel集合 53 | ChannelList trigger_channel_; //触发的channel集合 54 | int ep_; 55 | int max_events_; 56 | int listen_fd_; 57 | }; 58 | } 59 | 60 | 61 | #endif /* kqueue.h */ 62 | 63 | #endif /* LINUX */ 64 | -------------------------------------------------------------------------------- /luves/eventhandle.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // event_handle.cpp 3 | // Luves 4 | // 5 | // Created by leviathan on 16/5/17. 6 | // Copyright © 2016年 leviathan. All rights reserved. 7 | // 8 | 9 | #include "eventhandle.h" 10 | 11 | namespace luves { 12 | 13 | // 14 | //Event loop 15 | // 16 | EventLoop::EventLoop() 17 | { 18 | 19 | io_model_=std::make_shared(); 20 | timer_=std::make_shared(); 21 | } 22 | 23 | void EventLoop::SetChannelPtr(std::map* channel_fd) 24 | { 25 | channel_fd_ = channel_fd; 26 | this->io_model_->SetChannelPtr(channel_fd_); 27 | } 28 | 29 | void EventLoop::SetHsha(bool hsha) 30 | { 31 | is_hsha_=hsha; 32 | io_model_->SetHsha(is_hsha_); 33 | } 34 | 35 | void EventLoop::loop() 36 | { 37 | looping_ = true; 38 | quit_ = false; 39 | 40 | while(!quit_) 41 | { 42 | io_model_->RunModel(timer_->GetNextTimeout()); 43 | trigger_channels_ = io_model_->GetTriggerPtr(); 44 | for (auto event:trigger_channels_) 45 | event->HandleEvent(); 46 | //定时事件模块处理超时事件 47 | timer_->HandleTimeoutEvent(); 48 | } 49 | } 50 | 51 | void EventLoop::AddChannel(Channel * channel) 52 | { 53 | channel_fd_->insert(std::make_pair(channel->GetFd(),channel)); 54 | io_model_->AddChannel(channel); 55 | } 56 | 57 | void EventLoop::UpdateChannel(Channel * channel) 58 | { 59 | 60 | } 61 | 62 | void EventLoop::DeleteChannel(Channel * channel) 63 | { 64 | channel_fd_->erase(channel->GetFd()); 65 | io_model_->DeleteChannel(channel); 66 | } 67 | 68 | //定时事件操作 69 | TimerId EventLoop::startTimer(int64_t delaytime, const TimerTask & task,int64_t interval) 70 | { 71 | return timer_->StartTimer(delaytime, task,interval); 72 | } 73 | 74 | bool EventLoop::stopTimer(TimerId timerid) 75 | { 76 | return timer_->StopTimer(timerid); 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /luves/eventhandle.h: -------------------------------------------------------------------------------- 1 | // 2 | // event_handle.h 3 | // Luves 4 | // 5 | // Created by leviathan on 16/5/17. 6 | // Copyright © 2016年 leviathan. All rights reserved. 7 | // 8 | 9 | #ifndef EVENT_HANDLE_H_ 10 | #define EVENT_HANDLE_H_ 11 | 12 | #ifdef __linux__ 13 | #include 14 | #include "epoll.h" 15 | 16 | #elif __APPLE__ 17 | #include 18 | #include "kqueue.h" 19 | #endif 20 | 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include "timer.h" 30 | #include "logger.h" 31 | #include "channel.h" 32 | #include "threadpool.h" 33 | 34 | namespace luves { 35 | 36 | #ifdef __linux__ 37 | class EpollModel; 38 | typedef EpollModel io_model; 39 | #elif __APPLE__ 40 | class KqueueModel; 41 | typedef KqueueModel io_model; 42 | #endif 43 | 44 | class Channel; 45 | 46 | // 47 | //事件循环 48 | // 49 | class EventLoop 50 | { 51 | public: 52 | typedef std::vector TriggerChannels; 53 | EventLoop(); 54 | ~EventLoop(){}; 55 | 56 | //进入事件循环 57 | void loop(); 58 | 59 | //对通道进行操作 60 | void AddChannel(Channel * channel); 61 | void DeleteChannel(Channel *channel); 62 | void UpdateChannel(Channel *channel); 63 | 64 | //定时事件操作 65 | TimerId startTimer(int64_t delaytime,const TimerTask & task,int64_t interval=0); 66 | bool stopTimer(TimerId timerid); 67 | //获取IO模型指针 68 | std::shared_ptr & GetIOModel(){return io_model_;} 69 | 70 | void SetChannelPtr(std::map* channel_fd); 71 | 72 | void Exit(); 73 | 74 | void SetHsha(bool hsha); 75 | 76 | private: 77 | 78 | std::map * channel_fd_; 79 | bool is_hsha_; 80 | TriggerChannels trigger_channels_; 81 | bool looping_; 82 | bool quit_; 83 | std::shared_ptr io_model_; //事件循环使用的IO复用模型 84 | std::shared_ptr timer_; //定时处理单元 85 | 86 | }; 87 | 88 | //监听事件类型 89 | #ifdef __linux__ 90 | const int read_event = EPOLLIN; 91 | const int write_event = EPOLLOUT; 92 | #elif __APPLE__ 93 | const int read_event = EVFILT_READ; 94 | const int write_event = EVFILT_WRITE; 95 | #endif 96 | 97 | } 98 | 99 | #endif /* event_handle_h */ 100 | -------------------------------------------------------------------------------- /luves/hshaserver.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // hsha.cpp 3 | // Luves 4 | // 5 | // Created by leviathan on 16/6/26. 6 | // Copyright © 2016年 leviathan. All rights reserved. 7 | // 8 | 9 | #include "hshaserver.h" 10 | 11 | namespace luves 12 | { 13 | 14 | void HshaServer::RunServer() 15 | { 16 | server_->SetReadCb(read_cb_); 17 | server_->SetWriteCb(write_cb_); 18 | server_->SetHsha(true); 19 | 20 | server_->RunServer(); 21 | 22 | ThreadsPool::SetThreadNum(thread_num_); 23 | ThreadsPool::SetChannelPtr(server_->GetChannelPtr()); 24 | ThreadsPool::Instance().CreatePool(); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /luves/hshaserver.h: -------------------------------------------------------------------------------- 1 | // 2 | // hsha.h 3 | // Luves 4 | // 5 | // Created by leviathan on 16/6/26. 6 | // Copyright © 2016年 leviathan. All rights reserved. 7 | // 8 | 9 | #ifndef HSHA_SERVER_H_ 10 | #define HSHA_SERVER_H_ 11 | 12 | #include 13 | 14 | #include "tcpserver.h" 15 | #include "threadpool.h" 16 | #include "eventhandle.h" 17 | #include "net.h" 18 | 19 | namespace luves 20 | { 21 | 22 | // 23 | //Hsha model 24 | // 25 | typedef std::shared_ptr TcpServerPtr; 26 | typedef std::function HshaCallBack; 27 | 28 | //HshaServer 29 | class HshaServer 30 | { 31 | public: 32 | HshaServer(EventLoop *loop,Ip4Addr &addr,int thread_num):server_(TcpServerPtr(new TcpServer(loop,addr))),thread_num_(thread_num){} 33 | 34 | void RunServer(); 35 | 36 | //set call back function 37 | void SetReadCb(const HshaCallBack & cb){read_cb_=cb;}; 38 | void SetWriteCb(const HshaCallBack & cb){write_cb_=cb;}; 39 | 40 | private: 41 | int thread_num_; 42 | TcpServerPtr server_; 43 | HshaCallBack read_cb_,write_cb_; 44 | 45 | }; 46 | } 47 | #endif /* hsha_h */ 48 | -------------------------------------------------------------------------------- /luves/kqueue.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // kqueue.cpp 3 | // Luves 4 | // 5 | // Created by hashdata on 16/9/30. 6 | // Copyright © 2016年 hashdata. All rights reserved. 7 | // 8 | 9 | #ifdef __APPLE__ 10 | 11 | #include "kqueue.h" 12 | 13 | namespace luves { 14 | 15 | // 16 | //IO复用模型-Kqueue 17 | // 18 | 19 | 20 | void KqueueModel::AddChannel(Channel *channel) 21 | { 22 | struct kevent ev; 23 | if (channel->GetIsListen()) //是否为listen套接字 24 | { 25 | listen_fd_=channel->GetFd(); 26 | EV_SET(&ev, channel->GetFd(),read_event, EV_ADD|EV_ENABLE, 0, 0, NULL); 27 | INFO_LOG("Add the listen socket %d of channel to kqueue.", channel->GetFd()); 28 | } 29 | else 30 | { 31 | EV_SET(&ev, channel->GetFd(), read_event|write_event, EV_ADD|EV_ENABLE|EV_ONESHOT, 0, 0, NULL); 32 | INFO_LOG("Add the EV_ONESHOT socket %d of channel to kqueue.", channel->GetFd()); 33 | 34 | } 35 | //调用kevent(),更改设置 36 | kevent(kq_, &ev, 1 , NULL, 0, NULL); 37 | monitor_nums_++; 38 | 39 | } 40 | 41 | void KqueueModel::DeleteChannel(Channel * channel) 42 | { 43 | struct kevent ev; 44 | EV_SET(&ev, channel->GetFd(), read_event|write_event, EV_DELETE, 0, 0, NULL); 45 | //调用kevent(),更改设置 46 | kevent(kq_, &ev, 1, NULL, 0, NULL); 47 | INFO_LOG("Remove the socket %d of channel from kqueue.",channel->GetFd()); 48 | monitor_nums_++; 49 | } 50 | 51 | // TODO 52 | void KqueueModel::UpdateChannel(Channel * channel) 53 | { 54 | 55 | } 56 | 57 | void KqueueModel::RunModel(int64_t wait_time) 58 | { 59 | //struct timespec time_out={static_cast<__darwin_time_t>(0.001*waittime),0}; 60 | 61 | int nev = kevent(kq_,NULL, 0 ,trigger_events, 2048, NULL); 62 | trigger_channel_.clear(); 63 | 64 | for (int i=0; ifind(int(event->ident)) != channel_fd_->end()) 78 | { 79 | auto channel = channel_fd_->find(int(event->ident))->second; 80 | channel_fd_->insert(std::make_pair(channel->GetFd(),channel)); 81 | 82 | //add to trigger_channel_ 83 | */ 84 | trigger_channel_.push_back(channel_fd_->find(int(trigger_events[i].ident))->second); 85 | 86 | } 87 | else if (trigger_events[i].flags & EVFILT_READ && is_hsha_) //the server of model is hsha 88 | { 89 | ThreadsPool::AddTask(int(trigger_events[i].ident)); 90 | } 91 | } 92 | } 93 | 94 | ChannelList & KqueueModel::GetTriggerPtr() 95 | { 96 | return trigger_channel_; 97 | } 98 | } 99 | 100 | #endif /* MAC OS X */ 101 | -------------------------------------------------------------------------------- /luves/kqueue.h: -------------------------------------------------------------------------------- 1 | // 2 | // kqueue.h 3 | // Luves 4 | // 5 | // Created by hashdata on 16/9/30. 6 | // Copyright © 2016年 hashdata. All rights reserved. 7 | // 8 | 9 | #ifdef __APPLE__ 10 | 11 | #ifndef EVENTMODEL_H_ 12 | #define EVENTMODEL_H_ 13 | 14 | #include 15 | #include 16 | #include "eventhandle.h" 17 | #include "channel.h" 18 | 19 | 20 | namespace luves { 21 | 22 | class Channel; 23 | // 24 | //Event Model-Kqueue 25 | // 26 | typedef std::vector ChannelList; 27 | typedef std::map ChannelMap; 28 | typedef std::vector MonitorEvents; 29 | 30 | 31 | class KqueueModel 32 | { 33 | public: 34 | KqueueModel():kq_(kqueue()),monitor_nums_(0){}; 35 | ~KqueueModel(){}; 36 | 37 | typedef std::vector ChannelList; 38 | typedef std::map ChannelMap; 39 | 40 | //启动事件模型 41 | void RunModel(int64_t wait_time); 42 | 43 | //事件通道操作,只暴露给事件循环EventLoop模块操作 44 | void AddChannel(Channel * channel); 45 | void UpdateChannel(Channel * channel); 46 | void DeleteChannel(Channel * channel); 47 | 48 | ChannelList & GetTriggerPtr(); 49 | 50 | void SetHsha(bool is_hsha){is_hsha_=is_hsha;} 51 | 52 | void SetChannelPtr(std::map * channel_fd){ channel_fd_= channel_fd; } 53 | private: 54 | 55 | bool is_hsha_; 56 | int monitor_nums_; //监听的事件总数 57 | struct kevent monitor_events[2048]; 58 | struct kevent trigger_events[2048]; 59 | std::map * channel_fd_; //channel与fd 映射 60 | ChannelList monitor_channel_; //监听的channel集合 61 | ChannelList trigger_channel_; //触发的channel集合 62 | int kq_; 63 | int listen_fd_; //监听套接字 64 | }; 65 | } 66 | 67 | #endif /* kqueue_h */ 68 | 69 | #endif /* MAC OS X*/ 70 | -------------------------------------------------------------------------------- /luves/logger.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // log.cpp 3 | // Luves 4 | // 5 | // Created by leviathan on 16/6/17. 6 | // Copyright © 2016年 leviathan. All rights reserved. 7 | // 8 | 9 | #include "logger.h" 10 | #include "stdarg.h" 11 | 12 | namespace luves 13 | { 14 | 15 | std::string strlevel[]= 16 | { 17 | "ERROR", 18 | "WARN", 19 | "INFO", 20 | "DEBUG", 21 | "TRACE" 22 | }; 23 | 24 | Logger::Logger(): level_(LINFO),mode_(TERMIANAL) 25 | { 26 | fd_=-1; 27 | level_=LWARN; 28 | logger_mutex = PTHREAD_MUTEX_INITIALIZER; 29 | } 30 | 31 | Logger::~Logger() 32 | { 33 | if (fd_!=-1) 34 | { 35 | close(fd_); 36 | } 37 | } 38 | 39 | void Logger::SetFileName(const std::string & filename) 40 | { 41 | int fd=open(filename.c_str(), O_APPEND|O_CREAT|O_WRONLY|O_CLOEXEC); 42 | if (fd<0) 43 | { 44 | return ; 45 | } 46 | filename_=filename; 47 | if (fd_==-1) 48 | { 49 | fd_=fd; 50 | } 51 | else 52 | { 53 | close(fd); 54 | } 55 | 56 | 57 | } 58 | 59 | void Logger::PrintLog(int level, const char* file, int line, const char* func, const char * pram, ...) 60 | { 61 | if (level>level_) 62 | { 63 | return; 64 | } 65 | 66 | struct timeval now_tv; 67 | gettimeofday(&now_tv,NULL); //得到当前时间 68 | const time_t seconds=now_tv.tv_sec; 69 | struct tm t; 70 | localtime_r(&seconds, &t); //返回当地时间 71 | 72 | char *buffer=new char[4*1024]; 73 | char* p = buffer; 74 | //char* limit = buffer + sizeof(buffer); 75 | 76 | p+= snprintf(p,4*1024, 77 | "%04d/%02d/%02d-%02d:%02d:%02d-%lu[%s]:-%s:%d-%s%s-", 78 | t.tm_year + 1900, 79 | t.tm_mon + 1, 80 | t.tm_mday, 81 | t.tm_hour, 82 | t.tm_min, 83 | t.tm_sec, 84 | long(pthread_self()), 85 | strlevel[level].c_str(), 86 | file, 87 | line, 88 | func, 89 | "()" 90 | ); 91 | 92 | va_list pvar; 93 | va_start(pvar,pram); 94 | p += vsnprintf(p,4*1024,pram,pvar); 95 | va_end(pvar); 96 | 97 | if (mode_==FILE) 98 | write(fd_, buffer, 1); 99 | else if(mode_ == TERMIANAL) 100 | pthread_mutex_lock(&logger_mutex); 101 | std::cout< 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | 21 | namespace luves 22 | { 23 | extern std::string strlevel[]; 24 | 25 | //日志等级 26 | enum loglevel 27 | { 28 | LDEBUG, //指明细致的事件信息,对调试应用最有用。 29 | LERROR, //指明错误事件,但应用可能还能继续运行。 30 | LFATAL, //指明非常严重的错误事件,可能会导致应用终止执行。 31 | LINFO, //指明描述信息,从粗粒度上描述了应用运行过程。 32 | LTRACE, //比DEBUG级别的粒度更细。 33 | LWARN, //指明潜在的有害状况。 34 | 35 | }; 36 | 37 | 38 | #define printlog(level,...) \ 39 | do { \ 40 | if (level<=Logger::Instance().GetLevel()) { \ 41 | Logger::Instance().PrintLog(level, __FILE__, __LINE__, __func__, __VA_ARGS__); \ 42 | } \ 43 | } while(0) 44 | 45 | 46 | #define TRACE_LOG(...) printlog(LTRACE, __VA_ARGS__) 47 | #define DEBUG_LOG(...) pringlog(LDEBUG, __VA_ARGS__) 48 | #define INFO_LOG(...) printlog(LINFO, __VA_ARGS__) 49 | #define WARN_LOG(...) printlog(LWARN, __VA_ARGS__) 50 | #define ERROR_LOG(...) printlog(LERROR, __VA_ARGS__) 51 | #define FATAL_LOG(...) printlog(LFATAL, __VA_ARGS__) 52 | #define FATALIF_LOG(b, ...) do { if((b)) { printlog(LFATAL, __VA_ARGS__); } } while (0) 53 | #define CHECK_LOG(b, ...) do { if((b)) { printlog(LFATAL, __VA_ARGS__); } } while (0) 54 | #define EXITIF_LOG(b, ...) do { if ((b)) { printlog(LERROR, __VA_ARGS__); _exit(1); }} while(0) 55 | 56 | #define SETLOGLEVEL(l) Log::Instance().SetLevel(l) 57 | #define SETLOGFILE(n) Log::Instance().SetFileName(n) 58 | 59 | //日志模式,分为终端打印与文件输出两种,默认终端打印 60 | enum logmode 61 | { 62 | TERMIANAL, 63 | FILE 64 | }; 65 | 66 | 67 | // 68 | //日志模块,单例模式 69 | // 70 | class Logger 71 | { 72 | public: 73 | static Logger & Instance() 74 | { 75 | static Logger log; 76 | return log; 77 | } 78 | void SetLogMode(logmode mode){mode_=mode;}; 79 | void PrintLog(int level,const char * file,int line,const char * func ,const char * parm...); 80 | void SetLevel(const std::string & level); 81 | void SetLevel(loglevel level){level_=level;} 82 | 83 | loglevel & GetLevel(){return level_;} 84 | void SetFileName(const std::string & filename); 85 | private: 86 | pthread_mutex_t logger_mutex; 87 | Logger(); 88 | ~Logger(); 89 | Logger & operator=(Logger const &); // assign op. hidden 90 | Logger(Logger const &); // copy ctor hidden 91 | std::string filename_; 92 | loglevel level_; //log level 93 | int fd_; //file descriptor 94 | logmode mode_; 95 | 96 | }; 97 | } 98 | 99 | #endif /* log_h */ 100 | -------------------------------------------------------------------------------- /luves/luves.h: -------------------------------------------------------------------------------- 1 | // 2 | // luves.h 3 | // Luves 4 | // 5 | // Created by leviathan on 16/5/19. 6 | // Copyright © 2016年 leviathan. All rights reserved. 7 | // 8 | 9 | #ifndef LUVES_H_ 10 | #define LUVES_H_ 11 | 12 | #include "tcpserver.h" 13 | #include "logger.h" 14 | #include "hshaserver.h" 15 | 16 | #endif /* luves_h_ */ 17 | -------------------------------------------------------------------------------- /luves/net.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // net.cpp 3 | // Luves 4 | // 5 | // Created by leviathan on 16/5/17. 6 | // Copyright © 2016年 leviathan. All rights reserved. 7 | // 8 | #include 9 | 10 | #include "net.h" 11 | 12 | namespace luves 13 | { 14 | // 15 | //Socket属性操作 16 | // 17 | int SocketOp::SetNonblock(int fd) 18 | { 19 | int flags=fcntl(fd, F_GETFL,0); 20 | if(flags<0) 21 | return errno; 22 | return fcntl(fd, F_SETFL,flags|O_NONBLOCK); 23 | } 24 | 25 | int SocketOp::SetReuseaddr(int fd) 26 | { 27 | int flags=1; 28 | int len=sizeof(flags); 29 | return setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &flags, len); 30 | } 31 | 32 | int SocketOp::SetReuseport(int fd) 33 | { 34 | int flags=1; 35 | int len=sizeof(flags); 36 | return setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &flags, len); 37 | } 38 | 39 | // 40 | //Ip4地址模块 41 | // 42 | std::string Ip4Addr::ToString() 43 | { 44 | uint32_t host = addr_.sin_addr.s_addr; 45 | char str[64]; 46 | sprintf(str, "%d.%d.%d.%d:%d",(host>> 0)&0xff,(host >> 8)&0xff,(host >> 16)&0xff,(host>> 24)&0xff, ntohs(addr_.sin_port)); 47 | return str; 48 | } 49 | 50 | // 51 | //Socket 52 | // 53 | void Socket::Close(int fd) 54 | { 55 | close(fd); 56 | } 57 | 58 | int Socket::CreateNonBlockSocket() 59 | { 60 | int socket_fd=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 61 | FATALIF_LOG(!socket_fd,"socket fd create failed!"); 62 | return socket_fd; 63 | } 64 | 65 | int Socket::Bind(int fd,sockaddr_in * server_addr) 66 | { 67 | int ret =bind(fd,(struct sockaddr *)server_addr,sizeof(*server_addr)); 68 | if (ret==-1) 69 | { 70 | close(fd); 71 | ERROR_LOG("bind to %d failed! %d %s",fd,errno,strerror(errno)); 72 | return ret; 73 | } 74 | return 0; 75 | } 76 | 77 | void Socket::Listen(int fd) 78 | { 79 | int ret=listen(fd, 256); 80 | if (ret==-1) 81 | { 82 | FATALIF_LOG(ret, "listen to %d failed! %d %s", fd, errno, strerror(errno)); 83 | } 84 | } 85 | 86 | int Socket::Accept(int fd,sockaddr_in * client_addr) 87 | { 88 | socklen_t client_len=sizeof(*client_addr); 89 | int accept_fd=accept(fd, (struct sockaddr *)client_addr,&client_len); 90 | if(accept_fd==-1 & errno!=EAGAIN) 91 | ERROR_LOG("accept to %d failed! %d %s",fd,errno,strerror(errno)); 92 | return accept_fd; 93 | } 94 | 95 | void Socket::Connect(int fd,sockaddr_in * server_addr) 96 | { 97 | connect(fd, (struct sockaddr *)&server_addr, sizeof(server_addr)); 98 | 99 | } 100 | 101 | } 102 | -------------------------------------------------------------------------------- /luves/net.h: -------------------------------------------------------------------------------- 1 | // 2 | // net.h 3 | // Luves 4 | // 5 | // Created by leviathan on 16/5/17. 6 | // Copyright © 2016年 leviathan. All rights reserved. 7 | // 8 | 9 | #ifndef NET_H_ 10 | #define NET_H_ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include "logger.h" 21 | 22 | namespace luves { 23 | 24 | //Socket operation 25 | class SocketOp 26 | { 27 | public: 28 | static int SetNonblock(int fd); 29 | static int SetReuseaddr(int fd); 30 | static int SetReuseport(int fd); 31 | }; 32 | 33 | // 34 | //Ipv4 35 | // 36 | class Ip4Addr 37 | { 38 | public: 39 | Ip4Addr(const std::string & ip,int port): 40 | ip_(ip),port_(port){}; 41 | Ip4Addr(const sockaddr_in & addr):addr_(addr){}; 42 | 43 | //get data 44 | short GetPort(){return port_;} 45 | std::string GetIp(){return ip_;} 46 | 47 | std::string ToString(); 48 | private: 49 | sockaddr_in addr_; 50 | std::string ip_; 51 | short port_; 52 | }; 53 | 54 | // 55 | //Socket 56 | // 57 | class Socket 58 | { 59 | public: 60 | explicit Socket(int fd):fd_(Socket::CreateNonBlockSocket()){} 61 | ~Socket(){}; 62 | 63 | int GetFd(){return fd_;} 64 | 65 | //Socket Operation 66 | static void ShutDownWrite(); 67 | static int Bind(int fd,sockaddr_in * server_addr); 68 | static void Listen(int fd); 69 | static int Accept(int fd,sockaddr_in * client_addr); 70 | static void Connect(int fd,sockaddr_in * server_addr); 71 | static int CreateNonBlockSocket(); 72 | static void Close(int fd); 73 | private: 74 | const int fd_; 75 | }; 76 | 77 | } 78 | 79 | #endif /* net_h */ 80 | -------------------------------------------------------------------------------- /luves/tcpserver.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // tcp.cpp 3 | // Luves 4 | // 5 | // Created by leviathan on 16/5/17. 6 | // Copyright © 2016年 leviathan. All rights reserved. 7 | // 8 | 9 | #include "tcpserver.h" 10 | #include "eventhandle.h" 11 | 12 | namespace luves { 13 | 14 | 15 | // 16 | //TCP Server模块 17 | //用于新建TCP服务端 18 | // 19 | TcpServer::~TcpServer() 20 | { 21 | delete listen_channel_; 22 | } 23 | void TcpServer::Bind() 24 | { 25 | bzero(&serverAddr_, sizeof(serverAddr_)); 26 | serverAddr_.sin_family=AF_INET; 27 | serverAddr_.sin_addr.s_addr=inet_addr(addr_.GetIp().c_str()); 28 | serverAddr_.sin_port=htons(addr_.GetPort()); 29 | 30 | Socket::Bind(listenFd_,this->GetServerAddrPointer()); 31 | } 32 | 33 | void TcpServer::Listen() 34 | { 35 | listenning_=true; 36 | Socket::Listen(listenFd_); 37 | } 38 | 39 | void TcpServer::RunServer() 40 | { 41 | this->Bind(); 42 | this->Listen(); 43 | 44 | loop_->SetChannelPtr(&channel_fd_); 45 | loop_->AddChannel(listen_channel_); 46 | } 47 | 48 | //当有新的连接,epoll被触发,回调HandleAccept()函数并建立新的连接 49 | void TcpServer::HandleAccept() 50 | { 51 | struct sockaddr_in client_addr; 52 | int accept_fd; 53 | while((accept_fd=Socket::Accept(listen_channel_->GetFd(), &client_addr))>=0) 54 | this->NewChannel(accept_fd); 55 | } 56 | 57 | void TcpServer::NewChannel(int accept_fd) 58 | { 59 | Channel * new_channel = new Channel(loop_, accept_fd, false); 60 | 61 | new_channel->SetReadCb([=]{new_channel->GetConnectionPtr()->HandleRead();}); 62 | new_channel->SetWriteCb([=]{new_channel->GetConnectionPtr()->HandleWrite();}); 63 | if (read_cb_) 64 | new_channel->GetConnectionPtr()->SetReadCb(read_cb_); 65 | if (write_cb_) 66 | new_channel->GetConnectionPtr()->SetWriteCb(write_cb_); 67 | 68 | channel_fd_[accept_fd] = new_channel; 69 | loop_->AddChannel(new_channel); 70 | 71 | } 72 | 73 | // 74 | //TCP Client 75 | // 76 | 77 | /* 78 | void TcpClient::RunClient() 79 | { 80 | this->Bind(); 81 | this->HandleConnect(); 82 | client_channel_->SetEvent(read_event); 83 | loop_->UpdateChannel(client_channel_); 84 | 85 | TcpConnectionPtr conn=TcpConnectionPtr(new TcpConnection(loop_)); 86 | if (readcb_) 87 | { 88 | conn->SetReadCb(readcb_); 89 | } 90 | if (writecb_) { 91 | conn->SetWriteCb(writecb_); 92 | } 93 | 94 | } 95 | 96 | void TcpClient::Bind() 97 | { 98 | struct sockaddr_in client_addr; 99 | bzero(&client_addr, sizeof(client_addr)); 100 | client_addr.sin_family=AF_INET; 101 | client_addr.sin_addr.s_addr=htons(INADDR_ANY); 102 | client_addr.sin_port=htons(0); 103 | 104 | bind(client_fd_, (struct sockaddr *)&client_addr, sizeof(client_addr)); 105 | } 106 | 107 | void TcpClient::HandleConnect() 108 | { 109 | struct sockaddr_in server_addr; 110 | server_addr.sin_family=AF_INET; 111 | server_addr.sin_addr.s_addr=inet_addr("127.0.0.1"); 112 | server_addr.sin_port=htons(server_addr_.GetPort()); 113 | 114 | Socket::Bind(client_fd_, &server_addr); 115 | connect(client_fd_, (struct sockaddr *)&server_addr, sizeof(server_addr)); 116 | } 117 | */ 118 | } 119 | -------------------------------------------------------------------------------- /luves/tcpserver.h: -------------------------------------------------------------------------------- 1 | // 2 | // tcp.h 3 | // Luves 4 | // 5 | // Created by leviathan on 16/5/17. 6 | // Copyright © 2016年 leviathan. All rights reserved. 7 | // 8 | 9 | #ifndef TCP_SERVER_H_ 10 | #define TCP_SERVER_H_ 11 | 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include "connection.h" 22 | 23 | namespace luves { 24 | 25 | // 26 | //TcpServer 27 | // 28 | class TcpServer 29 | { 30 | public: 31 | TcpServer(EventLoop *loop,Ip4Addr & addr):loop_(loop),addr_(addr),listenFd_(Socket::CreateNonBlockSocket()),listenning_(false),ip_(addr.GetIp()),port_(addr.GetPort()) 32 | { 33 | SocketOp::SetReuseaddr(listenFd_); 34 | SocketOp::SetNonblock(listenFd_); 35 | listen_channel_=new Channel(loop,listenFd_,true); 36 | listen_channel_->SetReadCb([this]{HandleAccept();}); 37 | 38 | INFO_LOG("Set server ip: %s", addr_.GetIp().c_str()); 39 | INFO_LOG("Set server port: %d", addr_.GetPort()); 40 | }; 41 | virtual ~TcpServer(); 42 | 43 | void Bind(); 44 | void Listen(); 45 | 46 | 47 | void NewChannel(int accept_fd); //Server新建Channel 48 | 49 | void HandleAccept(); 50 | 51 | void SetReadCb(const TcpCallBack & read_cb){read_cb_ = read_cb;} 52 | void SetWriteCb(const TcpCallBack & write_cb){write_cb_ = write_cb;} 53 | 54 | void RunServer(); 55 | 56 | struct sockaddr_in * GetServerAddrPointer(){return &serverAddr_;} 57 | 58 | EventLoop * GetLoop(){ return loop_;} 59 | 60 | std::map* GetChannelPtr() { return &channel_fd_;} 61 | 62 | void SetHsha(bool is_hsha) 63 | { 64 | is_hsha_ = is_hsha; 65 | loop_->SetHsha(is_hsha_); 66 | } 67 | private: 68 | 69 | std::map channel_fd_; 70 | struct sockaddr_in serverAddr_; 71 | std::string ip_; 72 | short port_; 73 | int listenFd_; 74 | bool listenning_, is_hsha_; 75 | Ip4Addr addr_; 76 | EventLoop * loop_; 77 | Channel * listen_channel_; 78 | TcpCallBack read_cb_,write_cb_; 79 | }; 80 | 81 | 82 | // 83 | //Tcp客户端 84 | // 85 | class TcpClient 86 | { 87 | public: 88 | TcpClient(EventLoop *loop,Ip4Addr & server_addr):loop_(loop),server_addr_(server_addr),client_fd_(Socket::CreateNonBlockSocket()){}; 89 | virtual ~TcpClient(){}; 90 | 91 | void Bind(); 92 | void HandleConnect(); 93 | 94 | //设置回调函数 95 | void SetReadCb(const TcpCallBack & cb){readcb_=cb;} 96 | void SetWriteCb(const TcpCallBack & cb){writecb_=cb;} 97 | 98 | //启动Client 99 | void RunClient(); 100 | private: 101 | short port_; 102 | int client_fd_; 103 | Ip4Addr server_addr_; 104 | EventLoop * loop_; 105 | Channel * client_channel_; 106 | TcpCallBack readcb_,writecb_; 107 | 108 | }; 109 | } 110 | 111 | #endif /* tcp_h */ 112 | -------------------------------------------------------------------------------- /luves/threadpool.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // threads.cpp 3 | // Luves 4 | // 5 | // Created by leviathan on 16/5/18. 6 | // Copyright © 2016年 leviathan. All rights reserved. 7 | // 8 | 9 | #include "threadpool.h" 10 | 11 | namespace luves 12 | { 13 | 14 | std::queue ThreadsPool::task_; 15 | //std::vector ThreadsPool::active_; 16 | 17 | std::map * ThreadsPool::channel_fd_; 18 | 19 | pthread_mutex_t ThreadsPool::pthreadMutex_ = PTHREAD_MUTEX_INITIALIZER; 20 | pthread_mutex_t ThreadsPool::task_mutex_ = PTHREAD_MUTEX_INITIALIZER; 21 | pthread_cond_t ThreadsPool::pthreadCond_ = PTHREAD_COND_INITIALIZER; 22 | 23 | std::function ThreadsPool::readcb_; 24 | std::function ThreadsPool::writecb_; 25 | 26 | int ThreadsPool::thread_num_; 27 | 28 | ThreadsPool::~ThreadsPool() 29 | { 30 | delete [] pthreadId_; 31 | 32 | } 33 | 34 | //创建线程池 35 | void ThreadsPool::CreatePool() 36 | { 37 | pthreadId_ =new pthread_t[thread_num_]; 38 | for (int i=0;ifind(fd) != channel_fd_->end()) 59 | channel_fd_->find(fd)->second->HandleEvent(); 60 | } 61 | 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /luves/threadpool.h: -------------------------------------------------------------------------------- 1 | // 2 | // threads.h 3 | // Luves 4 | // 5 | // Created by leviathan on 16/5/18. 6 | // Copyright © 2016年 leviathan. All rights reserved. 7 | // 8 | 9 | #ifndef THREADS_H_ 10 | #define THREADS_H_ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include "connection.h" 19 | #include "logger.h" 20 | 21 | namespace luves 22 | { 23 | 24 | class TcpConnection; 25 | typedef std::shared_ptr TcpConnectionPtr; 26 | typedef std::function TcpCallBack; 27 | // 28 | // 29 | //线程池模块 30 | //Singleton模式 31 | // 32 | 33 | class ThreadsPool 34 | { 35 | public: 36 | static ThreadsPool & Instance() 37 | { 38 | static ThreadsPool pool; 39 | return pool; 40 | } 41 | 42 | 43 | static void AddTask(int fd) 44 | { 45 | pthread_mutex_lock(&task_mutex_); 46 | task_.push(fd); 47 | pthread_mutex_unlock(&task_mutex_); 48 | pthread_cond_signal(&pthreadCond_); 49 | }; 50 | 51 | void CreatePool(); 52 | 53 | static void * ThreadCallBack(void * data); //pthread_create()回调函数 54 | 55 | static void SetReadCb(std::function & cb){readcb_=cb;} 56 | static void SetWriteCb(std::function & cb){writecb_=cb;} 57 | 58 | static void SetChannelPtr(std::map * channel_fd) 59 | { 60 | channel_fd_ = channel_fd; 61 | } 62 | 63 | static void SetThreadNum(int thread_num) 64 | { 65 | thread_num_ = thread_num; 66 | INFO_LOG("Set the number of thread : %d", thread_num_); 67 | } 68 | 69 | private: 70 | ThreadsPool(){}; 71 | ~ThreadsPool(); 72 | ThreadsPool & operator=(ThreadsPool const &); 73 | ThreadsPool(ThreadsPool const &); 74 | 75 | static std::map * channel_fd_; 76 | static std::queue task_; 77 | static int thread_num_; 78 | pthread_t * pthreadId_; 79 | 80 | static pthread_mutex_t pthreadMutex_; 81 | static pthread_mutex_t task_mutex_; 82 | static pthread_cond_t pthreadCond_; 83 | static std::function readcb_,writecb_; 84 | }; 85 | } 86 | 87 | #endif /* threads_h */ 88 | 89 | -------------------------------------------------------------------------------- /luves/timer.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // timer.cpp 3 | // Luves 4 | // 5 | // Created by leviathan on 16/6/6. 6 | // Copyright © 2016年 leviathan. All rights reserved. 7 | // 8 | 9 | #include "timer.h" 10 | 11 | namespace luves 12 | { 13 | // 14 | //定时事件模块 15 | // 16 | 17 | Timer::Timer() 18 | { 19 | timerPL_=0; 20 | nexttimeout_=10; 21 | } 22 | 23 | //处理超时时间 24 | void Timer::HandleTimeoutEvent() 25 | { 26 | int64_t now=Timer::GetTimeSecond(); 27 | while (timertasks_.size()&&timertasks_.begin()->first.first<=now) 28 | { 29 | TimerTask task=timertasks_.begin()->second; 30 | timertasks_.erase(timertasks_.begin()); 31 | task(); 32 | } 33 | } 34 | 35 | TimerId Timer::StartTimer(int64_t delaytime,const TimerTask & task,int64_t interval) 36 | { 37 | if (interval) //重复任务 38 | { 39 | int64_t now=Timer::GetSystemTick(); 40 | TimerId tid {delaytime+now,++timerPL_}; 41 | TimerRepeat * tr=new TimerRepeat; 42 | tr->at=now+delaytime; 43 | tr->interval=interval; 44 | tr->timerid=tid; 45 | tr->taskfunc=task; 46 | timer_repeat_tasks_[tid]=*tr; 47 | 48 | timertasks_[tr->timerid]=[this,tr]{UpdateRepeatEvent(tr);}; 49 | UpdateNextTimeout(); 50 | return tr->timerid; 51 | } 52 | else //非重复任务 53 | { 54 | TimerId tid {delaytime+Timer::GetSystemTick(),++timerPL_}; 55 | timertasks_.insert({tid,task}); 56 | UpdateNextTimeout(); 57 | return tid; 58 | } 59 | } 60 | 61 | /* 62 | 定时事件存储在两个map中,一个是timertasks_,重复定时事件增加一个副本存放在timer_repeat_tasks_, 63 | timertasks_: key为timeid,value为回调函数 64 | timer_repeat_tasks_:key 为timeid,value为TimerRepeat 65 | timer_repeat_tasks_中的key为初始timeid,不会改变 66 | timer_repeat_tasks_中的value中的at变量为定时事件的最新超时时间,timeSeq为定时事件的最新唯一标识,at与timeSeq会随着定时事件的处理变化 67 | */ 68 | void Timer::UpdateRepeatEvent(TimerRepeat * tr) 69 | { 70 | timer_repeat_tasks_[tr->timerid].at+=tr->interval; 71 | timer_repeat_tasks_[tr->timerid].timerPL=++timerPL_; 72 | tr->at+=tr->interval; 73 | TimerId tid {tr->at,timerPL_}; 74 | timertasks_[tid]=[this,tr]{UpdateRepeatEvent(tr);}; 75 | 76 | UpdateNextTimeout(); 77 | 78 | tr->taskfunc(); 79 | } 80 | 81 | //更新下一个的最小等待时间 82 | void Timer::UpdateNextTimeout() 83 | { 84 | if (timertasks_.empty()) 85 | { 86 | //nexttimeout_=1<<30; 87 | } 88 | else 89 | { 90 | const TimerId & t= timertasks_.begin()->first; 91 | nexttimeout_=t.first-Timer::GetSystemTick(); 92 | nexttimeout_=nexttimeout_< 0 ? 0 : nexttimeout_; 93 | } 94 | } 95 | 96 | //取消定时事件 97 | bool Timer::StopTimer(TimerId timeid) 98 | { 99 | auto er=timer_repeat_tasks_.find(timeid); 100 | 101 | if (er==timer_repeat_tasks_.end())//非重复事件 102 | { 103 | auto e=timertasks_.find(timeid); 104 | if (e!=timertasks_.end()) 105 | { 106 | timertasks_.erase(e); 107 | } 108 | timer_repeat_tasks_.erase(er); 109 | return true; 110 | } 111 | else //重复事件 112 | { 113 | TimerId ep {er->second.at,er->second.timerPL}; 114 | auto e=timertasks_.find(ep); 115 | if (e!=timertasks_.end()) 116 | { 117 | timertasks_.erase(e); 118 | } 119 | timer_repeat_tasks_.erase(er); 120 | } 121 | return false; 122 | } 123 | 124 | //精度为秒 125 | int64_t Timer::GetTimeSecond() 126 | { 127 | std::chrono::time_point p = std::chrono::system_clock::now(); 128 | int64_t now=std::chrono::duration_cast(p.time_since_epoch()).count(); 129 | return now; 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /luves/timer.h: -------------------------------------------------------------------------------- 1 | // 2 | // timer.h 3 | // Luves 4 | // 5 | // Created by leviathan on 16/6/6. 6 | // Copyright © 2016年 leviathan. All rights reserved. 7 | // 8 | 9 | #ifndef TIMER_H_ 10 | #define TIMER_H_ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | 18 | namespace luves 19 | { 20 | 21 | typedef std::pair TimerId; 22 | typedef std::function TimerTask; 23 | 24 | 25 | //重复的定时事件数据结构 26 | struct TimerRepeat 27 | { 28 | int64_t at; //事件的当前超时时间 29 | int64_t timerPL; //事件的当前唯一id 30 | int64_t interval; //间隔时间 31 | TimerId timerid; //原始TIMEID,不会改变 32 | TimerTask taskfunc; 33 | }; 34 | 35 | // 36 | //定时事件模块 37 | // 38 | class Timer 39 | { 40 | public: 41 | Timer(); 42 | ~Timer(){}; 43 | 44 | 45 | //添加定时事件 46 | TimerId StartTimer(int64_t delaytime,const TimerTask & task,int64_t interval=0); 47 | //处理超时任务 48 | void HandleTimeoutEvent(); 49 | //更新下一个的最小等待时间 50 | void UpdateNextTimeout(); 51 | //更新重复的定时事件 52 | void UpdateRepeatEvent(TimerRepeat * tr); 53 | //取消定时事件 54 | bool StopTimer(TimerId timerid); 55 | 56 | //获取系统时间,精度是millisecond 57 | static int64_t GetSystemTick() 58 | { 59 | return (int64_t)std::chrono::duration_cast(std::chrono::steady_clock::now().time_since_epoch()).count(); 60 | } 61 | static int64_t GetSteadyTick() 62 | { 63 | return (int64_t)std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); 64 | } 65 | //获取系统时间,精度是second 66 | static int64_t GetTimeSecond(); 67 | 68 | int64_t GetNextTimeout(){return nexttimeout_;} 69 | 70 | private: 71 | int64_t nexttimeout_; //下一个定时事件的超时时间 72 | std::atomic timerPL_; //定时事件唯一ID 73 | std::map timer_repeat_tasks_; //重复的定时事件 74 | std::map timertasks_ ;//定时事件 75 | }; 76 | } 77 | 78 | #endif /* timer_h */ 79 | --------------------------------------------------------------------------------