├── LICENSE ├── README.md ├── WebBench ├── LICENSE ├── Makefile ├── README.md ├── bin │ └── web_bench ├── build.sh ├── lib │ └── libweb_bench.a ├── main.cpp ├── run_bench.sh ├── web_bench.cpp └── web_bench.h ├── WebServer ├── CMakeLists.txt ├── Makefile ├── README.md ├── build.sh ├── include │ ├── connection │ │ ├── ftp_connection.h │ │ ├── http_connection.h │ │ └── http_type.h │ ├── event │ │ ├── channel.h │ │ ├── event_loop.h │ │ ├── event_loop_thread.h │ │ ├── event_loop_thread_pool.h │ │ └── poller.h │ ├── locker │ │ └── mutex_lock.h │ ├── log │ │ ├── async_logging.h │ │ ├── log_stream.h │ │ └── logging.h │ ├── manager │ │ ├── file_manager.h │ │ ├── file_operator.h │ │ └── user_manager.h │ ├── memory │ │ └── memory_pool.h │ ├── pagecache │ │ └── lfu_cache.h │ ├── server │ │ └── web_server.h │ ├── skiplist │ │ ├── Node.h │ │ ├── Random.h │ │ └── SkipList.h │ ├── thread │ │ ├── block_queue.hpp │ │ ├── thread.h │ │ ├── thread_pool.h │ │ └── worker_thread_pool.h │ ├── timer │ │ ├── timer.h │ │ └── timer_heap.h │ └── utility │ │ ├── count_down_latch.h │ │ ├── noncopyable.h │ │ └── socket_utils.h ├── main.cpp ├── old_version │ ├── CMakeLists.txt │ ├── README.md │ ├── build.sh │ └── src │ │ ├── CMakeLists.txt │ │ ├── FTPClient │ │ ├── CMakeLists.txt │ │ └── FTPClient.cc │ │ ├── LFUCache │ │ ├── LFUCache.cc │ │ ├── LFUCache.h │ │ └── tests │ │ │ └── test_LFUCache.cc │ │ ├── Main.cc │ │ ├── base │ │ ├── AsyncLogging.cc │ │ ├── AsyncLogging.h │ │ ├── CMakeLists.txt │ │ ├── Condition.h │ │ ├── CountDownLatch.cc │ │ ├── CountDownLatch.h │ │ ├── CurrentThread.h │ │ ├── FileUtil.cc │ │ ├── FileUtil.h │ │ ├── LogFile.cc │ │ ├── LogFile.h │ │ ├── LogStream.cc │ │ ├── LogStream.h │ │ ├── Logging.cc │ │ ├── Logging.h │ │ ├── Log的设计.txt │ │ ├── MutexLock.h │ │ ├── Thread.cc │ │ ├── Thread.h │ │ ├── noncopyable.h │ │ └── tests │ │ │ ├── CMakeLists.txt │ │ │ └── LoggingTest.cc │ │ ├── client │ │ ├── CMakeLists.txt │ │ └── HTTPClient.cc │ │ ├── connection │ │ ├── CMakeLists.txt │ │ ├── connection.cc │ │ ├── connection.h │ │ ├── ftpConnection.cc │ │ ├── ftpConnection.h │ │ ├── httpConnection.cc │ │ └── httpConnection.h │ │ ├── manager │ │ ├── CMakeLists.txt │ │ ├── fileManager.cc │ │ ├── fileManager.h │ │ ├── fileOperator.cc │ │ ├── fileOperator.h │ │ ├── tests │ │ │ └── test_fileManager.cc │ │ ├── userManager.cc │ │ └── userManager.h │ │ ├── memory │ │ ├── CMakeLists.txt │ │ ├── MemoryPool.cc │ │ ├── MemoryPool.h │ │ └── tests │ │ │ ├── CMakeLists.txt │ │ │ └── test_MemoryPool.cc │ │ ├── package │ │ ├── CMakeLists.txt │ │ ├── Util.cc │ │ └── Util.h │ │ ├── page │ │ ├── favicon.ico │ │ ├── game.html │ │ ├── index.html │ │ ├── music.mp3 │ │ └── page.jpg │ │ ├── reactor │ │ ├── CMakeLists.txt │ │ ├── Channel.cc │ │ ├── Channel.h │ │ ├── Epoll.cc │ │ ├── Epoll.h │ │ ├── eventLoop.cc │ │ ├── eventLoop.h │ │ ├── old │ │ │ ├── EventLoop.cc │ │ │ ├── EventLoop.h │ │ │ ├── Timer.cc │ │ │ └── Timer.h │ │ ├── timer.cc │ │ └── timerManager.cc │ │ ├── server │ │ ├── CMakeLists.txt │ │ ├── FTPServer.cc │ │ ├── FTPServer.h │ │ ├── HTTPServer.cc │ │ └── HTTPServer.h │ │ └── threadPool │ │ ├── CMakeLists.txt │ │ ├── EventLoopThread.cc │ │ ├── EventLoopThread.h │ │ ├── EventLoopThreadPool.cc │ │ └── EventLoopThreadPool.h ├── pages │ ├── favicon.ico │ ├── game.html │ ├── index.html │ ├── music.mp3 │ └── page.jpg ├── run_server.sh └── src │ ├── client │ ├── ftp_client.cc │ └── http_client.cc │ ├── connection │ ├── ftp_connection.cpp │ ├── http_connection.cpp │ └── http_type.cpp │ ├── event │ ├── channel.cpp │ ├── event_loop.cpp │ ├── event_loop_thread.cpp │ ├── event_loop_thread_pool.cpp │ └── poller.cpp │ ├── log │ ├── async_logging.cpp │ ├── log_stream.cpp │ └── logging.cpp │ ├── manager │ ├── file_manager.cc │ ├── file_operator.cc │ └── user_manager.cc │ ├── memory │ └── memory_pool.cpp │ ├── pagecache │ └── lfu_cache.cpp │ ├── server │ └── webserver.cpp │ ├── thread │ ├── thread.cpp │ ├── thread_pool.cpp │ └── worker_thread_pool.cpp │ ├── timer │ ├── timer.cpp │ └── timer_heap.cpp │ └── utility │ └── socket_utils.cpp └── img ├── 主从Reactor模式.svg ├── 多线程异步日志库系统.svg ├── 短连接测试.jpg └── 长连接测试.jpg /README.md: -------------------------------------------------------------------------------- 1 | # a high concurrency WebServer in linux 2 | 3 | 4 | 5 | 该项目是在Linux环境下,使用C++11标准编写的一个遵循 One Loop Per Thread 思想的高性能 Web 服务器,支持一定数量的客户端连接并发连接并及时响应,支持客户端对服务器静态资源的访问,在特定端口浏览、上传和下载服务器文件。 6 | 7 | 8 | 9 | ## 技术要点 10 | 11 | - 实现了基于双缓冲技术的多线程异步日志系统,分离日志写入与业务处理,提高日志系统的写入效率。 12 | - 使用主从 Reactor 网络模式,和基于 Epoll 的 I/O 多路复用技术(ET边缘触发工作模式),提高服务器的并发处理能力。 13 | - 使用有限状态机解析 HTTP 请求,支持GET、POST、HEAD请求方法,支持HTTP长连接与短连接。 14 | - 使用小根堆做定时器,惰性删除超时的任务,即客户端没有向服务器发送请求的时间已经超过给定的超时时间,当再次访问它的时候才会去关闭这个连接。 15 | - 实现了LFU缓存淘汰策略,实现高频页面的高效传输,提高服务器响应。 16 | - 模仿STL allocator,实现了基于哈希桶的内存池,提高程序内存的利用效率。 17 | - 使用了智能指针、bind、function、右值引用、范围循环等一些 c++11 的新特性。 18 | 19 | 20 | 21 | ## 整体框架 22 | 23 | ![项目整体框架](./img/主从Reactor模式.svg) 24 | 25 | 26 | 27 | ## 项目构建 28 | 29 | 项目的基本文件结构如下: 30 | 31 | ```text 32 | ./WebServer/ 33 | ├── build.sh 34 | ├── CMakeLists.txt 35 | ├── include 36 | │ ├── cache 37 | │ ├── connection 38 | │ ├── event 39 | │ ├── locker 40 | │ ├── log 41 | │ ├── manager 42 | │ ├── memory 43 | │ ├── server 44 | │ ├── thread 45 | │ ├── timer 46 | │ └── utility 47 | ├── main.cpp 48 | ├── Makefile 49 | ├── old_version 50 | ├── pages 51 | │ ├── favicon.ico 52 | │ ├── game.html 53 | │ ├── index.html 54 | │ ├── music.mp3 55 | │ └── page.jpg 56 | ├── README.md 57 | ├── run_server.sh 58 | └── src 59 | ├── client 60 | ├── connection 61 | ├── event 62 | ├── lfuCache 63 | ├── log 64 | ├── manager 65 | ├── memory 66 | ├── server 67 | ├── thread 68 | ├── timer 69 | └── utility 70 | ``` 71 | 72 | 73 | 74 | ### 环境 75 | 76 | - 硬件平台:阿里云 轻量应用服务器 (双核4G,6M 带宽) 77 | - OS version:Ubuntu 18.04 78 | - Complier version: g++ 7.4.0 (Ubuntu 7.4.0-1ubuntu1~18.04) 79 | - cmake version: 3.10.2 80 | - Debugger version: gdb (Ubuntu 8.1.1-0ubuntu1) 8.1.1 81 | 82 | 83 | 84 | ### 构建 85 | 86 | ```shell 87 | # 切换到主目录 88 | cd ./WerServer/ 89 | # 使用脚本构建项目 90 | sh ./build.sh 91 | ``` 92 | 93 | 94 | 95 | ### 运行 96 | 97 | ```shell 98 | # 直接输入参数启动 99 | ./web_server [-p port] [-t thread_numbers] [-f log_file_name] [-o open_log] \ 100 | [-s log_to_stderr] [-c color_log_to_stderr] [-l min_log_level] \ 101 | [-d page_cache_capacity] 102 | # 使用脚本启动 103 | sh ./run_server.sh 104 | ``` 105 | 106 | - `port`:为服务器监听的端口号,默认为 8888 107 | - `thread_numbers` :为 `subReactor` 的数目,也就是业务线程池中的线程数(不包括后台的日志线程),默认为2 108 | - `log_file_name` : 为服务器日志文件的路径,默认为 `WebServer` 所在的目录,文件不存在的话程序会自动创建 109 | - `open_log` : 是否启用日志功能,1-启用 0-不启用 110 | - `log_to_stderr`:日志同时输出到 `stderr`,1-启用 0-不启用 111 | - `color_log_to_stderr`:输出日志颜色,1-启用 0-不启用 112 | - `min_log_level`:输出的最小日志等级,0-DEBUG 1-INFO 2-WARNING 3-ERROR 4-FATAL 113 | - `page_cache_capacity`: 页面缓存的最大数量,默认为10 114 | 115 | 116 | ## 压力测试 117 | 118 | 压力测试使用开源压测工具 WebBench,开启1000个进程,访问服务器60s,过程是客户端发出请求,然后服务器读取并解析,返回响应报文,客户端读取。 119 | 120 | 长连接因为不需要频繁的创建新套接字去响应请求,然后发送数据读取数据,关闭套接字等操作,所以比短连接QPS高很多。 121 | 122 | ### 参数调节 123 | 124 | - 将单个进程可以打开的文件描述符 descriptors 设置成了 10w 125 | - 程序中关闭了套接字的TCP Nagle算法, 避免响应时间过久,每次数据直接发,而不用等到一定量再一起发。 126 | 127 | 128 | 129 | ### 压测结果 130 | 131 | 本地测试: 132 | 133 | - HTTP短连接(QPS:1.8w) 134 | 135 | ![HTTP短连接测试图](./img/短连接测试.jpg) 136 | 137 | 138 | - HTTP长连接(QPS:5.2万) 139 | 140 | ![HTTP短连接测试图](./img/长连接测试.jpg) 141 | -------------------------------------------------------------------------------- /WebBench/Makefile: -------------------------------------------------------------------------------- 1 | # $^ 代表所有依赖文件 2 | # $@ 代表所有目标文件 3 | # $< 代表第一个依赖文件 4 | # % 代表通配符 5 | 6 | TARGET := web_bench 7 | STATIC_LIB := libweb_bench.a 8 | SHARED_LIB := libweb_bench.so 9 | 10 | CXX := g++ 11 | CXXFLAGS := -std=gnu++11 -Wfatal-errors -Wno-unused-parameter 12 | LDFLAGS := -Wl,-rpath=./lib 13 | INC_DIR := -I ./include 14 | LIB_DIR := -L ./ 15 | LIBS := -lpthread 16 | 17 | DEBUG := 0 18 | 19 | ifeq ($(DEBUG), 1) 20 | CXXFLAGS += -g -DDEBUG 21 | else 22 | CXXFLAGS += -O3 -DNDEBUG 23 | endif 24 | 25 | all: $(STATIC_LIB) $(TARGET) 26 | 27 | #源文件 28 | SOURCES := web_bench.cpp 29 | #所有.c源文件结尾变为.o 放入变量OBJS 30 | OBJS := $(patsubst %.cpp, %.o, $(SOURCES)) 31 | #main源文件 32 | MAIN := main.cpp 33 | MAIN_OBJ := main.o 34 | 35 | #编译 36 | %.o: %.cpp 37 | @echo -e '\e[1;32mBuilding CXX object: $@\e[0m' 38 | $(CXX) -c $^ -o $@ $(CXXFLAGS) $(INC_DIR) 39 | 40 | #链接生成静态库(这只是将源码归档到一个库文件中,什么flag都不加) @执行shell 41 | $(STATIC_LIB): $(OBJS) 42 | @echo -e '\e[1;36mLinking CXX static library: $@\e[0m' 43 | ar -rcs -o $@ $^ 44 | @echo -e '\e[1;35mBuilt target: $@\e[0m' 45 | 46 | #链接生成动态库 47 | $(SHARED_LIB): $(OBJS) 48 | @echo -e '\e[1;36mLinking CXX shared library: $@\e[0m' 49 | $(CXX) -fPIC -shared -o $@ $^ 50 | @echo -e '\e[1;35mBuilt target: $@\e[0m' 51 | 52 | #链接生成可执行文件 53 | $(TARGET): $(MAIN_OBJ) $(STATIC_LIB) 54 | @echo -e '\e[1;36mLinking CXX executable: $@\e[0m' 55 | $(CXX) -o $@ $^ $(LDFLAGS) 56 | @echo -e '\e[1;35mBuilt target: $@\e[0m' 57 | 58 | #声明这是伪目标文件 59 | .PHONY: all clean 60 | 61 | install: $(STATIC_LIB) $(TARGET) 62 | @if (test ! -d lib); then mkdir -p lib; fi 63 | @mv $(STATIC_LIB) lib 64 | @if (test ! -d bin); then mkdir -p bin; fi 65 | @mv $(TARGET) bin 66 | 67 | clean: 68 | rm -f $(OBJS) $(MAIN_OBJ) $(TARGET) $(STATIC_LIB) $(SHARED_LIB) ./bin/$(TARGET) ./lib/$(STATIC_LIB) ./lib/$(SHARED_LIB) 69 | 70 | -------------------------------------------------------------------------------- /WebBench/README.md: -------------------------------------------------------------------------------- 1 | # 开源压力测试工具WebBench 2 | 3 | ## 介绍 4 | * `WebBench` 是开源的 `Web` 性能压力测试工具。使用 `fork()` 系统调用创建多个子进程,模拟客户端去访问指定服务器。 5 | * 支持 `HTTP/0.9`, `HTTP/1.0`, `HTTP1.1` 请求,最终输出: 请求/秒,字节/秒。 6 | * 本项目使用 `C++11` 实现,核心实现在 `web_bench.cpp`,可以生成静态库和动态库提供 `api` 调用,详细的中文注释。 7 | * 修复了 `WebBench` `connect()` 失败时 `sockfd` 泄漏的bug,以及读取响应报文时读完了依然read导致阻塞的bug(因为是BIO,读完了再读就会阻塞了)。 8 | * 支持 `HTTP1.1 Connection: keep-alive`。 9 | 10 | ## 环境 11 | - 硬件平台:阿里云 轻量应用服务器 (双核4G,6M 带宽) 12 | - OS version:Ubuntu 18.04 13 | - Complier version: g++ 7.4.0 (Ubuntu 7.4.0-1ubuntu1~18.04) 14 | - cmake version: 3.10.2 15 | - Debugger version: gdb (Ubuntu 8.1.1-0ubuntu1) 8.1.1 16 | 17 | ## 构建 18 | ```shell 19 | # 使用Makefile来build 20 | make -j8 && make install 21 | # 使用脚本构建 22 | ./build.sh 23 | ``` 24 | 25 | ## 运行 26 | ```shell 27 | # 直接运行 28 | ./web_bench [-c process_num] [t request_time] url 29 | 30 | # 使用脚本运行 31 | sh ./run_bench.sh 32 | ``` 33 | 34 | ## 还有其他命令行选项: 35 | * `-k`: keep-alive 36 | * `-f`: 不等待服务器响应 37 | * `-r`: 重新请求加载(无缓存) 38 | * `-9`: 使用http0.9协议来构造请求 39 | * `-1`: 使用http1.0协议来构造请求 40 | * `-2`: 使用http1.1协议来构造请求 41 | * `-k`: 客户端是否支持keep alive 42 | * `-t`: 运行时间,单位:秒,默认为30秒 43 | * `-c`: 创建多少个客户端,默认为1个 44 | * `-p`: 使用代理服务器发送请求 45 | * `--get`: 使用GET请求方法 46 | * `--head`: 使用HEAD请求方法 47 | * `--options`: 使用OPTIONS请求方法 48 | * `--trace`: 使用TRACE请求方法 49 | * `-?|-h|--help`: 显示帮助信息 50 | * `-V|--version`: 显示版本信息 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /WebBench/bin/web_bench: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Liluoquan/a-high-concurrency-webserver-in-linux/fb360a54709082cff606b8e52a65738bacc7440e/WebBench/bin/web_bench -------------------------------------------------------------------------------- /WebBench/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #编译 4 | make clean && make -j8 && make install 5 | rm -f *.o 6 | 7 | 8 | -------------------------------------------------------------------------------- /WebBench/lib/libweb_bench.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Liluoquan/a-high-concurrency-webserver-in-linux/fb360a54709082cff606b8e52a65738bacc7440e/WebBench/lib/libweb_bench.a -------------------------------------------------------------------------------- /WebBench/main.cpp: -------------------------------------------------------------------------------- 1 | #include "web_bench.h" 2 | 3 | #include 4 | 5 | int main(int argc, char* argv[]) { 6 | //解析命令行参数 7 | ParseArg(argc, argv); 8 | 9 | const char* url = argv[optind]; 10 | //构造http请求报文 11 | BuildRequest(url); 12 | 13 | //开始执行压力测试 14 | WebBench(); 15 | 16 | return 0; 17 | } 18 | 19 | -------------------------------------------------------------------------------- /WebBench/run_bench.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | webbench=./bin/web_bench 4 | #服务器地址 5 | server_ip=127.0.0.1 6 | server_port=8888 7 | url=http://${server_ip}:${server_port}/echo 8 | 9 | #子进程数量 10 | process_num=1000 11 | #请求时间(单位s) 12 | request_time=60 13 | #keep-alive 14 | is_keep_alive=1 15 | #force 16 | is_force=0 17 | 18 | #命令行选项 19 | options="-c $process_num -t $request_time $url" 20 | 21 | if [ $is_force -eq 1 ] 22 | then 23 | options="-f $options" 24 | fi 25 | 26 | if [ $is_keep_alive -eq 1 ] 27 | then 28 | options="-k $options" 29 | fi 30 | 31 | #删除之前开的进程 32 | #kill -9 `ps -ef | grep web_bench | awk '{print $2}'` 33 | 34 | #运行 35 | $webbench $options 36 | 37 | 38 | -------------------------------------------------------------------------------- /WebBench/web_bench.h: -------------------------------------------------------------------------------- 1 | #ifndef WEB_BENCH_H_ 2 | #define WEB_BENCH_H_ 3 | 4 | void ParseArg(int argc, char* argv[]); 5 | void BuildRequest(const char* url); 6 | void WebBench(); 7 | 8 | #endif // WEB_BENCH_H_ 9 | -------------------------------------------------------------------------------- /WebServer/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(WebServer LANGUAGES CXX) 2 | cmake_minimum_required(VERSION 3.5.1) 3 | 4 | #开关 5 | set(DEBUG OFF) 6 | set(CHECK_MEMORY OFF) 7 | set(OPEN_LOGGING ON) 8 | 9 | #项目根目录 10 | set(ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}) 11 | #源码目录 12 | set(SRC_DIR ${ROOT_DIR}/src) 13 | #头文件路径 14 | set(INC_DIR ${ROOT_DIR}/include) 15 | #库文件路径 16 | set(LIB_DIR /usr/lib/x86_64-linux-gnu) 17 | #可执行文件安装路径 18 | set(EXEC_INSTALL_DIR ${ROOT_DIR}/bin) 19 | #库安装路径 20 | set(LIB_INSTALL_DIR ${ROOT_DIR}/lib) 21 | 22 | #g++ 编译选项 -Wl,-rpath指定运行时库的搜索路径 23 | #使用-Wl,-Bstatic后面的库都以静态链接,-Wl,-Bdynamic后面的库都以动态链接 24 | #还可以使用-static来避免动态链接, 此方法会导致对所有的库都以静态链接 25 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11 -Wfatal-errors -Wno-unused-parameter -Wl,-rpath=${LIB_INSTALL_DIR}") 26 | if (${DEBUG} STREQUAL "ON") 27 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g") 28 | #add_definitions(-DDEBUG) 29 | else() 30 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3") 31 | add_definitions(-DNDEBUG) 32 | endif() 33 | 34 | if (${CHECK_MEMORY} STREQUAL "ON") 35 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer") 36 | endif() 37 | 38 | if (${OPEN_LOGGING} STREQUAL "ON") 39 | add_definitions(-DOPEN_LOGGING) 40 | endif() 41 | 42 | #CPP源文件 43 | file(GLOB UTILITY_SRC_FILE ${SRC_DIR}/utility/*.cpp) 44 | file(GLOB THREAD_SRC_FILE ${SRC_DIR}/thread/*.cpp) 45 | file(GLOB TIMER_SRC_FILE ${SRC_DIR}/timer/*.cpp) 46 | file(GLOB LOG_SRC_FILE ${SRC_DIR}/log/*.cpp) 47 | file(GLOB MEMORY_SRC_FILE ${SRC_DIR}/memory/*.cpp) 48 | file(GLOB EVENT_SRC_FILE ${SRC_DIR}/event/*.cpp) 49 | file(GLOB PAGECACHE_SRC_FILE ${SRC_DIR}/pagecache/*.cpp) 50 | file(GLOB CONNECTION_SRC_FILE ${SRC_DIR}/connection/*.cpp) 51 | file(GLOB SERVER_SRC_FILE ${SRC_DIR}/server/*.cpp) 52 | set(MAIN_SRC_FILE ${ROOT_DIR}/main.cpp) 53 | 54 | set(LIBEVENT_SOURCES ${UTILITY_SRC_FILE} 55 | ${THREAD_SRC_FILE} 56 | ${TIMER_SRC_FILE} 57 | ${LOG_SRC_FILE} 58 | ${MEMORY_SRC_FILE} 59 | ${EVENT_SRC_FILE} 60 | ${PAGECACHE_SRC_FILE} 61 | ${CONNECTION_SRC_FILE} 62 | ${SERVER_SRC_FILE}) 63 | #message(${LIBEVENT_SOURCES}) 64 | 65 | #头文件路径添加 66 | include_directories(${INC_DIR}) 67 | #库文件路径添加 68 | link_directories(${LIB_DIR}) 69 | #用到的库 70 | set(LINK_LIBRARY pthread) 71 | 72 | #生成动态链接库 73 | add_library(event_shared SHARED ${LIBEVENT_SOURCES}) 74 | #更改动态链接库输出名字 75 | set_target_properties(event_shared PROPERTIES OUTPUT_NAME event) 76 | #设置动态链接库版本号 77 | set_target_properties(event_shared PROPERTIES VERSION 1.2 SOVERSION 1) 78 | #链接库 79 | target_link_libraries(event_shared ${LINK_LIBRARY}) 80 | 81 | #生成静态库 82 | add_library(event_static STATIC ${LIBEVENT_SOURCES}) 83 | #更改静态库输出名字 84 | set_target_properties(event_static PROPERTIES OUTPUT_NAME event) 85 | #链接库 86 | target_link_libraries(event_static ${LINK_LIBRARY}) 87 | 88 | #将静态库链接 生成可执行文件 89 | add_executable(web_server ${MAIN_SRC_FILE}) 90 | #链接库 91 | target_link_libraries(web_server event_static ${LINK_LIBRARY}) 92 | 93 | #将所有源文件链接 生成可执行文件 94 | #add_executable(web_server ${LIBEVENT_SOURCES} ${MAIN_SRC_FILE}) 95 | #链接库 96 | #target_link_libraries(web_server ${LINK_LIBRARY}) 97 | 98 | #安装 99 | install(TARGETS event_shared event_static DESTINATION ${LIB_INSTALL_DIR}) 100 | install(TARGETS web_server DESTINATION ${EXEC_INSTALL_DIR}) 101 | -------------------------------------------------------------------------------- /WebServer/Makefile: -------------------------------------------------------------------------------- 1 | # $^ 代表所有依赖文件 2 | # $@ 代表所有目标文件 3 | # $< 代表第一个依赖文件 4 | # % 代表通配符 5 | 6 | TARGET := web_server 7 | STATIC_LIB := libevent.a 8 | SHARED_LIB := libevent.so 9 | 10 | CXX := g++ 11 | CXXFLAGS := -std=gnu++11 -Wfatal-errors -Wno-unused-parameter 12 | LDFLAGS := -Wl,-rpath=./lib 13 | #LDFLAGS := -Wl,-rpath=./lib -Wl,-Bstatic 14 | #LDFLAGS := -Wl,-rpath=./lib -Wl,-Bdynamic 15 | INC_DIR := -I ./include 16 | LIB_DIR := -L ./ 17 | LIBS := -lpthread 18 | 19 | DEBUG := 0 20 | OPEN_LOGGING := 1 21 | 22 | ifeq ($(DEBUG), 1) 23 | CXXFLAGS += -g -DDEBUG 24 | else 25 | CXXFLAGS += -O3 -DNDEBUG 26 | endif 27 | 28 | ifeq ($(OPEN_LOGGING), 1) 29 | CXXFLAGS += -DOPEN_LOGGING 30 | endif 31 | 32 | all: $(STATIC_LIB) $(TARGET) 33 | 34 | #源文件 35 | SOURCES := $(wildcard src/utility/*.cpp \ 36 | src/thread/*.cpp \ 37 | src/timer/*.cpp \ 38 | src/log/*.cpp \ 39 | src/http/*.cpp \ 40 | src/event/*.cpp \ 41 | src/server/*.cpp) 42 | #所有.c源文件结尾变为.o 放入变量OBJS 43 | OBJS := $(patsubst %.cpp, %.o, $(SOURCES)) 44 | #main源文件 45 | MAIN := main.cpp 46 | MAIN_OBJ := main.o 47 | 48 | #编译 49 | %.o: %.cpp 50 | @echo -e '\e[1;32mBuilding CXX object: $@\e[0m' 51 | $(CXX) -c $^ -o $@ $(CXXFLAGS) $(INC_DIR) 52 | 53 | #链接生成静态库(这只是将源码归档到一个库文件中,什么flag都不加) @执行shell 54 | $(STATIC_LIB): $(OBJS) 55 | @echo -e '\e[1;36mLinking CXX static library: $@\e[0m' 56 | ar -rcs -o $@ $^ 57 | @echo -e '\e[1;35mBuilt target: $@\e[0m' 58 | 59 | # 链接生成动态库 60 | $(SHARED_LIB): $(OBJS) 61 | @echo -e '\e[1;36mLinking CXX shared library: $@\e[0m' 62 | $(CXX) -fPIC -shared -o $@ $^ $(LIB_DIR) $(LIBS) 63 | @echo -e '\e[1;35mBuilt target: $@\e[0m' 64 | 65 | # 链接生成可执行文件 66 | $(TARGET): $(MAIN_OBJ) $(STATIC_LIB) 67 | @echo -e '\e[1;36mLinking CXX executable: $@\e[0m' 68 | $(CXX) -o $@ $^ $(LDFLAGS) $(LIB_DIR) $(LIBS) 69 | @echo -e '\e[1;35mBuilt target: $@\e[0m' 70 | 71 | # 声明这是伪目标文件 72 | .PHONY: all clean 73 | 74 | install: $(STATIC_LIB) 75 | @if (test ! -d lib); then mkdir -p lib; fi 76 | @mv $^ ./lib 77 | 78 | install: $(TARGET) 79 | @if (test ! -d bin); then mkdir -p bin; fi 80 | @mv $^ ./bin 81 | 82 | clean: 83 | rm -f $(OBJS) $(MAIN_OBJ) $(TARGET) $(STATIC_LIB) $(SHARED_LIB) ./bin/$(TARGET) ./lib/$(STATIC_LIB) ./lib/$(SHARED_LIB) 84 | 85 | -------------------------------------------------------------------------------- /WebServer/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #用makefile还是cmake 4 | use_make=0 5 | build_dir=./build 6 | 7 | if [ $use_make -eq 1 ] 8 | then 9 | # Makefile 10 | make clean && make -j8 && make install 11 | else 12 | # cmake 判断文件夹是否存在 13 | if [ ! -d $build_dir ] 14 | then 15 | mkdir $build_dir 16 | else 17 | rm -r $build_dir 18 | mkdir $build_dir 19 | fi 20 | 21 | cd $build_dir 22 | cmake .. && make -j8 && make install 23 | cd .. 24 | fi 25 | 26 | # flush_core 27 | # rm -f $log_file_name 28 | -------------------------------------------------------------------------------- /WebServer/include/connection/ftp_connection.h: -------------------------------------------------------------------------------- 1 | // @Author: Lawson 2 | // @CreateDate: 2022/05/14 3 | // @LastModifiedDate: 2022/05/15 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include // for transform command 17 | #include 18 | 19 | #include "manager/file_operator.h" 20 | #include "event/channel.h" 21 | #include "manager/user_manager.h" 22 | 23 | // 命令分隔符 24 | #define SEPARATOR " " 25 | 26 | namespace connection 27 | { 28 | 29 | enum ProcessState { 30 | //LOGIN_ERROR = 0, // 登录错误(密码或用户名错误) 31 | QUIT = 0, 32 | UPLOAD, 33 | LOGIN, 34 | PARSE, 35 | }; 36 | 37 | 38 | class ftpConnection { 39 | public: 40 | using CallBack = std::function; 41 | public: 42 | ftpConnection(std::shared_ptr ftpChannel, unsigned int connId, std::string defaultDir, unsigned short commandOffset = 1); 43 | virtual ~ftpConnection(); 44 | 45 | std::vector extractParameters(std::string command); 46 | void run(); 47 | int getFD(); 48 | size_t getConnectionId(); 49 | 50 | private: 51 | std::shared_ptr ftpChannel_; 52 | ProcessState processState_; 53 | manager::UserManager::userManagerPtr userManager_; 54 | std::string dir_; 55 | std::shared_ptr fo_; // For browsing, writing and reading 56 | 57 | 58 | CallBack callBackFunc[4]; 59 | 60 | size_t filePart_; 61 | std::vector directories_; 62 | std::vector files_; 63 | size_t connectionId_; 64 | std::string parameter_; 65 | 66 | void sendToClient(std::string response); 67 | bool commandEquals(std::string a, std::string b); 68 | std::string filterOutBlanks(std::string inString); 69 | static void getAllParametersAfter(std::vector parameterVector, unsigned int currentParameter, std::string& theRest); 70 | unsigned short commandOffset_; 71 | std::string inBuffer_; 72 | std::string outBuffer_; 73 | 74 | 75 | ProcessState login(); 76 | ProcessState quit(); 77 | ProcessState commandParser(); 78 | ProcessState upload(); 79 | ProcessState download(); 80 | 81 | void handleRead(); 82 | void handleWrite(); 83 | }; 84 | 85 | } // namespace connection 86 | 87 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /WebServer/include/connection/http_connection.h: -------------------------------------------------------------------------------- 1 | #ifndef HTTP_HTTP_CONNECTION_H_ 2 | #define HTTP_HTTP_CONNECTION_H_ 3 | 4 | #include "http_type.h" 5 | 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "timer/timer.h" 15 | #include "pagecache/lfu_cache.h" 16 | 17 | //类的前置声明 18 | namespace event { 19 | class Channel; 20 | class EventLoop; 21 | } // namespace event 22 | 23 | namespace http { 24 | // std::enable_shared_from_this 当类http被std::shared_ptr管理, 25 | // 且在类http的成员函数里需要把当前类对象作为参数传给其他函数时,就需要传递一个指向自身的std::shared_ptr 26 | class HttpConnection : public std::enable_shared_from_this { 27 | public: 28 | HttpConnection(event::EventLoop* event_loop, int connect_fd); 29 | ~HttpConnection(); 30 | 31 | void Register(); //给fd注册默认事件(可读 | ET触发 | ONESHOT即只执行一次,下次epoll_wait不会触发了) 32 | void Delete(); //从epoll事件表中删除fd(绑定的定时器被删除时 会调用此函数),然后http连接释放,会close掉fd 33 | void Reset(); //重置HTTP状态 34 | void ResetTimer(); //重新加入定时器 35 | 36 | void set_timer(std::shared_ptr timer) { 37 | timer_ = timer; 38 | } 39 | 40 | std::shared_ptr connect_channel() { 41 | return connect_channel_; 42 | } 43 | 44 | int connect_fd() const { 45 | return connect_fd_; 46 | } 47 | 48 | private: 49 | void HandleRead(); //处理读回调 读请求报文数据到read_buffer 解析请求报文 构建响应报文并写入write_buffer 50 | void HandleWrite(); //处理写回调 向客户端发送write_buffer中的响应报文数据 51 | void HandleUpdate(); //处理更新事件回调 52 | void ReturnErrorMessage(int fd, int error_code, std::string error_message); //构建错误信息的响应(返回错误信息) 53 | 54 | LineState ParseRequestLine(); //解析uri(请求行) 55 | HeaderState ParseRequestHeader(); //解析请求头, post方法就再解析请求体 56 | ResponseState BuildResponse(); //构建响应报文并写入write_buffer 57 | 58 | private: 59 | static constexpr int kDefaultEvent = EPOLLIN | EPOLLET | EPOLLONESHOT; //默认事件 60 | static constexpr int kDefaultTimeOut = 2 * 1000; //默认超时时间 ms 61 | static constexpr int kDefaultKeepAliveTime = 5 * 60 * 1000; //默认长连接保持时间 ms 62 | 63 | int connect_fd_; //连接套接字fd 64 | event::EventLoop* event_loop_; //事件循环 65 | std::shared_ptr connect_channel_; //连接套接字的管道 66 | std::weak_ptr timer_; //定时器 67 | std::string read_buffer_; //读缓冲区 68 | std::string write_buffer_; //写缓冲区 69 | 70 | ProcessState process_state_; //处理状态 71 | ConnectionState connection_state_; //服务器和客户端的连接状态 72 | ParseState parse_state_; //解析状态 73 | RequestMethod method_; //http请求方法 74 | HttpVersion version_; //http版本 75 | 76 | std::string file_name_; //请求文件名 77 | std::string resource_dir_; //资源路径 78 | std::map request_headers_; //请求头字段 79 | bool is_error_; //是否发生错误 80 | bool is_keep_alive_; //是否长连接 81 | }; 82 | 83 | } // namespace http 84 | 85 | #endif // HTTP_HTTP_CONNECTION_H_ 86 | -------------------------------------------------------------------------------- /WebServer/include/connection/http_type.h: -------------------------------------------------------------------------------- 1 | #ifndef HTTP_HTTP_TYPE_H_ 2 | #define HTTP_HTTP_TYPE_H_ 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include "timer/timer.h" 12 | 13 | namespace http { 14 | //图标 15 | extern char web_server_favicon[555]; 16 | 17 | //http mime文件类型 18 | class MimeType { 19 | public: 20 | static std::string get_mime(const std::string& type); 21 | 22 | private: 23 | MimeType(); 24 | MimeType(const MimeType& mime_type); 25 | 26 | static void OnceInit(); 27 | 28 | private: 29 | static std::unordered_map mime_map; 30 | static pthread_once_t once_control; 31 | }; 32 | 33 | //处理状态 34 | enum ProcessState { 35 | STATE_PARSE_LINE, 36 | STATE_PARSE_HEADERS, 37 | STATE_RECV_BODY, 38 | STATE_RESPONSE, 39 | STATE_FINISH 40 | }; 41 | 42 | //解析uri(请求行)的状态 43 | enum LineState { 44 | PARSE_LINE_SUCCESS, 45 | PARSE_LINE_AGAIN, 46 | PARSE_LINE_ERROR, 47 | }; 48 | 49 | //解析请求头的状态 50 | enum HeaderState { 51 | PARSE_HEADER_SUCCESS, 52 | PARSE_HEADER_AGAIN, 53 | PARSE_HEADER_ERROR 54 | }; 55 | 56 | //构建响应报文时的状态 57 | enum ResponseState { 58 | RESPONSE_SUCCESS, 59 | RESPONSE_ERROR 60 | }; 61 | 62 | //解析状态 63 | enum ParseState { 64 | START, 65 | KEY, 66 | COLON, 67 | SPACES_AFTER_COLON, 68 | VALUE, 69 | CR, 70 | LF, 71 | END_CR, 72 | END_LF 73 | }; 74 | 75 | //服务器和客户端的连接状态 76 | enum ConnectionState { 77 | CONNECTED, 78 | DISCONNECTING, 79 | DISCONNECTED 80 | }; 81 | 82 | //Http请求方法 83 | enum RequestMethod { 84 | METHOD_GET, 85 | METHOD_POST, 86 | METHOD_HEAD 87 | }; 88 | 89 | //Http版本 90 | enum HttpVersion { 91 | HTTP_1_0, 92 | HTTP_1_1 93 | }; 94 | 95 | } // namespace http 96 | 97 | #endif // HTTP_HTTP_TYPE_H_ -------------------------------------------------------------------------------- /WebServer/include/event/channel.h: -------------------------------------------------------------------------------- 1 | #ifndef EVENT_CHANNEL_H_ 2 | #define EVENT_CHANNEL_H_ 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "http/http_connection.h" 12 | 13 | namespace event { 14 | // Channel封装了一系列fd对应的操作 使用EventCallBack回调函数的手法 15 | // 包括处理读 处理写 处理错误 处理连接4个回调函数 16 | // fd一般是tcp连接connfd(套接字fd), 或者timerfd(定时器fd),文件fd 17 | class Channel { 18 | public: 19 | typedef std::function EventCallBack; 20 | 21 | Channel(); 22 | explicit Channel(int fd); 23 | ~Channel(); 24 | 25 | //IO事件的回调函数 EventLoop中调用Loop开始事件循环 会调用Poll得到就绪事件 26 | //然后依次调用此函数处理就绪事件 27 | void HandleEvents(); 28 | void HandleRead(); //处理读事件的回调 29 | void HandleWrite(); //处理写事件的回调 30 | void HandleUpdate(); //处理更新事件的回调 31 | void HandleError(); //处理错误事件的回调 32 | 33 | int fd() const { 34 | return fd_; 35 | } 36 | 37 | void set_fd(int fd) { 38 | fd_ = fd; 39 | } 40 | 41 | //返回weak_ptr所指向的shared_ptr对象 42 | std::shared_ptr holder() { 43 | std::shared_ptr http(holder_.lock()); 44 | return http; 45 | } 46 | 47 | void set_holder(std::shared_ptr holder) { 48 | holder_ = holder; 49 | } 50 | 51 | void set_read_handler(EventCallBack&& read_handler) { 52 | read_handler_ = read_handler; 53 | } 54 | 55 | void set_write_handler(EventCallBack&& write_handler) { 56 | write_handler_ = write_handler; 57 | } 58 | 59 | void set_update_handler(EventCallBack&& update_handler) { 60 | update_handler_ = update_handler; 61 | } 62 | 63 | void set_error_handler(EventCallBack&& error_handler) { 64 | error_handler_ = error_handler; 65 | } 66 | 67 | void set_revents(int revents) { 68 | revents_ = revents; 69 | } 70 | 71 | int& events() { 72 | return events_; 73 | } 74 | 75 | void set_events(int events) { 76 | events_ = events; 77 | } 78 | 79 | int last_events() const { 80 | return last_events_; 81 | } 82 | 83 | bool update_last_events() { 84 | bool is_events_changed = (last_events_ == events_); 85 | last_events_ = events_; 86 | return is_events_changed; 87 | } 88 | 89 | private: 90 | int fd_; //Channel的fd 91 | int events_; //Channel正在监听的事件 92 | int revents_; //返回的就绪事件 93 | int last_events_; //上一此事件(主要用于记录如果本次事件和上次事件一样 就没必要调用epoll_mod) 94 | 95 | //weak_ptr是一个观测者(不会增加或减少引用计数),同时也没有重载->,和*等运算符 所以不能直接使用 96 | //可以通过lock函数得到它的shared_ptr(对象没销毁就返回,销毁了就返回空shared_ptr) 97 | //expired函数判断当前对象是否销毁了 98 | std::weak_ptr holder_; 99 | 100 | EventCallBack read_handler_; 101 | EventCallBack write_handler_; 102 | EventCallBack update_handler_; 103 | EventCallBack error_handler_; 104 | }; 105 | 106 | } // namespace event 107 | 108 | #endif // EVENT_CHANNEL_H_ -------------------------------------------------------------------------------- /WebServer/include/event/event_loop.h: -------------------------------------------------------------------------------- 1 | #ifndef EVENT_EVENT_LOOP_H_ 2 | #define EVENT_EVENT_LOOP_H_ 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "channel.h" 12 | #include "poller.h" 13 | #include "thread/thread.h" 14 | #include "locker/mutex_lock.h" 15 | #include "utility/socket_utils.h" 16 | 17 | namespace event { 18 | // Reactor模式的核心 每个Reactor线程内部调用一个EventLoop 19 | // 内部不停的进行epoll_wait调用 然后调用fd对应Channel的相应回调函数进行处理 20 | class EventLoop { 21 | public: 22 | typedef std::function Function; 23 | 24 | //初始化poller, event_fd,给event_fd注册到epoll中并注册其事件处理回调 25 | EventLoop(); 26 | ~EventLoop(); 27 | 28 | //开始事件循环 调用该函数的线程必须是该EventLoop所在线程,也就是Loop函数不能跨线程调用 29 | void Loop(); 30 | 31 | //停止Loop 32 | void StopLoop(); 33 | 34 | //如果当前线程就是创建此EventLoop的线程 就调用callback(关闭连接 EpollDel) 否则就放入等待执行函数区 35 | void RunInLoop(Function&& func); 36 | //把此函数放入等待执行函数区 如果当前是跨线程 或者正在调用等待的函数则唤醒 37 | void QueueInLoop(Function&& func); 38 | 39 | //把fd和绑定的事件注册到epoll内核事件表 40 | void PollerAdd(std::shared_ptr channel, int timeout = 0) { 41 | poller_->EpollAdd(channel, timeout); 42 | } 43 | 44 | //在epoll内核事件表修改fd所绑定的事件 45 | void PollerMod(std::shared_ptr channel, int timeout = 0) { 46 | poller_->EpollMod(channel, timeout); 47 | } 48 | 49 | //从epoll内核事件表中删除fd及其绑定的事件 50 | void PollerDel(std::shared_ptr channel) { 51 | poller_->EpollDel(channel); 52 | } 53 | 54 | //只关闭连接(此时还可以把缓冲区数据写完再关闭) 55 | void ShutDown(std::shared_ptr channel) { 56 | utility::ShutDownWR(channel->fd()); 57 | } 58 | 59 | bool is_in_loop_thread() const { 60 | return thread_id_ == current_thread::thread_id(); 61 | } 62 | 63 | private: 64 | //创建eventfd 类似管道的 进程间通信方式 65 | static int CreateEventfd(); 66 | 67 | void HandleRead(); //eventfd的读回调函数(因为event_fd写了数据,所以触发可读事件,从event_fd读数据) 68 | void HandleUpdate(); //eventfd的更新事件回调函数(更新监听事件) 69 | void WakeUp(); //异步唤醒SubLoop的epoll_wait(向event_fd中写入数据) 70 | void PerformPendingFunctions(); //执行正在等待的函数(SubLoop注册EpollAdd连接套接字以及绑定事件的函数) 71 | 72 | private: 73 | std::shared_ptr poller_; //io多路复用 分发器 74 | int event_fd_; //用于异步唤醒SubLoop的Loop函数中的Poll(epoll_wait因为还没有注册fd会一直阻塞) 75 | std::shared_ptr wakeup_channel_; //用于异步唤醒的channel 76 | pid_t thread_id_; //线程id 77 | 78 | mutable locker::MutexLock mutex_; 79 | std::vector pending_functions_; //正在等待处理的函数 80 | 81 | bool is_stop_; //是否停止事件循环 82 | bool is_looping_; //是否正在事件循环 83 | bool is_event_handling_; //是否正在处理事件 84 | bool is_calling_pending_functions_; //是否正在调用等待处理的函数 85 | }; 86 | 87 | } // namespace event 88 | 89 | #endif // EVENT_EVENT_LOOP_H_ -------------------------------------------------------------------------------- /WebServer/include/event/event_loop_thread.h: -------------------------------------------------------------------------------- 1 | #ifndef EVENT_EVENT_LOOP_THREAD_H_ 2 | #define EVENT_EVENT_LOOP_THREAD_H_ 3 | 4 | #include "event_loop.h" 5 | 6 | namespace event { 7 | //IO线程 8 | class EventLoopThread : utility::NonCopyAble { 9 | public: 10 | EventLoopThread(); 11 | ~EventLoopThread(); 12 | 13 | //执行线程函数, 在线程函数还没运行起来的时候 一直阻塞 运行起来了才唤醒返回该event_loop 14 | EventLoop* StartLoop(); 15 | 16 | private: 17 | //线程函数(就是EventLoop的Loop函数) 18 | void Worker(); 19 | 20 | private: 21 | EventLoop* sub_loop_; //子loop 22 | thread::Thread thread_; //线程对象 23 | mutable locker::MutexLock mutex_; 24 | locker::ConditionVariable condition_; 25 | bool is_exiting_; 26 | }; 27 | 28 | } // namespace event 29 | 30 | #endif // EVENT_EVENT_LOOP_THREAD_H_ 31 | -------------------------------------------------------------------------------- /WebServer/include/event/event_loop_thread_pool.h: -------------------------------------------------------------------------------- 1 | #ifndef EVENT_EVENT_LOOP_THREAD_POOL_H_ 2 | #define EVENT_EVENT_LOOP_THREAD_POOL_H_ 3 | 4 | #include "event_loop_thread.h" 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | namespace event { 11 | //IO线程池 12 | class EventLoopThreadPool : utility::NonCopyAble { 13 | public: 14 | EventLoopThreadPool(EventLoop* main_loop, int thread_num); 15 | ~EventLoopThreadPool(); 16 | 17 | void Start(); 18 | EventLoop* GetNextLoop(); 19 | 20 | private: 21 | EventLoop* main_loop_; 22 | bool is_started_; 23 | int thread_num_; 24 | int next_; 25 | std::vector> sub_loop_threads_; 26 | std::vector sub_loops_; 27 | }; 28 | 29 | } // namespace event 30 | 31 | #endif // EVENT_EVENT_LOOP_THREAD_POOL_H_ 32 | -------------------------------------------------------------------------------- /WebServer/include/event/poller.h: -------------------------------------------------------------------------------- 1 | #ifndef EVENT_POLLER_H_ 2 | #define EVENT_POLLER_H_ 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include "timer/timer_heap.h" 11 | #include "utility/noncopyable.h" 12 | 13 | //类的前置声明 14 | namespace http { 15 | class HttpConnection; 16 | } // namespace http 17 | 18 | namespace event { 19 | //类的前置声明 20 | class Channel; 21 | 22 | //IO多路复用类 23 | class Poller : utility::NonCopyAble { 24 | public: 25 | //创建epoll内核事件表 给就绪事件,所有channel,以及对应http连接开辟内存空间 26 | explicit Poller(int thread_id_ = 0); 27 | ~Poller(); 28 | 29 | //epoll_wait 等待就绪事件,然后处理就绪事件 30 | std::vector> Poll(); 31 | 32 | // 注册新描述符(如果传入的超时时间大于0 就给此fd绑定一个定时器 以及绑定http连接) 33 | void EpollAdd(std::shared_ptr channel, int timeout); 34 | // 修改描述符状态(如果传入的超时时间大于0 就给此fd绑定一个定时器) 35 | void EpollMod(std::shared_ptr channel, int timeout); 36 | // 从epoll中删除描述符 37 | void EpollDel(std::shared_ptr channel); 38 | 39 | //添加定时器 40 | void AddTimer(std::shared_ptr channel, int timeout); 41 | //处理超时 42 | void HandleExpire(); 43 | 44 | int epoll_fd() { 45 | return epoll_fd_; 46 | } 47 | 48 | private: 49 | static constexpr int kMaxFdNum = 100000; //最大fd数量 50 | static constexpr int kMaxEventsNum = 4096; //最大事件数量 51 | static constexpr int kEpollTimeOut = 10000; //epoll wait的超时时间 52 | 53 | int epoll_fd_; //epoll的文件描述符 54 | std::vector ready_events_; //就绪事件 55 | std::shared_ptr ready_channels_[kMaxFdNum]; //就绪fd的channel 56 | std::shared_ptr http_connections_[kMaxFdNum]; //http连接对象 57 | timer::TimerHeap timer_heap_; //定时器小顶堆 58 | 59 | int thread_id_; 60 | int connection_num_; 61 | }; 62 | 63 | } // namespace event 64 | 65 | #endif // EVENT_POLLER_H_ 66 | -------------------------------------------------------------------------------- /WebServer/include/locker/mutex_lock.h: -------------------------------------------------------------------------------- 1 | #ifndef LOCKER_MUTEX_LOCK_H_ 2 | #define LOCKER_MUTEX_LOCK_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "utility/noncopyable.h" 9 | 10 | namespace locker { 11 | class ConditionVariable; 12 | 13 | //c++类不指定默认private方式继承 14 | //private继承的父类的public, protected都会成为子类的private 15 | class MutexLock : utility::NonCopyAble { 16 | public: 17 | MutexLock() { 18 | pthread_mutex_init(&mutex_, NULL); 19 | } 20 | 21 | ~MutexLock() { 22 | //要先拿到锁 再释放锁 因为直接释放锁 其他在用锁的地方就相当于失效了 23 | pthread_mutex_lock(&mutex_); 24 | pthread_mutex_destroy(&mutex_); 25 | } 26 | 27 | void lock() { 28 | pthread_mutex_lock(&mutex_); 29 | } 30 | 31 | void unlock() { 32 | pthread_mutex_unlock(&mutex_); 33 | } 34 | 35 | pthread_mutex_t* get() { 36 | return &mutex_; 37 | } 38 | 39 | private: 40 | pthread_mutex_t mutex_; 41 | 42 | // 友元类不受访问权限影响 43 | friend class ConditionVariable; 44 | }; 45 | 46 | //互斥锁RAII 47 | class LockGuard : utility::NonCopyAble { 48 | public: 49 | explicit LockGuard(MutexLock& mutex) 50 | : mutex_(mutex) { 51 | mutex_.lock(); 52 | } 53 | 54 | ~LockGuard() { 55 | mutex_.unlock(); 56 | } 57 | 58 | private: 59 | MutexLock& mutex_; 60 | }; 61 | 62 | //条件变量 63 | class ConditionVariable : utility::NonCopyAble { 64 | public: 65 | explicit ConditionVariable(MutexLock& mutex) 66 | : mutex_(mutex) { 67 | pthread_cond_init(&cond_, NULL); 68 | } 69 | 70 | ~ConditionVariable() { 71 | pthread_cond_destroy(&cond_); 72 | } 73 | 74 | void wait() { 75 | pthread_cond_wait(&cond_, mutex_.get()); 76 | } 77 | 78 | bool wait_for_seconds(int seconds) { 79 | struct timespec abstime; 80 | clock_gettime(CLOCK_REALTIME, &abstime); 81 | abstime.tv_sec += static_cast(seconds); 82 | return ETIMEDOUT == pthread_cond_timedwait(&cond_, mutex_.get(), &abstime); 83 | } 84 | 85 | void notify() { 86 | pthread_cond_signal(&cond_); 87 | } 88 | 89 | void notify_all() { 90 | pthread_cond_broadcast(&cond_); 91 | } 92 | 93 | private: 94 | MutexLock& mutex_; 95 | pthread_cond_t cond_; 96 | }; 97 | 98 | } // namespace locker 99 | 100 | #endif // LOCKER_MUTEX_LOCK_H_ 101 | -------------------------------------------------------------------------------- /WebServer/include/log/async_logging.h: -------------------------------------------------------------------------------- 1 | #ifndef LOG_ASYNC_LOGGING_H_ 2 | #define LOG_ASYNC_LOGGING_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "log_stream.h" 9 | #include "locker/mutex_lock.h" 10 | #include "utility/count_down_latch.h" 11 | #include "thread/thread.h" 12 | 13 | namespace log { 14 | // 操作文件的工具类 15 | class FileUtils { 16 | public: 17 | explicit FileUtils(std::string file_name) 18 | : fp_(fopen(file_name.c_str(), "ae")) { 19 | setbuffer(fp_, buffer_, sizeof(buffer_)); 20 | } 21 | 22 | ~FileUtils() { 23 | fclose(fp_); 24 | } 25 | 26 | // 写日志到文件 27 | void Write(const char* single_log, const size_t size) { 28 | size_t write_size = fwrite_unlocked(single_log, 1, size, fp_); 29 | // 剩余size 30 | size_t remain_size = size - write_size; 31 | //如果一次没写完 就继续写 32 | while (remain_size > 0) { 33 | size_t bytes = fwrite_unlocked(single_log + write_size, 1, remain_size, fp_); 34 | if (bytes == 0) { 35 | if (ferror(fp_)) { 36 | perror("Write to log file failed"); 37 | } 38 | break; 39 | } 40 | write_size += bytes; 41 | remain_size = size - write_size; 42 | } 43 | } 44 | 45 | void Flush() { 46 | fflush(fp_); 47 | } 48 | 49 | private: 50 | FILE* fp_; 51 | char buffer_[64 * 1024]; 52 | }; 53 | 54 | // 日志文件 封装了FileUtils 55 | class LogFile : utility::NonCopyAble { 56 | public: 57 | // 每写flush_every_n次,就会flush一次 58 | LogFile(const std::string& file_name, int flush_every_n = 1024) 59 | : file_name_(file_name), 60 | flush_every_n_(flush_every_n), 61 | count_(0), 62 | mutex_() { 63 | file_.reset(new FileUtils(file_name)); 64 | } 65 | 66 | ~LogFile() { 67 | } 68 | 69 | // 写日志到文件 70 | void Write(const char* single_log, int size) { 71 | locker::LockGuard lock(mutex_); 72 | { 73 | // 每写flush_every_n次,就会flush一次 74 | file_->Write(single_log, size); 75 | ++count_; 76 | if (count_ >= flush_every_n_) { 77 | count_ = 0; 78 | file_->Flush(); 79 | } 80 | } 81 | } 82 | 83 | void Flush() { 84 | locker::LockGuard lock(mutex_); 85 | { 86 | file_->Flush(); 87 | } 88 | } 89 | 90 | private: 91 | const std::string file_name_; 92 | const int flush_every_n_; 93 | int count_; 94 | locker::MutexLock mutex_; 95 | std::unique_ptr file_; 96 | }; 97 | 98 | class AsyncLogging : utility::NonCopyAble { 99 | using Buffer = FixedBuffer; 100 | public: 101 | AsyncLogging(const std::string file_name, int flush_interval = 2); 102 | ~AsyncLogging(); 103 | 104 | void WriteLog(const char* single_log, int size, bool is_quit = false); //将日志写入buffer输出缓冲区中 105 | void Start(); //开始线程 106 | void Stop(); //停止线程 107 | 108 | private: 109 | void Worker(); //线程函数 将buffer的数据写入日志文件 110 | 111 | private: 112 | std::string file_name_; 113 | const int timeout_; 114 | bool is_running_; 115 | 116 | std::shared_ptr current_buffer_; 117 | std::shared_ptr next_buffer_; 118 | std::vector> buffers_; 119 | 120 | thread::Thread thread_; 121 | mutable locker::MutexLock mutex_; 122 | locker::ConditionVariable condition_; 123 | utility::CountDownLatch count_down_latch_; 124 | }; 125 | 126 | } // namespace log 127 | 128 | #endif // LOG_ASYNC_LOGGING_H_ -------------------------------------------------------------------------------- /WebServer/include/log/logging.h: -------------------------------------------------------------------------------- 1 | #ifndef LOG_LOGGING_H_ 2 | #define LOG_LOGGING_H_ 3 | 4 | #define OPEN_LOGGING 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "log_stream.h" 12 | 13 | namespace log { 14 | class Logging { 15 | public: 16 | Logging(const char* file_name, int line, int level); 17 | ~Logging(); 18 | 19 | static std::string log_file_name() { 20 | return log_file_name_; 21 | } 22 | 23 | static void set_log_file_name(std::string log_file_name) { 24 | log_file_name_ = log_file_name; 25 | } 26 | 27 | static bool open_log() { 28 | return open_log_; 29 | } 30 | 31 | static void set_open_log(bool open_log) { 32 | open_log_ = open_log; 33 | } 34 | 35 | static void set_log_to_stderr(bool log_to_stderr) { 36 | log_to_stderr_ = log_to_stderr; 37 | } 38 | 39 | static void set_color_log_to_stderr(bool color_log_to_stderr) { 40 | color_log_to_stderr_ = color_log_to_stderr; 41 | } 42 | 43 | static void set_min_log_level(int min_log_level) { 44 | min_log_level_ = min_log_level; 45 | } 46 | 47 | LogStream& stream() { 48 | return impl_.stream_; 49 | } 50 | 51 | private: 52 | class Impl { 53 | public: 54 | Impl(const char* file_name, int line, int level); 55 | void FormatLevel(); 56 | void FormatTime(); 57 | 58 | LogStream stream_; 59 | std::string file_name_; 60 | int line_; 61 | int level_; 62 | std::string level_str_; 63 | std::string log_color_; 64 | char time_str_[26]; 65 | bool is_fatal_; 66 | }; 67 | 68 | private: 69 | static std::string log_file_name_; 70 | static bool open_log_; 71 | static bool log_to_stderr_; 72 | static bool color_log_to_stderr_; 73 | static int min_log_level_; 74 | 75 | Impl impl_; 76 | }; 77 | 78 | } // namespace log 79 | 80 | enum LogLevel { 81 | DEBUG = 0, 82 | INFO, 83 | WARNING, 84 | ERROR, 85 | FATAL 86 | }; 87 | 88 | //宏定义 89 | #ifdef OPEN_LOGGING 90 | #define LOG(level) log::Logging(__FILE__, __LINE__, level).stream() 91 | #define LOG_DEBUG log::Logging(__FILE__, __LINE__, DEBUG).stream() 92 | #define LOG_INFO log::Logging(__FILE__, __LINE__, INFO).stream() 93 | #define LOG_WARNING log::Logging(__FILE__, __LINE__, WARNING).stream() 94 | #define LOG_ERROR log::Logging(__FILE__, __LINE__, ERROR).stream() 95 | #define LOG_FATAL log::Logging(__FILE__, __LINE__, FATAL).stream() 96 | #else 97 | #define LOG(level) log::LogStream() 98 | #endif 99 | 100 | #endif // LOG_LOGGING_H_ 101 | -------------------------------------------------------------------------------- /WebServer/include/manager/file_manager.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "locker/mutex_lock.h" 13 | #include "log/logging.h" 14 | 15 | 16 | namespace manager 17 | { 18 | 19 | class FileManager { 20 | public: 21 | using fileManagerPtr = std::shared_ptr; 22 | 23 | public: 24 | FileManager(); 25 | ~FileManager(); 26 | 27 | static fileManagerPtr getFileManager(); 28 | static std::vector getFileList() { return fileList_; } 29 | static std::string getFileName(); 30 | 31 | 32 | private: 33 | static std::vector fileList_; 34 | static locker::MutexLock mutex_; 35 | static fileManagerPtr instance_; 36 | }; 37 | 38 | 39 | } // namespace manager 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /WebServer/include/manager/file_operator.h: -------------------------------------------------------------------------------- 1 | // @Author: Lawson 2 | // @CreateDate: 2022/05/13 3 | // @LastModifiedDate: 2022/05/13 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | // 缓冲区大小 23 | #define BUFFER_SIZE 4096 24 | 25 | // 用于指示服务器根目录 26 | #define SERVERROOTPATHSTRING "/" 27 | 28 | namespace manager 29 | { 30 | 31 | // bool strict 代表对其他目录的访问权 32 | // strict = true: 只能访问当前工作目录 33 | // strict = false: 可以访问其他目录 34 | class FileOperator { 35 | public: 36 | FileOperator(std::string dir); 37 | virtual ~FileOperator(); 38 | int readFile(std::string fileName); 39 | char* readFileBlock(unsigned long& sizeInBytes); 40 | int writeFileAtOnce(std::string fileName, char* content); 41 | int beginWriteFile(std::string fileName); 42 | int writeFileBlock(std::string content); 43 | int closeWriteFile(); 44 | bool changeDir(std::string newPath, bool strict = true); 45 | std::string getCurrentWorkingDir(bool showRootPath = true); 46 | bool createFile(std::string& fileName, bool strict = true); 47 | bool createAndCoverFile(std::string& fileName, bool strict = true); 48 | bool createDirectory(std::string& dirName, bool strict = true); 49 | bool deleteDirectory(std::string dirName, bool cancel = false, std::string pathToDir = ""); 50 | bool deleteFile(std::string fileName, bool strict = true); 51 | void browse(std::string dir, std::vector &directories, std::vector& files, bool strict = true); 52 | bool dirCanBeOpened(std::string dir); 53 | std::string getParentDir(); 54 | unsigned long getDirSize(std::string dirName); 55 | std::vector getStats(std::string fileName, struct stat Status); 56 | void clearListOfDeletedFiles(); 57 | void clearListOfDeletedDirectories(); 58 | std::vector getListOfDeletedFiles(); 59 | std::vector getListOfDeletedDirectories(); 60 | bool dirIsBelowServerRoot(std::string dirName); 61 | std::ofstream currentOpenFile_; 62 | std::ifstream currentOpenReadFile_; 63 | 64 | private: 65 | std::vector deletedDirectories_; 66 | std::vector deletedFiles_; 67 | void getValidDir(std::string& dirName); 68 | void getValidFile(std::string& fileName); 69 | void stripServerRootString(std::string& dirOrFileName); 70 | 71 | std::list completePath_; //从服务器根目录向上到当前工作目录的路径,每个列表元素包含一个目录 72 | static void IntToString(int i, std::string& res); 73 | }; 74 | 75 | 76 | 77 | } // namespace manager 78 | 79 | 80 | -------------------------------------------------------------------------------- /WebServer/include/manager/user_manager.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "locker/mutex_lock.h" 12 | #include "memory/memory_pool.h" 13 | 14 | 15 | namespace manager 16 | { 17 | 18 | class UserManager { 19 | public: 20 | using userManagerPtr = std::shared_ptr; 21 | 22 | public: 23 | UserManager(std::string userInfoFile); 24 | ~UserManager(); 25 | 26 | static userManagerPtr getUserManger(std::string userInfoFile); 27 | static bool login(std::string name, std::string psw); 28 | 29 | private: 30 | static std::unordered_map userInfo_; 31 | static userManagerPtr instance_; 32 | static locker::MutexLock mutex_; 33 | }; 34 | 35 | } // namespace manager 36 | 37 | -------------------------------------------------------------------------------- /WebServer/include/memory/memory_pool.h: -------------------------------------------------------------------------------- 1 | // @Author: Lawson 2 | // @CreateDate: 2022/04/21 3 | // @ModifiedDate: 2022/04/21 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "locker/mutex_lock.h" 16 | 17 | #define BlockSize 4096 18 | 19 | namespace memoryPool 20 | { 21 | 22 | struct Slot { 23 | Slot* next; 24 | }; 25 | 26 | // template 27 | class MemoryPool { 28 | public: 29 | MemoryPool(); 30 | ~MemoryPool(); 31 | 32 | void init(int size); 33 | 34 | // 分配或收回一个元素的内存空间 35 | Slot* allocate(); 36 | void deAllocate(Slot* p); 37 | private: 38 | int slotSize_; // 每个槽所占字节数 39 | 40 | Slot* currentBolck_; // 内存块链表的头指针 41 | Slot* currentSlot_; // 元素链表的头指针 42 | Slot* lastSlot_; // 可存放元素的最后指针 43 | Slot* freeSlot_; // 元素构造后释放掉的内存链表头指针 44 | 45 | locker::MutexLock mutex_freeSlot_; 46 | locker::MutexLock mutex_other_; 47 | 48 | size_t padPointer(char* p, size_t align); // 计算对齐所需空间 49 | Slot* allocateBlock(); // 申请内存块放进内存池 50 | Slot* nofree_solve(); 51 | }; 52 | 53 | void init_MemoryPool(); 54 | void* use_Memory(size_t size); 55 | void free_Memory(size_t size, void* p); 56 | 57 | // template 58 | MemoryPool& get_MemoryPool(int id); 59 | 60 | template 61 | T* newElement(Args&&... args) { 62 | T* p; 63 | if((p = reinterpret_cast(use_Memory(sizeof(T)))) != nullptr) 64 | // new(p) T1(value); 65 | // placement new:在指针p所指向的内存空间创建一个T1类型的对象,类似与 realloc 66 | // 把已有的空间当成一个缓冲区来使用,减少了分配空间所耗费的时间 67 | // 因为直接用new操作符分配内存的话,在堆中查找足够大的剩余空间速度是比较慢的 68 | new(p) T(std::forward(args)...); // 完美转发 69 | 70 | return p; 71 | } 72 | 73 | // 调用p的析构函数,然后将其总内存池中释放 74 | template 75 | void deleteElement(T* p) { 76 | // printf("deleteElement...\n"); 77 | if(p) 78 | p->~T(); 79 | free_Memory(sizeof(T), reinterpret_cast(p)); 80 | // printf("deleteElement success\n"); 81 | } 82 | 83 | } // namespace memoryPool 84 | 85 | 86 | -------------------------------------------------------------------------------- /WebServer/include/pagecache/lfu_cache.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "locker/mutex_lock.h" 7 | #include "memory/MemoryPool.h" 8 | 9 | #define LFU_CAPACITY 10 10 | 11 | namespace cache 12 | { 13 | 14 | using std::string; 15 | 16 | // 链表的节点 17 | template 18 | class Node { 19 | public: 20 | void setPre(Node* p) { pre_ = p; } 21 | void setNext(Node* p) { next_ = p; } 22 | Node* getPre() { return pre_; } 23 | Node* getNext() { return next_; } 24 | T& getValue() { return value_; } 25 | 26 | private: 27 | T value_; 28 | Node* pre_; 29 | Node* next_; 30 | }; 31 | 32 | // 文件名->文件内容的映射 33 | struct Key { 34 | string key_, value_; 35 | }; 36 | 37 | typedef Node* key_node; 38 | 39 | // 链表:由多个Node组成 40 | class KeyList { 41 | public: 42 | void init(int freq); 43 | void destory(); 44 | int getFreq(); 45 | void add(key_node& node); 46 | void del(key_node& node); 47 | bool isEmpty(); 48 | key_node getLast(); 49 | 50 | private: 51 | int freq_; 52 | key_node Dummyhead_; 53 | key_node tail_; 54 | }; 55 | 56 | typedef Node* freq_node; 57 | 58 | /* 59 | 典型的双重链表+hash表实现 60 | 首先是一个大链表,链表的每个节点都是一个小链表附带一个值表示频度 61 | 小链表存的是同一频度下的key value节点。 62 | hash表存key到大链表节点的映射(key,freq_node)和 63 | key到小链表节点的映射(key,key_node). 64 | */ 65 | 66 | // LFU由多个链表组成 67 | class LFUCache { 68 | public: 69 | static LFUCache& GetInstance(); 70 | void Initialize(int capacity = 10); 71 | 72 | bool Get(string& key, string& value); // 通过key返回value并进行LFU操作 73 | void Set(string& key, string& value); // 更新LFU缓存 74 | size_t GetCapacity() const { return capacity_; } 75 | 76 | private: 77 | LFUCache() {} 78 | ~LFUCache(); 79 | 80 | void AddFreq(key_node& nowk, freq_node& nowf); 81 | void Del(freq_node& node); 82 | void Init(); 83 | 84 | freq_node Dummyhead_; // 大链表的头节点,里面每个节点都是小链表的头节点 85 | size_t capacity_; 86 | locker::MutexLock mutex_; 87 | 88 | std::unordered_map kmap_; // key到keynode的映射 89 | std::unordered_map fmap_; // key到freqnode的映射 90 | 91 | 92 | }; 93 | 94 | } // namespace cache 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /WebServer/include/server/web_server.h: -------------------------------------------------------------------------------- 1 | #ifndef WEB_SERVER_H_ 2 | #define WEB_SERVER_H_ 3 | 4 | #include 5 | 6 | #include "event/channel.h" 7 | #include "event/event_loop.h" 8 | #include "event/event_loop_thread_pool.h" 9 | 10 | namespace server 11 | { 12 | 13 | class WebServer { 14 | public: 15 | static WebServer& GetInstance(); 16 | void Initialize(event::EventLoop* event_loop, int thread_num, int port); 17 | 18 | event::EventLoop* event_loop() { 19 | return event_loop_; 20 | } 21 | 22 | void Start(); 23 | 24 | private: 25 | WebServer() {} 26 | WebServer(event::EventLoop* event_loop, int thread_num, int port); 27 | ~WebServer() {} 28 | 29 | WebServer(const WebServer&) = delete; 30 | WebServer& operator=(const WebServer&) = delete; 31 | 32 | void HandleNewConnect(); 33 | void HandelCurConnect(); 34 | 35 | 36 | private: 37 | static const int MAX_FD_NUM = 100000; 38 | 39 | event::EventLoop* event_loop_; 40 | std::unique_ptr event_loop_thread_pool_; 41 | std::shared_ptr accept_channel_; 42 | 43 | int port_; 44 | int listen_fd_; 45 | int thread_num_; 46 | bool is_started_; 47 | }; 48 | 49 | } // namespace server 50 | 51 | 52 | 53 | 54 | #endif // WEB_SERVER_H_ -------------------------------------------------------------------------------- /WebServer/include/skiplist/Node.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | template 4 | class SkipList; 5 | 6 | template 7 | class Node { 8 | friend class SkipList; 9 | public: 10 | Node() {} 11 | Node(K k, V v, int level); 12 | ~Node(); 13 | 14 | K getKey() const; 15 | V getValue() const; 16 | void setValue(V v); 17 | 18 | // 不同层数的下一节点 19 | Node **_forward; 20 | int _nodeLevel; 21 | 22 | private: 23 | K _key; 24 | V _value; 25 | }; 26 | 27 | template 28 | Node ::Node(const K k, const V v, int level) { 29 | _key = k; 30 | _value = v; 31 | _nodeLevel = level; 32 | 33 | _forward = new Node *[_nodeLevel + 1] (); 34 | } 35 | 36 | template 37 | Node::~Node() { 38 | delete[] _forward; 39 | } 40 | 41 | template 42 | K Node::getKey() const { 43 | return _key; 44 | } 45 | 46 | template 47 | V Node::getValue() const { 48 | return _value; 49 | } 50 | 51 | template 52 | void Node::setValue(V v) { 53 | _value = v; 54 | } 55 | 56 | 57 | -------------------------------------------------------------------------------- /WebServer/include/skiplist/Random.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | class Random { 6 | Random(uint32_t s) : seed(s & 0x7fffffffu) { 7 | // Avoid bad seeds. 8 | if (seed == 0 || seed == 2147483647L) { 9 | seed = 1; 10 | } 11 | } 12 | 13 | uint32_t Next() { 14 | static const uint32_t M = 2147483647L; // 2^31-1 15 | static const uint64_t A = 16807; // bits 14, 8, 7, 5, 2, 1, 0 16 | // We are computing 17 | // seed_ = (seed_ * A) % M, where M = 2^31-1 18 | // 19 | // seed_ must not be zero or M, or else all subsequent computed values 20 | // will be zero or M respectively. For all other values, seed_ will end 21 | // up cycling through every number in [1,M-1] 22 | uint64_t product = seed * A; 23 | 24 | // Compute (product % M) using the fact that ((x << 31) % M) == x. 25 | seed = static_cast((product >> 31) + (product & M)); 26 | // The first reduction may overflow by 1 bit, so we may need to 27 | // repeat. mod == M is not possible; using > allows the faster 28 | // sign-bit-based test. 29 | if (seed > M) { 30 | seed -= M; 31 | } 32 | return seed; 33 | } 34 | 35 | // Returns a uniformly distributed value in the range [0..n-1] 36 | // REQUIRES: n > 0 37 | uint32_t Uniform(int n) { return (Next() % n); } 38 | 39 | // Randomly returns true ~"1/n" of the time, and false otherwise. 40 | // REQUIRES: n > 0 41 | bool OneIn(int n) { return (Next() % n) == 0; } 42 | 43 | // Skewed: pick "base" uniformly from range [0,max_log] and then 44 | // return "base" random bits. The effect is to pick a number in the 45 | // range [0,2^max_log-1] with exponential bias towards smaller numbers. 46 | uint32_t Skewed(int max_log) { 47 | return Uniform(1 << Uniform(max_log + 1)); 48 | } 49 | 50 | 51 | private: 52 | uint32_t seed; 53 | }; -------------------------------------------------------------------------------- /WebServer/include/thread/block_queue.hpp: -------------------------------------------------------------------------------- 1 | #ifndef THREAD_BLOCK_QUEUE_H_ 2 | #define THREAD_BLOCK_QUEUE_H_ 3 | 4 | #include 5 | #include 6 | 7 | #include "locker/mutex_lock.h" 8 | #include "event/channel.h" 9 | 10 | namespace thread { 11 | // 阻塞队列模板类 12 | template 13 | class BlockQueue { 14 | public: 15 | BlockQueue(); 16 | ~BlockQueue(); 17 | 18 | void Push(T* task); 19 | void Push(const std::vector& tasks); 20 | void Push(std::vector&& tasks); 21 | std::vector Pop(); 22 | bool Empty(); 23 | int Size(); 24 | // T* Front(); 25 | 26 | //静态成员函数 线程安全的懒汉式单例模式 27 | static BlockQueue* GetInstance() { 28 | static BlockQueue block_queue; 29 | return &block_queue; 30 | } 31 | 32 | private: 33 | std::queue> task_queue_; 34 | mutable locker::MutexLock mutex_; //请求队列的互斥锁 35 | locker::ConditionVariable condition_; //请求队列的条件变量 36 | }; 37 | 38 | template 39 | BlockQueue::BlockQueue() 40 | : mutex_(), 41 | condition_(mutex_) { 42 | } 43 | 44 | template 45 | BlockQueue::~BlockQueue() { 46 | } 47 | 48 | template 49 | void BlockQueue::Push(T* task) { 50 | locker::LockGuard lock(mutex_); 51 | // 添加任务 52 | if (task) { 53 | task_queue_.push(task); 54 | // 唤醒 55 | condition_.notify(); 56 | } 57 | } 58 | 59 | template 60 | void BlockQueue::Push(const std::vector& tasks) { 61 | locker::LockGuard lock(mutex_); 62 | // for (auto task : tasks) { 63 | // // 添加任务 64 | // task_queue_.push(task); 65 | // } 66 | task_queue_.push(tasks); 67 | // 唤醒 68 | condition_.notify(); 69 | } 70 | 71 | template 72 | void BlockQueue::Push(std::vector&& tasks) { 73 | locker::LockGuard lock(mutex_); 74 | // for (auto task : tasks) { 75 | // // 添加任务 76 | // task_queue_.push(task); 77 | // } 78 | task_queue_.push(tasks); 79 | // 唤醒 80 | condition_.notify(); 81 | } 82 | 83 | template 84 | std::vector BlockQueue::Pop() { 85 | locker::LockGuard lock(mutex_); 86 | //如果队列为空,条件变量等待 87 | while (task_queue_.empty()) { 88 | condition_.wait(); 89 | } 90 | // 从请求队列中取出一个任务 91 | auto task = task_queue_.front(); 92 | task_queue_.pop(); 93 | return task; 94 | } 95 | 96 | template 97 | bool BlockQueue::Empty() { 98 | locker::LockGuard lock(mutex_); 99 | return task_queue_.empty(); 100 | } 101 | 102 | template 103 | int BlockQueue::Size() { 104 | locker::LockGuard lock(mutex_); 105 | return task_queue_.size(); 106 | } 107 | 108 | // template 109 | // T* BlockQueue::Front() { 110 | // locker::LockGuard lock(mutex_); 111 | // if (task_queue_.empty()) { 112 | // return NULL; 113 | // } else { 114 | // return task_queue_.front(); 115 | // } 116 | // } 117 | 118 | } // namespace thread 119 | 120 | typedef thread::BlockQueue SingletonBlockQueue; 121 | 122 | #endif // BLOCK_QUEUE_H_ -------------------------------------------------------------------------------- /WebServer/include/thread/thread.h: -------------------------------------------------------------------------------- 1 | #ifndef THREAD_THREAD_H_ 2 | #define THREAD_THREAD_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | #include "locker/mutex_lock.h" 15 | #include "utility/count_down_latch.h" 16 | #include "utility/noncopyable.h" 17 | 18 | namespace current_thread { 19 | // __thread: TLS线程局部存储 每个当前线程都有一个该变量的实例 20 | extern __thread int tls_thread_id; //线程id 21 | extern __thread const char* tls_thread_name; //线程名字 22 | 23 | //得到线程id syscall 24 | inline int thread_id() { 25 | if (__builtin_expect(tls_thread_id == 0, 0)) { 26 | tls_thread_id = static_cast(::syscall(SYS_gettid)); 27 | } 28 | 29 | return tls_thread_id; 30 | } 31 | 32 | inline const char* thread_name() { 33 | return tls_thread_name; 34 | } 35 | 36 | } // namespace thread_local_storage 37 | 38 | namespace thread { 39 | class Thread : utility::NonCopyAble { 40 | public: 41 | typedef std::function Worker; 42 | 43 | explicit Thread(const Worker&, const std::string& thread_name = ""); 44 | ~Thread(); 45 | 46 | //开始线程 47 | void Start(); 48 | //join线程 49 | int Join(); 50 | 51 | bool is_started() const { 52 | return is_started_; 53 | } 54 | 55 | pid_t thread_id() const { 56 | return thread_id_; 57 | } 58 | 59 | const std::string& thread_name() const { 60 | return thread_name_; 61 | } 62 | 63 | private: 64 | static void* Run(void* arg); 65 | void Run(); 66 | 67 | private: 68 | Worker worker_; //线程函数 69 | pthread_t pthread_id_; //创建线程的id 70 | pid_t thread_id_; //线程id 71 | std::string thread_name_; //线程名字 72 | 73 | bool is_started_; //线程是否已经开始 74 | bool is_joined_; //线程是否已经join 75 | }; 76 | 77 | } // namespace thread 78 | 79 | #endif // THREAD_THREAD_H_ 80 | -------------------------------------------------------------------------------- /WebServer/include/thread/thread_pool.h: -------------------------------------------------------------------------------- 1 | #ifndef THREAD_THREAD_POOL_H_ 2 | #define THREAD_THREAD_POOL_H_ 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include "utility/noncopyable.h" 11 | 12 | namespace thread { 13 | //线程池状态 14 | enum ThreadPoolState { 15 | THREAD_POOL_INVALID, 16 | THREAD_POOL_LOCK_FAILURE, 17 | THREAD_POOL_QUEUE_FULL, 18 | THREAD_POOL_SHUTDOWN, 19 | THREAD_POOL_THREAD_FAILURE, 20 | THREAD_POOL_GRACEFUL 21 | }; 22 | 23 | typedef enum { 24 | immediate_shutdown, 25 | graceful_shutdown 26 | } ShutDownOption; 27 | 28 | const int kMaxThreadNum = 1024; 29 | const int kMaxQueueSize = 65535; 30 | 31 | struct Task { 32 | std::function)> callback; 33 | std::shared_ptr args; 34 | }; 35 | 36 | //线程池(用于计算线程) 37 | class ThreadPool : utility::NonCopyAble { 38 | public: 39 | ThreadPool(int thread_num, int queue_size); 40 | ~ThreadPool(); 41 | 42 | int Start(); 43 | int Add(std::shared_ptr args, 44 | std::function)> task); 45 | int Destroy(ShutDownOption shutdown_option = graceful_shutdown); 46 | int Free(); 47 | 48 | private: 49 | static void* Worker(void* args); 50 | void Run(); 51 | 52 | private: 53 | int thread_num_; 54 | int queue_size_; 55 | int head_; 56 | int tail_; 57 | int count_; 58 | int started_thread_count_; 59 | int shutdown_; 60 | 61 | std::vector threads_; 62 | std::vector task_queue_; 63 | pthread_mutex_t mutex_; 64 | pthread_cond_t condition_; 65 | }; 66 | 67 | } // namespace thread 68 | 69 | #endif // THREAD_THREAD_POOL_H_ -------------------------------------------------------------------------------- /WebServer/include/thread/worker_thread_pool.h: -------------------------------------------------------------------------------- 1 | #ifndef THREAD_WORKER_THREAD_POOL_H_ 2 | #define THREAD_WORKER_THREAD_POOL_H_ 3 | 4 | #include 5 | 6 | #include 7 | 8 | namespace thread { 9 | class WorkerThreadPool { 10 | public: 11 | /*thread_num是线程池中线程的数量,max_request是请求队列中最多允许的、等待处理的请求的数量*/ 12 | WorkerThreadPool(int thread_num); 13 | ~WorkerThreadPool(); 14 | 15 | void set_poller(event::Poller* poller) { 16 | poller_ = poller; 17 | } 18 | 19 | private: 20 | /*工作线程运行的函数,它不断从工作队列中取出任务并执行之*/ 21 | static void* Worker(void* arg); 22 | void Run(); 23 | 24 | private: 25 | int thread_num_; //线程池中的线程数 26 | pthread_t* pthreads_id_; //工作线程池,其大小为thread_num 27 | event::Poller* poller_; 28 | }; 29 | 30 | } // namespace thread 31 | 32 | #endif // THREAD_WORKER_THREAD_POOL_H_ 33 | -------------------------------------------------------------------------------- /WebServer/include/timer/timer.h: -------------------------------------------------------------------------------- 1 | #ifndef TIMER_TIMER_H_ 2 | #define TIMER_TIMER_H_ 3 | 4 | #include 5 | 6 | #include 7 | 8 | //类的前置声明 9 | namespace http { 10 | class HttpConnection; 11 | } // namespace http 12 | 13 | namespace timer { 14 | //定时器类 15 | class Timer { 16 | public: 17 | Timer(std::shared_ptr http, int timeout); 18 | //拷贝构造 19 | Timer(Timer& timer); 20 | ~Timer(); 21 | 22 | //更新到期时间 = 当前时间 + 超时时间 23 | void Update(int timeout); 24 | //是否到期 25 | bool is_expired(); 26 | //释放http 27 | void Release(); 28 | 29 | //得到到期时间 30 | int expire_time() const { 31 | return expire_time_; 32 | } 33 | 34 | //http是否已经删除 35 | bool is_deleted() const { 36 | return is_deleted_; 37 | } 38 | 39 | private: 40 | std::shared_ptr http_connection_; 41 | int expire_time_; 42 | bool is_deleted_; 43 | }; 44 | 45 | } // namespace timer 46 | 47 | #endif // namespace TIMER_TIMER_H_ -------------------------------------------------------------------------------- /WebServer/include/timer/timer_heap.h: -------------------------------------------------------------------------------- 1 | #ifndef TIMER_TIMER_HEAP_H_ 2 | #define TIMER_TIMER_HEAP_H_ 3 | 4 | #include "timer.h" 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include "utility/noncopyable.h" 11 | 12 | //类的前置声明 13 | namespace http { 14 | class HttpConnection; 15 | } // namespace http 16 | 17 | namespace timer { 18 | //定时器比较仿函数 升序 19 | struct TimerCompare { 20 | bool operator()(const std::shared_ptr& a, 21 | const std::shared_ptr& b) const { 22 | return a->expire_time() > b->expire_time(); 23 | } 24 | }; 25 | 26 | //定时器小根堆 27 | class TimerHeap : utility::NonCopyAble { 28 | public: 29 | TimerHeap() { 30 | } 31 | ~TimerHeap() { 32 | } 33 | 34 | //添加定时器 将其添加到小根堆中 35 | void AddTimer(std::shared_ptr http_connection, int timeout); 36 | //处理到期事件 如果定时器被删除或者已经到期 就从小根堆中删除 37 | void HandleExpireEvent(); 38 | 39 | private: 40 | //优先级队列 小顶堆 41 | std::priority_queue, 42 | std::deque>, 43 | TimerCompare> timer_heap_; 44 | }; 45 | 46 | } // namespace timer 47 | 48 | #endif // namespace TIMER_TIMER_H_ -------------------------------------------------------------------------------- /WebServer/include/utility/count_down_latch.h: -------------------------------------------------------------------------------- 1 | #ifndef UTILITY_COUNT_DOWN_LATCH_H_ 2 | #define UTILITY_COUNT_DOWN_LATCH_H_ 3 | 4 | #include "noncopyable.h" 5 | #include "locker/mutex_lock.h" 6 | 7 | namespace utility { 8 | // CountDownLatch的主要作用是确保Thread中传进去的func真的启动了以后 外层的start才返回 9 | class CountDownLatch : NonCopyAble { 10 | public: 11 | explicit CountDownLatch(int count) 12 | : mutex_(), 13 | condition_(mutex_), 14 | count_(count) { 15 | } 16 | 17 | ~CountDownLatch() { 18 | } 19 | 20 | void wait() { 21 | locker::LockGuard lock(mutex_); 22 | while (count_ > 0) { 23 | condition_.wait(); 24 | } 25 | } 26 | 27 | void count_down() { 28 | locker::LockGuard lock(mutex_); 29 | --count_; 30 | if (count_ == 0) { 31 | condition_.notify_all(); 32 | } 33 | } 34 | 35 | private: 36 | mutable locker::MutexLock mutex_; 37 | locker::ConditionVariable condition_; 38 | int count_; 39 | }; 40 | 41 | } // namespace utility 42 | 43 | #endif // UTILITY_COUNT_DOWN_LATCH_H_ -------------------------------------------------------------------------------- /WebServer/include/utility/noncopyable.h: -------------------------------------------------------------------------------- 1 | #ifndef UTILITY_NONCOPYABLE_H_ 2 | #define UTILITY_NONCOPYABLE_H_ 3 | 4 | namespace utility { 5 | // 删除拷贝构造和拷贝赋值 子类继承此父类时 子类如果没有自己定义就会默认调用父类的 6 | class NonCopyAble { 7 | public: 8 | NonCopyAble(const NonCopyAble&) = delete; 9 | NonCopyAble& operator=(const NonCopyAble&) = delete; 10 | 11 | NonCopyAble(NonCopyAble&&) = default; 12 | NonCopyAble& operator=(NonCopyAble&&) = default; 13 | 14 | protected: 15 | NonCopyAble() = default; 16 | ~NonCopyAble() = default; 17 | }; 18 | 19 | } // namespace utility 20 | 21 | #endif // UTILITY_NONCOPYABLE_H_ 22 | -------------------------------------------------------------------------------- /WebServer/include/utility/socket_utils.h: -------------------------------------------------------------------------------- 1 | #ifndef UTILITY_SOCKET_UTILS_H_ 2 | #define UTILITY_SOCKET_UTILS_H_ 3 | 4 | #include 5 | #include 6 | 7 | namespace utility { 8 | 9 | // 设置NIO非阻塞套接字 read时不管是否读到数据 都直接返回,如果是阻塞式,就会等待直到读完数据或超时返回 10 | // 所以非阻塞需要一直去看现在是否有数据 有就读出来 没有就立即返回 11 | // 一般配合 IO多路复用 使用 12 | int SetSocketNonBlocking(int fd); 13 | 14 | // 禁用TCP Nagle算法 这样就不会存到写缓存积累一定量再发送 而是直接发送 15 | void SetSocketNoDelay(int fd); 16 | 17 | // 优雅关闭套接字 也就是套接字在close的时候是否等待缓冲区发送完成(内核默认close是直接返回的) 18 | void SetSocketNoLinger(int fd); 19 | 20 | // shutdown只关闭了连接 close则关闭了套接字 21 | // shutdown会等输出缓冲区中的数据传输完毕再发送FIN报文段 而close则直接关闭 将会丢失输出缓冲区的内容 22 | void ShutDownWR(int fd); 23 | 24 | // 注册处理管道信号的回调 对其信号屏蔽 25 | void HandlePipeSignal(); 26 | 27 | // 服务器绑定地址并监听端口 28 | int SocketListen(int port); 29 | 30 | // 从fd中读n个字节到buffer 31 | int Read(int fd, void* read_buffer, int size); 32 | int Read(int fd, std::string& read_buffer, bool& is_read_zero_bytes); 33 | int Read(int fd, std::string& read_buffer); 34 | 35 | // 从buffer中写n个字节到fd 36 | int Write(int fd, void* write_buffer, int size); 37 | int Write(int fd, std::string& write_buffer); 38 | 39 | } // namespace utility 40 | 41 | #endif // UTILITY_SOCKET_UTILS_H_ 42 | -------------------------------------------------------------------------------- /WebServer/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "server/web_server.h" 4 | #include "event/event_loop.h" 5 | #include "log/logging.h" 6 | #include "memory/memory_pool.h" 7 | #include "cache/lfu_cache.h" 8 | 9 | namespace configure { 10 | //默认值 11 | static int port = 8888; 12 | static int thread_num = 8; 13 | static std::string log_file_name = "./web_server.log"; 14 | static bool open_log = true; 15 | static bool log_to_stderr = false; 16 | static bool color_log_to_stderr = false; 17 | static int min_log_level = INFO; 18 | static int capacity = 10; 19 | 20 | static void ParseArg(int argc, char* argv[]) { 21 | int opt; 22 | const char* str = "p:t:f:o:s:c:l:d"; 23 | while ((opt = getopt(argc, argv, str)) != -1) { 24 | switch (opt) { 25 | case 'p': { 26 | port = atoi(optarg); 27 | break; 28 | } 29 | case 't': { 30 | thread_num = atoi(optarg); 31 | break; 32 | } 33 | case 'f': { 34 | log_file_name = optarg; 35 | break; 36 | } 37 | case 'o': { 38 | open_log = atoi(optarg); 39 | break; 40 | } 41 | case 's': { 42 | log_to_stderr = atoi(optarg); 43 | break; 44 | } 45 | case 'c': { 46 | color_log_to_stderr = atoi(optarg); 47 | break; 48 | } 49 | case 'l': { 50 | min_log_level = atoi(optarg); 51 | break; 52 | } 53 | case 'd': { 54 | capacity = atoi(optarg); 55 | break; 56 | } 57 | default: { 58 | break; 59 | } 60 | } 61 | } 62 | } 63 | 64 | } // namespace configure 65 | 66 | int main(int argc, char* argv[]) { 67 | //解析参数 68 | configure::ParseArg(argc, argv); 69 | 70 | // 设置日志文件 71 | log::Logging::set_log_file_name(configure::log_file_name); 72 | // 开启日志 73 | log::Logging::set_open_log(configure::open_log); 74 | // 设置日志输出标准错误流 75 | log::Logging::set_log_to_stderr(configure::log_to_stderr); 76 | // 设置日志输出颜色 77 | log::Logging::set_color_log_to_stderr(configure::color_log_to_stderr); 78 | // 设置最小日志等级 79 | log::Logging::set_min_log_level(configure::min_log_level); 80 | 81 | // 初始化内存池 82 | memoryPool::init_MemoryPool(); 83 | 84 | // 初始化缓存 85 | cache::LFUCache::GetInstance().Initialize(configure::capacity); 86 | 87 | // 主loop 初始化poller, 把eventfd注册到epoll中并注册其事件处理回调 88 | event::EventLoop main_loop; 89 | 90 | // 创建监听套接字绑定服务器,监听端口,设置监听套接字为NIO,屏蔽管道信号 91 | server::WebServer::GetInstance().Initialize(&main_loop, configure::thread_num, configure::port); 92 | // server::WebServer myHttpServer(&main_loop, configure::thread_num, configure::port); 93 | 94 | // 主loop创建事件循环线程池(子loop),每个线程都run起来(调用SubLoop::Loop) 95 | // 给监听套接字设置监听事件,绑定事件处理回调,注册到主loop的epoll内核事件表中 96 | server::WebServer::GetInstance().Start(); 97 | // myHttpServer.Start(); 98 | 99 | // 主loop开始事件循环 epoll_wait阻塞 等待就绪事件(主loop只注册了监听套接字的fd,所以只会处理新连接事件) 100 | std::cout << "================================================Start Web Server================================================" << std::endl; 101 | main_loop.Loop(); 102 | std::cout << "================================================Stop Web Server=================================================" << std::endl; 103 | 104 | return 0; 105 | } 106 | -------------------------------------------------------------------------------- /WebServer/old_version/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | 3 | project(WebServer CXX) 4 | 5 | 6 | if(NOT CMAKE_BUILD_TYPE) 7 | set(CMAKE_BUILD_TYPE "Debug") 8 | endif() 9 | 10 | SET(CMAKE_BUILD_TYPE "Debug") 11 | SET(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g2 -ggdb") 12 | SET(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall") 13 | set(LIBRARY_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/lib/) 14 | set(EXECUTABLE_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/bin/) 15 | 16 | set(CXX_FLAGS 17 | -g 18 | -Wall 19 | -std=c++11 20 | -D_PTHREADS 21 | -Wno-unused-parameter 22 | ) 23 | 24 | set(0 "g++") 25 | set(CMAKE_CXX_FLAGS_DEBUG "-O0") 26 | set(CMAKE_CXX_FLAGS_RELEASE "-O0") 27 | 28 | # 将输入字符串内所有出现match_string的地方都用replace_string代替,然后将结果存储到输出变量中 29 | string(REPLACE ";" " " CMAKE_CXX_FLAGS "${CXX_FLAGS}") 30 | 31 | string(TOUPPER ${CMAKE_BUILD_TYPE} BUILD_TYPE) 32 | message(STATUS "CXX_FLAGS = " ${CMAKE_CXX_FLAGS} " " ${CMAKE_CXX_FLAGS_${BUILD_TYPE}}) 33 | 34 | add_subdirectory(src) -------------------------------------------------------------------------------- /WebServer/old_version/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # -x:执行指令后,会先显示该指令及所下的参数 4 | set -x 5 | 6 | SOURCE_DIR=`pwd` 7 | BUILD_DIR=${BUILD_DIR:-./build} 8 | BUILD_TYPE=${BUILD_TYPE:-Debug} 9 | 10 | mkdir ./lib 11 | mkdir ./bin 12 | 13 | mkdir -p $BUILD_DIR/$BUILD_TYPE \ 14 | && cd $BUILD_DIR/$BUILD_TYPE \ 15 | && cmake \ 16 | -DCMAKE_BUILD_TYPE=$BUILD_TYPE \ 17 | $SOURCE_DIR \ 18 | && make $* \ 19 | && cp -r $SOURCE_DIR/src/page $SOURCE_DIR/bin/page 20 | 21 | cd $SOURCE_DIR/bin 22 | -------------------------------------------------------------------------------- /WebServer/old_version/src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include_directories(${PROJECT_SOURCE_DIR}/src/base) 2 | include_directories(${PROJECT_SOURCE_DIR}/src/server) 3 | 4 | add_executable(WebServer Main.cc) 5 | 6 | target_link_libraries(WebServer 7 | server 8 | libserver_base 9 | ) 10 | 11 | 12 | # 该命令告诉CMake去子目录中查看可用的CMakeLists.txt文件 13 | add_subdirectory(base) 14 | add_subdirectory(LFUCache) 15 | add_subdirectory(client) 16 | add_subdirectory(connection) 17 | add_subdirectory(memory) 18 | add_subdirectory(package) 19 | add_subdirectory(reactor) 20 | add_subdirectory(server) 21 | add_subdirectory(threadPool) 22 | add_subdirectory(manager) 23 | add_subdirectory(FTPClient) 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /WebServer/old_version/src/FTPClient/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(FTPClient FTPClient.cc) 2 | 3 | target_link_libraries(FTPClient package) -------------------------------------------------------------------------------- /WebServer/old_version/src/FTPClient/FTPClient.cc: -------------------------------------------------------------------------------- 1 | // @Author: Lawson 2 | // @CreateDate: 2022/05/06 3 | // @LastModifiedDate: 2022/05/06 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include "../package/Util.h" 17 | 18 | using namespace std; 19 | 20 | #define MAXSIZE 1024 21 | #define IPADDRESS "127.0.0.1" 22 | #define SERV_PORT 4242 23 | #define FDSIZE 1024 24 | #define EPOLLEVENTS 20 25 | 26 | #define DEBUG_FTPCLIENT 27 | 28 | 29 | int main(int argc, char* argv[]) { 30 | std::cout << "it's FTPClient!" << std::endl; 31 | char buff[4096]; 32 | buff[0] = '\0'; 33 | 34 | int sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 35 | if(sockfd == -1) { 36 | cout << "create socket error!\n"; 37 | return 0; 38 | } 39 | 40 | // setSocketNonBlocking(sockfd); 41 | struct sockaddr_in serverAddr; 42 | bzero(&serverAddr, sizeof(sockaddr_in)); 43 | serverAddr.sin_family = AF_INET; 44 | serverAddr.sin_port = htons(SERV_PORT); 45 | inet_pton(AF_INET, IPADDRESS, &serverAddr.sin_addr); 46 | 47 | std::string user_name, user_password; 48 | std::string msg; 49 | 50 | #ifndef DEBUG_FTPCLIENT 51 | std::cout<<"please input your user name and password seperated by space.\n"; 52 | std::cin >> user_name >> user_password; 53 | #else 54 | user_name = "admin"; 55 | user_password = "123456"; 56 | #endif 57 | 58 | msg = "%" + user_name + "%" + user_password; 59 | 60 | if(connect(sockfd, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) == -1) { 61 | std::cout << "connect to server failed!" << std::endl; 62 | return 0; 63 | } 64 | setSocketNonBlocking(sockfd); 65 | 66 | #ifdef DEBUG_FTPCLIENT 67 | cout << "send userInfo now" << std::endl; 68 | #endif 69 | sleep(1); 70 | write(sockfd, msg.c_str(), msg.size()); 71 | 72 | #ifdef DEBUG_FTPCLIENT 73 | cout << "the msg send to server is: " << msg << std::endl; 74 | // cout << "the msg.c_str() send to server is: " << msg.c_str() << std::endl; 75 | #endif 76 | sleep(1); 77 | read(sockfd, buff, sizeof(buff)); 78 | msg = buff; 79 | 80 | #ifdef DEBUG_FTPCLIENT 81 | // cout << "the msg receive from server is: " << msg << std::endl; 82 | #endif 83 | 84 | if(msg.find("correct") == std::string::npos) { 85 | std::cout << "your user name or password is incorrect." << std::endl; 86 | return 0; 87 | } 88 | 89 | #ifdef DEBUG_FTPCLIENT 90 | 91 | std::string cmd; 92 | bool zero = false; 93 | readn(sockfd, msg, zero); 94 | std::cout << "msg1 is: " << msg << std::endl; 95 | while(true) { 96 | std::cout << "enter your cmd: " << std::endl; 97 | getline(std::cin, cmd); 98 | writen(sockfd, cmd); 99 | msg.clear(); 100 | ssize_t readSum = readn(sockfd, msg, zero); 101 | if(readSum < 0 || zero) { 102 | break; 103 | } 104 | std::cout << "msg2 is: " << msg << std::endl; 105 | 106 | } 107 | 108 | cout << "FTPClient close" << endl; 109 | #endif 110 | } -------------------------------------------------------------------------------- /WebServer/old_version/src/LFUCache/LFUCache.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../memory/MemoryPool.h" 4 | #include "../base/MutexLock.h" 5 | #include 6 | #include 7 | 8 | #define LFU_CAPACITY 10 9 | 10 | using std::string; 11 | 12 | // 链表的节点 13 | template 14 | class Node { 15 | public: 16 | void setPre(Node* p) { pre_ = p; } 17 | void setNext(Node* p) { next_ = p; } 18 | Node* getPre() { return pre_; } 19 | Node* getNext() { return next_; } 20 | T& getValue() { return value_; } 21 | 22 | private: 23 | T value_; 24 | Node* pre_; 25 | Node* next_; 26 | }; 27 | 28 | // 文件名->文件内容的映射 29 | struct Key { 30 | string key_, value_; 31 | }; 32 | 33 | typedef Node* key_node; 34 | 35 | // 链表:由多个Node组成 36 | class KeyList { 37 | public: 38 | void init(int freq); 39 | void destory(); 40 | int getFreq(); 41 | void add(key_node& node); 42 | void del(key_node& node); 43 | bool isEmpty(); 44 | key_node getLast(); 45 | 46 | private: 47 | int freq_; 48 | key_node Dummyhead_; 49 | key_node tail_; 50 | }; 51 | 52 | typedef Node* freq_node; 53 | 54 | /* 55 | 典型的双重链表+hash表实现 56 | 首先是一个大链表,链表的每个节点都是一个小链表附带一个值表示频度 57 | 小链表存的是同一频度下的key value节点。 58 | hash表存key到大链表节点的映射(key,freq_node)和 59 | key到小链表节点的映射(key,key_node). 60 | */ 61 | 62 | // LFU由多个链表组成 63 | class LFUCache { 64 | private: 65 | freq_node Dummyhead_; // 大链表的头节点,里面每个节点都是小链表的头节点 66 | size_t capacity_; 67 | MutexLock mutex_; 68 | 69 | std::unordered_map kmap_; // key到keynode的映射 70 | std::unordered_map fmap_; // key到freqnode的映射 71 | 72 | void addFreq(key_node& nowk, freq_node& nowf); 73 | void del(freq_node& node); 74 | void init(); 75 | 76 | public: 77 | LFUCache(int capicity); 78 | ~LFUCache(); 79 | 80 | bool get(string& key, string& value); // 通过key返回value并进行LFU操作 81 | void set(string& key, string& value); // 更新LFU缓存 82 | size_t getCapacity() const { return capacity_; } 83 | }; 84 | 85 | LFUCache& getCache(); 86 | 87 | 88 | 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /WebServer/old_version/src/LFUCache/tests/test_LFUCache.cc: -------------------------------------------------------------------------------- 1 | #include "../LFUCache.h" 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace std; 7 | 8 | 9 | void test1() { 10 | init_MemoryPool(); 11 | getCache(); 12 | LFUCache& Cache = getCache(); 13 | cout << "the capacity of LFU is : " << Cache.getCapacity() << endl; 14 | 15 | default_random_engine e; 16 | e.seed(time(NULL)); 17 | uniform_int_distribution u(0, 25); 18 | 19 | vector> seed(26); 20 | for(int i = 0; i < 26; ++i) { 21 | seed[i] = make_pair('a' + i, 'A' + i); 22 | } 23 | 24 | for(int i = 0; i < 100; ++i) { 25 | string val; 26 | auto temp = seed[u(e)]; 27 | cout << "----------round " << i << "----------" << endl; 28 | cout << "i want key: " << temp.first << endl; 29 | if(!Cache.get(temp.first, val)) { 30 | cout << "cache miss "; 31 | Cache.set(temp.first, temp.second); 32 | cout << "insert val..." << endl; 33 | } 34 | else { 35 | cout << "cache hit and value is :" << val << endl; 36 | } 37 | } 38 | 39 | } 40 | 41 | int main() { 42 | test1(); 43 | } -------------------------------------------------------------------------------- /WebServer/old_version/src/Main.cc: -------------------------------------------------------------------------------- 1 | // @Author: Lawson 2 | // @CreateDate: 2022/04/08 3 | // @ModifiedDate: 2022/04/16 4 | 5 | #include 6 | #include 7 | #include 8 | #include "base/Logging.h" 9 | #include "server/HTTPServer.h" 10 | #include "server/FTPServer.h" 11 | 12 | // #define FTPSERVER_DEBUG 13 | 14 | 15 | 16 | int main(int argc, char* argv[]) { 17 | int threadNum = 2; 18 | int port = 8888; 19 | unsigned short commandOffset = 3; 20 | std::string rootDir = "./"; 21 | std::string logPath = "./WebServer.log"; 22 | 23 | // parse args 24 | int opt; 25 | const char* str = "t:l:p:o:r:"; 26 | while((opt = getopt(argc, argv, str)) != -1) { 27 | switch(opt) { 28 | case 't' : { // threadNum 29 | threadNum = atoi(optarg); 30 | break; 31 | } 32 | case 'l' : { // logPath 33 | logPath = optarg; 34 | if(logPath.size() < 2 || optarg[0] != '/') { 35 | printf("logPath should start with \"/\"\n"); 36 | abort(); 37 | } 38 | break; 39 | } 40 | case 'p' : { // port 41 | port = atoi(optarg); 42 | break; 43 | } 44 | case 'v' : { // version 45 | printf("WebServer version 3.0 (base on muduo)\n"); 46 | break; 47 | } 48 | case 'o' : { // commandOffset 49 | commandOffset = atoi(optarg); 50 | break; 51 | } 52 | case 'r' : { // rootDir 53 | rootDir = optarg; 54 | if(rootDir.size() < 2 || optarg[0] != '/') { 55 | printf("logPath should start with \"/\"\n"); 56 | return EXIT_SUCCESS; 57 | } 58 | break; 59 | } 60 | default: { // 参数不存在 61 | printf("Usage: %s [-t threadNum] [-l logFilePath] [-p port] [-v] \n", argv[0]); 62 | return 0; 63 | } 64 | } 65 | } 66 | 67 | // STL库在多线程上应用 68 | #ifndef _PTHREADS 69 | LOG << "_PTHREADS is not defined !"; 70 | #endif 71 | init_MemoryPool(); 72 | 73 | Logger::setLogFileName(logPath); 74 | 75 | 76 | #ifdef FTPSERVER_DEBUG 77 | // std::cout << "rootDir = " << rootDir << std::endl; 78 | FTPServer myFTPServer(threadNum, port, rootDir, commandOffset); 79 | myFTPServer.start(); 80 | #else 81 | HTTPServer myHTTPServer(threadNum, port); 82 | myHTTPServer.start(); 83 | #endif 84 | 85 | return 0; 86 | } 87 | 88 | -------------------------------------------------------------------------------- /WebServer/old_version/src/base/AsyncLogging.cc: -------------------------------------------------------------------------------- 1 | // @Author: Lawson 2 | // @Date: 2022/03/23 3 | 4 | #include "AsyncLogging.h" 5 | #include "LogFile.h" 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | AsyncLogging::AsyncLogging(std::string logFileName, int flushInterval) 12 | : flushInterval_(flushInterval), 13 | running_(false), 14 | basename_(logFileName), 15 | thread_(std::bind(&AsyncLogging::threadFunc, this), "Logging"), 16 | mutex_(), 17 | cond_(mutex_), 18 | currentBuffer_(new Buffer), 19 | nextBuffer_(new Buffer), 20 | buffers_(), 21 | latch_(1) { 22 | assert(logFileName.size() > 1); 23 | currentBuffer_->bzero(); 24 | nextBuffer_->bzero(); 25 | buffers_.reserve(16); 26 | } 27 | 28 | void AsyncLogging::append(const char* logline, int len) { 29 | //操作缓冲区需要加锁 30 | MutexLockGuard lock(mutex_); 31 | //剩余空间够则直接写入当前buffer 32 | if(currentBuffer_->avail() > len) 33 | currentBuffer_->append(logline, len); 34 | else { //否则换nextbuffer来写 35 | buffers_.push_back(currentBuffer_); 36 | currentBuffer_.reset(); 37 | if(nextBuffer_) 38 | currentBuffer_ = std::move(nextBuffer_); 39 | else //如果nextbuffer不可用,则新建一个buffer来写 40 | currentBuffer_.reset(new Buffer); 41 | currentBuffer_->append(logline, len); 42 | //通知buffers_中有数据了,可以往文件中写了 43 | cond_.notify(); 44 | } 45 | } 46 | 47 | void AsyncLogging::threadFunc() { 48 | assert(running_ == true); 49 | latch_.countDown(); 50 | LogFile output(basename_); //LogFile用于将日志写入文件 51 | BufferPtr newBuffer1(new Buffer); 52 | BufferPtr newBuffer2(new Buffer); 53 | newBuffer1->bzero(); 54 | newBuffer2->bzero(); 55 | BufferVector buffersToWrite; //该vector属于后端线程,用于和前端的buffers进行交换 56 | buffersToWrite.reserve(16); 57 | 58 | while(running_) { 59 | assert(newBuffer1 && newBuffer1->length() == 0); 60 | assert(newBuffer2 && newBuffer2->length() == 0); 61 | assert(buffersToWrite.empty()); 62 | 63 | //将前端buffers_中的数据交换到buffersToWrite中 64 | { 65 | MutexLockGuard lock(mutex_); 66 | //每隔3s,或者currentBuffer满了,就将currentBuffer放入buffers_中 67 | if(buffers_.empty()) 68 | cond_.waitForSeconds(flushInterval_); 69 | 70 | buffers_.push_back(std::move(currentBuffer_)); 71 | // buffers_.push_back(currentBuffer_); 72 | // currentBuffer_.reset(); 73 | currentBuffer_ = std::move(newBuffer1); 74 | 75 | buffersToWrite.swap(buffers_); 76 | if(!nextBuffer_) 77 | nextBuffer_ = std::move(newBuffer2); 78 | } 79 | 80 | 81 | assert(!buffersToWrite.empty()); 82 | 83 | //如果队列中buffer数目大于25,就删除多余数据 84 | //避免日志堆积:前端日志记录过快,后端来不及写入文件 85 | if(buffersToWrite.size() > 25) { 86 | //TODO:删除数据时加错误提示 87 | //只留原始的两个buffer,其余的删除 88 | buffersToWrite.erase(buffersToWrite.begin() + 2, buffersToWrite.end()); 89 | } 90 | 91 | for(const auto& buffer : buffersToWrite) { 92 | output.append(buffer->data(), buffer->length()); 93 | } 94 | 95 | //重新调整buffersToWrite的大小,仅保留两个原始buffer 96 | if(buffersToWrite.size() > 2) { 97 | buffersToWrite.resize(2); 98 | } 99 | 100 | if(!newBuffer1) { 101 | assert(!buffersToWrite.empty()); 102 | newBuffer1 = buffersToWrite.back(); 103 | buffersToWrite.pop_back(); 104 | newBuffer1->reset(); 105 | } 106 | 107 | if(!newBuffer2) { 108 | assert(!buffersToWrite.empty()); 109 | newBuffer2 = buffersToWrite.back(); 110 | buffersToWrite.pop_back(); 111 | newBuffer2->reset(); 112 | } 113 | 114 | buffersToWrite.clear(); 115 | output.flush(); 116 | } 117 | output.flush(); 118 | } 119 | 120 | 121 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /WebServer/old_version/src/base/AsyncLogging.h: -------------------------------------------------------------------------------- 1 | // Author: Lawson 2 | // Date: 2022/03/21 3 | 4 | #pragma once 5 | #include "CountDownLatch.h" 6 | #include "LogStream.h" 7 | #include "MutexLock.h" 8 | #include "Thread.h" 9 | #include "noncopyable.h" 10 | #include 11 | #include 12 | #include 13 | 14 | 15 | // AsyncLogging负责启动一个log线程,专门用来将log写入LogFile,应用了“双缓冲技术” 16 | class AsyncLogging : noncopyable { 17 | public: 18 | AsyncLogging(const std::string basename, int flushInterval = 2); 19 | ~AsyncLogging() { 20 | if(running_) stop(); 21 | } 22 | void append(const char* logline, int len); 23 | 24 | void start() { 25 | running_ = true; 26 | thread_.start(); 27 | latch_.wait(); 28 | } 29 | 30 | void stop() { 31 | running_ = false; 32 | cond_.notify(); 33 | thread_.join(); 34 | } 35 | 36 | private: 37 | void threadFunc(); // 后端日志线程函数,用于把缓冲区日志写入文件 38 | typedef FixedBuffer Buffer; 39 | typedef std::vector> BufferVector; 40 | typedef std::shared_ptr BufferPtr; 41 | 42 | const int flushInterval_; //超时时间,每隔一段时间写日志 43 | bool running_; //FIXME:std::atomic running_; 44 | const std::string basename_; //日志名字 45 | Thread thread_; //后端线程,用于将日志写入文件 46 | MutexLock mutex_; 47 | Condition cond_; 48 | BufferPtr currentBuffer_; 49 | BufferPtr nextBuffer_; 50 | BufferVector buffers_; 51 | CountDownLatch latch_; //倒计时,用于指示日志记录器何时开始工作 52 | }; 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /WebServer/old_version/src/base/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 将多个源文件复制给LIB_SRC变量 2 | set(LIB_SRC 3 | AsyncLogging.cc 4 | CountDownLatch.cc 5 | FileUtil.cc 6 | LogFile.cc 7 | Logging.cc 8 | LogStream.cc 9 | Thread.cc 10 | ) 11 | 12 | # 将LIB_SRC编译成名为libserver_base的静态库(动态库需要加SHARED关键字) 13 | add_library(libserver_base STATIC ${LIB_SRC}) 14 | 15 | # 将libserver_base与其他库链接(不加后缀) 16 | target_link_libraries(libserver_base pthread rt) 17 | 18 | # 设置libserver_base的输出名为"server_base" 19 | set_target_properties(libserver_base PROPERTIES OUTPUT_NAME "server_base") 20 | 21 | # 该命令告诉CMake去子目录中查看可用的CMakeLists.txt文件 22 | add_subdirectory(tests) 23 | -------------------------------------------------------------------------------- /WebServer/old_version/src/base/Condition.h: -------------------------------------------------------------------------------- 1 | // 实现对条件变量pthread_cond_t的封装,但是time暂时不知道作用是什么 2 | // @Author: Lawson 3 | // @Date: 2022/03/17 4 | 5 | #pragma once 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "MutexLock.h" 11 | #include "noncopyable.h" 12 | 13 | class Condition : noncopyable { 14 | public: 15 | explicit Condition(MutexLock &_mutex) : mutex(_mutex) { 16 | pthread_cond_init(&cond, NULL); 17 | } 18 | ~Condition() { pthread_cond_destroy(&cond); } 19 | 20 | // 使当前线程阻塞在cond上,pthread_cond_wait()分为以下三部 21 | // 1、线程放在等待队列上,解锁 22 | // 2、等待 pthread_cond_signal或者pthread_cond_broadcast信号之后去竞争锁 23 | // 3、若竞争到互斥锁则加锁 24 | void wait() { pthread_cond_wait(&cond, mutex.get()); } 25 | // 解除线程在条件变量上的阻塞 26 | void notify() { pthread_cond_signal(&cond); } 27 | // 解除所有线程在条件变量上的阻塞 28 | void notifyAll() { pthread_cond_broadcast(&cond); } 29 | // 阻塞直到指定时间 30 | bool waitForSeconds(int seconds) { 31 | struct timespec abstime; 32 | clock_gettime(CLOCK_REALTIME, &abstime); 33 | abstime.tv_sec += static_cast(seconds); 34 | // 超时返回的错误码是ETIMEDOUT 35 | return ETIMEDOUT == pthread_cond_timedwait(&cond, mutex.get(), &abstime); 36 | } 37 | 38 | private: 39 | MutexLock &mutex; 40 | pthread_cond_t cond; 41 | }; 42 | -------------------------------------------------------------------------------- /WebServer/old_version/src/base/CountDownLatch.cc: -------------------------------------------------------------------------------- 1 | // @Author: Lawson 2 | // @Date: 2022/03/17 3 | 4 | #include "CountDownLatch.h" 5 | 6 | CountDownLatch::CountDownLatch(int count) 7 | : mutex_(), condition_(mutex_), count_(count) { } 8 | 9 | void CountDownLatch::wait() { 10 | MutexLockGuard lock(mutex_); 11 | // Condition_在wait()的时候会将锁释放 12 | while(count_ > 0) condition_.wait(); 13 | } 14 | 15 | 16 | void CountDownLatch::countDown() { 17 | MutexLockGuard lock(mutex_); 18 | --count_; 19 | if(count_ == 0) condition_.notifyAll(); 20 | } 21 | 22 | int CountDownLatch::getCount() const { 23 | MutexLockGuard lock(mutex_); 24 | return count_; 25 | } 26 | -------------------------------------------------------------------------------- /WebServer/old_version/src/base/CountDownLatch.h: -------------------------------------------------------------------------------- 1 | // @Author: Lawson 2 | // @Date: 2022/03/17 3 | 4 | #pragma once 5 | #include "Condition.h" 6 | #include "MutexLock.h" 7 | #include "noncopyable.h" 8 | 9 | // CountDownLatch是一个同步辅助类,一个线程阻塞等待另一个线程完成之后再继续进行(可以理解为等待起跑的指令) 10 | // 此处仿照muduo::CountDownLatch而写 11 | 12 | 13 | class CountDownLatch : noncopyable { 14 | public: 15 | explicit CountDownLatch(int count); 16 | void wait(); 17 | void countDown(); 18 | int getCount() const; 19 | 20 | private: 21 | mutable MutexLock mutex_; 22 | Condition condition_; 23 | int count_; 24 | }; 25 | -------------------------------------------------------------------------------- /WebServer/old_version/src/base/CurrentThread.h: -------------------------------------------------------------------------------- 1 | // @Author: Lawson 2 | // @Date: 2022/03/18 3 | 4 | #pragma once 5 | #include 6 | 7 | 8 | // CurrentThread不是一个类,而是一个命名空间,目的是提供对于当前线程的管理操作。 9 | namespace CurrentThread { 10 | // internal 11 | // __thread修饰变量每一个线程有一个独立实体,各个线程的值互不干扰 12 | extern __thread int t_cachedTid; 13 | extern __thread char t_tidString[32]; 14 | extern __thread int t_tidStringLength; 15 | extern __thread const char* t_threadName; 16 | 17 | void cacheTid(); 18 | 19 | inline int tid() { 20 | // 告诉gcc该语句为假的概率很大 21 | if(__builtin_expect(t_cachedTid == 0, 0)) { 22 | cacheTid(); 23 | } 24 | return t_cachedTid; 25 | } 26 | 27 | // for logging 28 | inline const char* tidString() { 29 | return t_tidString; 30 | } 31 | 32 | // for logging 33 | inline int tidStringLength() { 34 | return t_tidStringLength; 35 | } 36 | 37 | inline const char* name() { 38 | return t_threadName; 39 | } 40 | } // namespace CurrentThread 41 | -------------------------------------------------------------------------------- /WebServer/old_version/src/base/FileUtil.cc: -------------------------------------------------------------------------------- 1 | // @Author: Lawson 2 | // @Date: 2022/03/19 3 | 4 | 5 | #include "FileUtil.h" 6 | #include 7 | #include 8 | #include //提供open,fcntl,fclose等文件控制 9 | #include 10 | #include //获取文件属性 11 | #include //POSIX系统调用的API 12 | 13 | AppendFile::AppendFile(std::string filename) 14 | : fp_(fopen(filename.c_str(), "ae")) { // e-O_CLOEXEC当调用exec成功后,文件会自动关闭 15 | // 设置文件流的缓冲区 16 | setbuffer(fp_, buffer_, sizeof buffer_); 17 | } 18 | 19 | AppendFile::~AppendFile() { fclose(fp_); } 20 | 21 | void AppendFile::append(const char* logline, const size_t len) { 22 | size_t n = this->write(logline, len); 23 | size_t remain = len - n; 24 | while(remain > 0) { 25 | size_t x = this->write(logline + n, remain); 26 | if(x == 0) { 27 | // 检查是否存在错误标识符 28 | int err = ferror(fp_); 29 | if(err) fprintf(stderr, "AppendFile::append() failed !\n"); 30 | break; 31 | } 32 | n += x; 33 | remain = len - n; 34 | } 35 | } 36 | 37 | // 强迫将buffer内的数据写入指定的文件 38 | void AppendFile::flush() { fflush(fp_); } 39 | 40 | size_t AppendFile::write(const char* logline, size_t len) { 41 | // fwrite的线程不安全版,写入速度明显比fwrite快 42 | return fwrite_unlocked(logline, 1, len, fp_); 43 | } 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /WebServer/old_version/src/base/FileUtil.h: -------------------------------------------------------------------------------- 1 | // @Author: Lawson 2 | // @Date: 2022/03/19 3 | 4 | #pragma once 5 | #include 6 | #include "noncopyable.h" 7 | 8 | 9 | // FileUtil是最底层的文件类,封装了log文件的打开和写入 10 | // 在类析构时关闭文件,底层使用了标准IO 11 | class AppendFile : noncopyable { 12 | public: 13 | explicit AppendFile(std::string filename); 14 | ~AppendFile(); 15 | // append会向文件写 16 | void append(const char* logline, const size_t len); 17 | void flush(); 18 | 19 | 20 | private: 21 | size_t write(const char* logline, size_t len); 22 | FILE *fp_; 23 | char buffer_[64 * 1024]; 24 | }; 25 | -------------------------------------------------------------------------------- /WebServer/old_version/src/base/LogFile.cc: -------------------------------------------------------------------------------- 1 | // @Author: Lawson 2 | // @Date: 2022/03/21 3 | 4 | #include "LogFile.h" 5 | #include "FileUtil.h" 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace std; 11 | 12 | LogFile::LogFile(const string& basename, int flushEveryN) 13 | : basename_(basename), 14 | flushEveryN_(flushEveryN), 15 | count_(0), 16 | mutex_(new MutexLock) { 17 | assert(basename.find('/') >= 0); 18 | // unique_ptr::reset(p) : 获取p所指向的堆内存的所有权 19 | file_.reset(new AppendFile(basename)); 20 | } 21 | 22 | LogFile::~LogFile() { } 23 | 24 | void LogFile::append(const char* logline, int len) { 25 | MutexLockGuard lock(*mutex_); 26 | append_unlocked(logline, len); 27 | } 28 | 29 | void LogFile::flush() { 30 | MutexLockGuard lock(*mutex_); 31 | file_->flush(); 32 | } 33 | 34 | void LogFile::append_unlocked(const char* logline, int len) { 35 | file_->append(logline, len); 36 | ++count_; 37 | // 每写入1024行,强制刷新一次buffer(将buffer写入文件) 38 | if(count_ >= flushEveryN_) { 39 | count_ = 0; 40 | file_->flush(); 41 | } 42 | } 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /WebServer/old_version/src/base/LogFile.h: -------------------------------------------------------------------------------- 1 | // @Author: Lawson 2 | // @Date: 2022/03/19 3 | 4 | #pragma once 5 | #include 6 | #include 7 | #include "FileUtil.h" 8 | #include "MutexLock.h" 9 | #include "noncopyable.h" 10 | 11 | // TODO: 提供自动归档功能 12 | // TODO: 增加日志滚动功能: 13 | // 1、每写满1G换下个文件 14 | // 2、每天零点新建一个日志文件,不论前一个文件是否写满 15 | class LogFile : noncopyable { 16 | public: 17 | // 每被append flushEveryN次,flush一下,会往文件写,当然是带缓冲区的 18 | // 默认分割行数1024 19 | LogFile(const std::string& basename, int flushEveryN = 1024); 20 | ~LogFile(); 21 | 22 | void append(const char* logline, int len); 23 | void flush(); 24 | bool rollFile(); 25 | 26 | private: 27 | void append_unlocked(const char* logline, int len); 28 | 29 | const std::string basename_; 30 | const int flushEveryN_; 31 | 32 | int count_; 33 | std::unique_ptr mutex_; 34 | std::unique_ptr file_; 35 | }; 36 | -------------------------------------------------------------------------------- /WebServer/old_version/src/base/LogStream.cc: -------------------------------------------------------------------------------- 1 | // @Author: Lawson 2 | // @Date: 2022/03/22 3 | 4 | #include "LogStream.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | const char digits[] = "9876543210123456789"; 13 | const char* zero = digits + 9; 14 | 15 | // 该函数将整数转换为字符串 16 | template 17 | size_t convert(char buf[], T value) { 18 | T i = value; 19 | char *p = buf; 20 | 21 | do{ 22 | // lsd-last digit 23 | int lsd = static_cast(i % 10); 24 | i /= 10; 25 | *p++ = zero[lsd]; //注:此处lsd是可以为负的 26 | } while(i != 0); 27 | 28 | if(value < 0) { 29 | *p++ = '-'; 30 | } 31 | *p = '\0'; 32 | std::reverse(buf, p); 33 | 34 | return p - buf; //返回buf的长度 35 | } 36 | 37 | 38 | template class FixedBuffer; 39 | template class FixedBuffer; 40 | 41 | 42 | template 43 | void LogStream::formatInteger(T v) { 44 | // buffer容不下kMaxNumericSize个字符会被直接丢弃 45 | if(buffer_.avail() >= kMaxNumericSize) { 46 | // 直接将buffer的当前可用位置赋进去 47 | // 然后再移动buffer的当前位置 48 | size_t len = convert(buffer_.current(), v); 49 | buffer_.add(len); 50 | } 51 | } 52 | 53 | 54 | // 能转换为int的都弄成int处理 55 | LogStream& LogStream::operator<< (short v) { 56 | *this << static_cast(v); 57 | return *this; 58 | } 59 | 60 | LogStream& LogStream::operator<< (unsigned short v) { 61 | *this << static_cast(v); 62 | return *this; 63 | } 64 | 65 | LogStream& LogStream::operator<< (int v) { 66 | formatInteger(v); 67 | return *this; 68 | } 69 | 70 | LogStream& LogStream::operator<< (unsigned int v) { 71 | formatInteger(v); 72 | return *this; 73 | } 74 | 75 | LogStream& LogStream::operator<< (long v) { 76 | formatInteger(v); 77 | return *this; 78 | } 79 | 80 | LogStream& LogStream::operator<< (unsigned long v) { 81 | formatInteger(v); 82 | return *this; 83 | } 84 | 85 | LogStream& LogStream::operator<< (long long v) { 86 | formatInteger(v); 87 | return *this; 88 | } 89 | 90 | LogStream& LogStream::operator<< (unsigned long long v) { 91 | formatInteger(v); 92 | return *this; 93 | } 94 | 95 | LogStream& LogStream::operator<< (double v) { 96 | if(buffer_.avail() >= kMaxNumericSize) { 97 | //"%.12g"-以小数/指数中的较短值输出,精度为12位 98 | int len = snprintf(buffer_.current(), kMaxNumericSize, "%.12g", v); 99 | buffer_.add(len); 100 | } 101 | return *this; 102 | } 103 | 104 | LogStream& LogStream::operator<< (long double v) { 105 | if(buffer_.avail() >= kMaxNumericSize) { 106 | int len = snprintf(buffer_.current(), kMaxNumericSize, "%.12Lg", v); 107 | buffer_.add(len); 108 | } 109 | return *this; 110 | } 111 | 112 | 113 | 114 | 115 | 116 | 117 | -------------------------------------------------------------------------------- /WebServer/old_version/src/base/LogStream.h: -------------------------------------------------------------------------------- 1 | // Author: Lawson 2 | // Date: 2022/03/21 3 | 4 | #pragma once 5 | #include 6 | #include //c中针对char*的函数 7 | #include //c++中的string类 8 | #include "noncopyable.h" 9 | 10 | class AsyncLogging; 11 | const int kSmallBuffer = 4000; 12 | const int kLargeBuffer = 4000 * 1000; 13 | 14 | template //非类型模板参数,相当于在编译器就给常量赋值 15 | class FixedBuffer : noncopyable { 16 | public: 17 | FixedBuffer() 18 | : cur_(data_) { 19 | //TODO: 加入setcookie的功能 20 | } 21 | 22 | ~FixedBuffer() {} 23 | 24 | void append(const char* buf, size_t len) { 25 | if(avail() > static_cast(len)) { //如果可用数据足够,就拷贝过去,并移动当前指针 26 | memcpy(cur_, buf, len); 27 | cur_ += len; 28 | } 29 | } 30 | 31 | const char* data() const { return data_; } //返回首地址 32 | int length() const { return static_cast(cur_ - data_); } //返回缓冲区已有数据长度 33 | 34 | char* current() { return cur_; } //返回当前数据末端地址 35 | int avail() const { return static_cast(end() - cur_); } //返回剩余可用地址 36 | void add(size_t len) { cur_ += len; } //cur前移 37 | 38 | void reset() { cur_ = data_; } //重置不清除数据,仅需让cur指回首地址 39 | void bzero() { memset(data_, 0, sizeof data_); } //数据清零 40 | private: 41 | const char* end() const { return data_ + sizeof data_; } //返回尾指针 42 | 43 | char data_[SIZE]; 44 | char* cur_; //指向已有数据的最右端,类似data_->cur_->end() 45 | }; 46 | 47 | class LogStream : noncopyable { 48 | typedef LogStream self; 49 | public: 50 | typedef FixedBuffer Buffer; 51 | 52 | self& operator<< (bool v) { 53 | buffer_.append(v ? "1" : "0", 1); 54 | return *this; 55 | } 56 | 57 | self& operator<< (short); 58 | self& operator<< (unsigned short); 59 | self& operator<< (int); 60 | self& operator<< (unsigned int); 61 | self& operator<< (long); 62 | self& operator<< (unsigned long); 63 | self& operator<< (long long); 64 | self& operator<< (unsigned long long); 65 | 66 | self& operator<< (const void*); 67 | 68 | self& operator<< (float v) { 69 | *this << static_cast(v); 70 | return *this; 71 | } 72 | self& operator<< (double); 73 | self& operator<< (long double); 74 | 75 | self& operator<< (char v) { 76 | buffer_.append(&v, 1); 77 | return *this; 78 | } 79 | 80 | self& operator<< (const char* str) { 81 | if(str) 82 | buffer_.append(str, strlen(str)); 83 | else 84 | buffer_.append("(null)", 6); 85 | return *this; 86 | } 87 | 88 | self& operator<< (const unsigned char* str) { 89 | // reinterpret_cast用在任意指针(或引用)类型之间的转换 90 | return operator<<(reinterpret_cast(str)); 91 | } 92 | 93 | self& operator<< (const std::string& v) { 94 | buffer_.append(v.c_str(), v.size()); 95 | return *this; 96 | } 97 | 98 | 99 | void append(const char* data, int len) { buffer_.append(data, len); } 100 | const Buffer& buffer() const { return buffer_; } 101 | void resetBuffer() { buffer_.reset(); } 102 | private: 103 | void staticCheck(); 104 | 105 | template 106 | void formatInteger(T); 107 | 108 | Buffer buffer_; 109 | 110 | static const int kMaxNumericSize = 32; 111 | }; 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | -------------------------------------------------------------------------------- /WebServer/old_version/src/base/Logging.cc: -------------------------------------------------------------------------------- 1 | // @Author: Lawson 2 | // @Date: 2022/03/23 3 | 4 | #include "./Logging.h" 5 | #include "./CurrentThread.h" 6 | #include "./Thread.h" 7 | #include "./AsyncLogging.h" 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | static pthread_once_t once_control_ = PTHREAD_ONCE_INIT; 14 | static AsyncLogging *AsynLogger_; 15 | 16 | std::string Logger::logFileName_ = "./WebServer.log"; 17 | 18 | void once_init() { 19 | AsynLogger_ = new AsyncLogging(Logger::getLogFileName()); 20 | AsynLogger_->start(); 21 | } 22 | 23 | void output(const char* msg, int len) { 24 | pthread_once(&once_control_, once_init); 25 | AsynLogger_->append(msg, len); 26 | } 27 | 28 | Logger::Impl::Impl(const char* fileName, int line) 29 | : stream_(), 30 | line_(line), 31 | basename_(fileName) { 32 | formatTime(); 33 | } 34 | 35 | void Logger::Impl::formatTime() { 36 | struct timeval tv; 37 | time_t time; 38 | char str_t[26] = {0}; 39 | gettimeofday(&tv, NULL); 40 | time = tv.tv_sec; 41 | struct tm* p_time = localtime(&time); 42 | strftime(str_t, 26, "%Y-%m-%d %H:%M:%S\n", p_time); 43 | stream_ << str_t; 44 | } 45 | 46 | Logger::Logger(const char* fileName, int line) 47 | : impl_(fileName, line) { } 48 | 49 | Logger::~Logger() { 50 | impl_.stream_ << " -- " << impl_.basename_ << ':' << impl_.line_ << '\n'; 51 | const LogStream::Buffer& buf(stream().buffer()); 52 | output(buf.data(), buf.length()); 53 | } 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /WebServer/old_version/src/base/Logging.h: -------------------------------------------------------------------------------- 1 | // @Author: Lawson 2 | // @Date: 2022/03/23 3 | 4 | #pragma once 5 | #include "LogStream.h" 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | class AsyncLogging; 12 | 13 | class Logger { 14 | public: 15 | Logger(const char* filename, int line); 16 | ~Logger(); 17 | LogStream& stream() { return impl_.stream_; } 18 | 19 | static void setLogFileName(std::string fileName) { logFileName_ = fileName; } 20 | static std::string getLogFileName() { return logFileName_; } 21 | private: 22 | //Logger的内部实现类Impl:负责把日志头信息写入logstream 23 | //包含:时间戳,LogStream数据流,源文件行号,源文件名字 24 | //TODO:加入日志级别 25 | class Impl { 26 | public: 27 | Impl(const char* fileName, int line); 28 | void formatTime(); 29 | 30 | LogStream stream_; 31 | int line_; 32 | std::string basename_; 33 | }; 34 | Impl impl_; 35 | static std::string logFileName_; 36 | }; 37 | 38 | 39 | // C/C++提供了三个宏来定位程序运行时的错误 40 | // __FUNCTION__:返回当前所在的函数名 41 | // __FILE__:返回当前的文件名 42 | // __LINE__:当前执行行所在行的行号 43 | #define LOG Logger(__FILE__, __LINE__).stream() 44 | 45 | -------------------------------------------------------------------------------- /WebServer/old_version/src/base/Log的设计.txt: -------------------------------------------------------------------------------- 1 | Log的设计仿照了muduo库的设计,但我写的没那么复杂 2 | https://github.com/chenshuo/muduo 3 | 4 | 与Log相关的类包括FileUtil、LogFile、AsyncLogging、LogStream、Logging。 5 | 其中前4个类每一个类都含有一个append函数,Log的设计也是主要围绕这个append函数展开的。 6 | 7 | FileUtil是最底层的文件类,封装了Log文件的打开、写入并在类析构的时候关闭文件,底层使用了标准IO,该append函数直接向文件写。 8 | LogFile进一步封装了FileUtil,并设置了一个循环次数,没过这么多次就flush一次。 9 | AsyncLogging是核心,它负责启动一个log线程,专门用来将log写入LogFile,应用了“双缓冲技术”,其实有4个以上的缓冲区,但思想是一样的。 10 | AsyncLogging负责(定时到或被填满时)将缓冲区中的数据写入LogFile中。 11 | LogStream主要用来格式化输出,重载了<<运算符,同时也有自己的一块缓冲区,这里缓冲区的存在是为了缓存一行,把多个<<的结果连成一块。 12 | Logging是对外接口,Logging类内涵一个LogStream对象,主要是为了每次打log的时候在log之前和之后加上固定的格式化的信息,比如打log的行、文件名等信息。 13 | -------------------------------------------------------------------------------- /WebServer/old_version/src/base/MutexLock.h: -------------------------------------------------------------------------------- 1 | // @Author: Lawson 2 | // @Date: 2022/03/20 3 | 4 | #pragma once 5 | #include 6 | #include 7 | #include "noncopyable.h" 8 | 9 | class MutexLock : noncopyable { 10 | public: 11 | MutexLock() { pthread_mutex_init(&mutex, NULL); } 12 | ~MutexLock() 13 | { 14 | pthread_mutex_lock(&mutex); 15 | pthread_mutex_destroy(&mutex); 16 | } 17 | void lock() { pthread_mutex_lock(&mutex); } 18 | void unlock() { pthread_mutex_unlock(&mutex); } 19 | pthread_mutex_t *get() { return &mutex; } 20 | 21 | private: 22 | pthread_mutex_t mutex; 23 | 24 | // 友元类不受访问权限影响 25 | private: 26 | friend class Condition; 27 | }; 28 | 29 | class MutexLockGuard : noncopyable { 30 | public: 31 | explicit MutexLockGuard(MutexLock &_mutex) : mutex(_mutex) { mutex.lock(); } 32 | ~MutexLockGuard() { mutex.unlock(); } 33 | 34 | private: 35 | MutexLock &mutex; 36 | }; -------------------------------------------------------------------------------- /WebServer/old_version/src/base/Thread.cc: -------------------------------------------------------------------------------- 1 | // @Author: Lawson 2 | // @Date: 2022/03/20 3 | 4 | #include "Thread.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include "CurrentThread.h" 15 | 16 | #include 17 | using namespace std; 18 | 19 | namespace CurrentThread 20 | { 21 | __thread int t_cachedTid = 0; 22 | __thread char t_tidString[32]; 23 | __thread int t_tidStringLength = 6; 24 | __thread const char *t_threadName = "default"; 25 | } // namespace CurrentThread 26 | 27 | pid_t gettid() { return static_cast(::syscall(SYS_gettid)); } 28 | 29 | void CurrentThread::cacheTid() 30 | { 31 | if (t_cachedTid == 0) 32 | { 33 | t_cachedTid = gettid(); 34 | t_tidStringLength = 35 | snprintf(t_tidString, sizeof t_tidString, "%5d ", t_cachedTid); 36 | } 37 | } 38 | 39 | // 为了在线程中保留name,tid这些数据 40 | struct ThreadData 41 | { 42 | typedef Thread::ThreadFunc ThreadFunc; 43 | ThreadFunc func_; 44 | string name_; 45 | pid_t *tid_; 46 | CountDownLatch *latch_; 47 | 48 | ThreadData(const ThreadFunc &func, const string &name, pid_t *tid, 49 | CountDownLatch *latch) 50 | : func_(func), name_(name), tid_(tid), latch_(latch) {} 51 | 52 | void runInThread() 53 | { 54 | *tid_ = CurrentThread::tid(); 55 | tid_ = NULL; 56 | latch_->countDown(); 57 | latch_ = NULL; 58 | 59 | CurrentThread::t_threadName = name_.empty() ? "Thread" : name_.c_str(); 60 | prctl(PR_SET_NAME, CurrentThread::t_threadName); 61 | 62 | func_(); 63 | CurrentThread::t_threadName = "finished"; 64 | } 65 | }; 66 | 67 | void *startThread(void *obj) 68 | { 69 | ThreadData *data = static_cast(obj); 70 | data->runInThread(); 71 | delete data; 72 | return NULL; 73 | } 74 | 75 | Thread::Thread(const ThreadFunc &func, const string &n) 76 | : started_(false), 77 | joined_(false), 78 | pthreadId_(0), 79 | tid_(0), 80 | func_(func), 81 | name_(n), 82 | latch_(1) 83 | { 84 | setDefaultName(); 85 | } 86 | 87 | Thread::~Thread() 88 | { 89 | if (started_ && !joined_) 90 | pthread_detach(pthreadId_); 91 | } 92 | 93 | void Thread::setDefaultName() 94 | { 95 | if (name_.empty()) 96 | { 97 | char buf[32]; 98 | snprintf(buf, sizeof buf, "Thread"); 99 | name_ = buf; 100 | } 101 | } 102 | 103 | void Thread::start() 104 | { 105 | assert(!started_); 106 | started_ = true; 107 | ThreadData *data = new ThreadData(func_, name_, &tid_, &latch_); 108 | if (pthread_create(&pthreadId_, NULL, &startThread, data)) 109 | { 110 | started_ = false; 111 | delete data; 112 | } 113 | else 114 | { 115 | latch_.wait(); 116 | assert(tid_ > 0); 117 | } 118 | } 119 | 120 | int Thread::join() 121 | { 122 | assert(started_); 123 | assert(!joined_); 124 | joined_ = true; 125 | return pthread_join(pthreadId_, NULL); 126 | } 127 | -------------------------------------------------------------------------------- /WebServer/old_version/src/base/Thread.h: -------------------------------------------------------------------------------- 1 | // @Author: Lawson 2 | // @Date: 2022/03/20 3 | 4 | #pragma once 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "CountDownLatch.h" 12 | #include "noncopyable.h" 13 | 14 | class Thread : noncopyable { 15 | public: 16 | typedef std::function ThreadFunc; 17 | explicit Thread(const ThreadFunc&, const std::string& name = std::string()); 18 | ~Thread(); 19 | void start(); 20 | int join(); 21 | bool started() const { return started_; } 22 | pid_t tid() const { return tid_; } 23 | const std::string& name() const { return name_; } 24 | 25 | private: 26 | void setDefaultName(); 27 | bool started_; 28 | bool joined_; 29 | pthread_t pthreadId_; 30 | pid_t tid_; 31 | ThreadFunc func_; 32 | std::string name_; 33 | CountDownLatch latch_; 34 | }; -------------------------------------------------------------------------------- /WebServer/old_version/src/base/noncopyable.h: -------------------------------------------------------------------------------- 1 | // @Author: Lawson 2 | // @Date: 2022/03/20 3 | 4 | #pragma once 5 | 6 | class noncopyable { 7 | protected: 8 | noncopyable() {} 9 | ~noncopyable() {} 10 | 11 | private: 12 | noncopyable(const noncopyable &); 13 | const noncopyable &operator=(const noncopyable &); 14 | }; -------------------------------------------------------------------------------- /WebServer/old_version/src/base/tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 使用指定的源文件生成目标可执行文件 2 | add_executable(LoggingTest LoggingTest.cc) 3 | 4 | # 将libserver_base库链接到该可执行文件 5 | target_link_libraries(LoggingTest libserver_base) 6 | -------------------------------------------------------------------------------- /WebServer/old_version/src/base/tests/LoggingTest.cc: -------------------------------------------------------------------------------- 1 | // @Author: Lawson 2 | // Date: 2022/03/24 3 | #include "../Logging.h" 4 | #include "../Thread.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | using namespace std; 12 | 13 | void threadFunc() { 14 | for(int i = 0; i < 100000; ++i) { 15 | LOG << i; 16 | } 17 | } 18 | 19 | void type_test() { 20 | // 13 lines 21 | cout << "-----------type test now-----------" << endl; 22 | LOG << 0; 23 | LOG << 1234567890123; 24 | LOG << 1.0f; 25 | LOG << 3.14159262; 26 | LOG << (short) 1; 27 | LOG << (long long) 1; 28 | LOG << (unsigned int) 1; 29 | LOG << (unsigned long) 1; 30 | LOG << (long double) 1.6555556; 31 | LOG << (unsigned long long) 1; 32 | 33 | LOG << 'a'; 34 | LOG << "Hello a const string"; 35 | LOG << string("This is a string"); 36 | } 37 | 38 | void stressing_single_thread() { 39 | // 100000 lines 40 | cout << "-----------stressing test single thread-----------" << endl; 41 | for(int i = 0; i < 100000; ++i) { 42 | LOG << i; 43 | } 44 | } 45 | 46 | void stressing_multi_thread(int threadNum = 4) { 47 | // threadNum * 100000 lines 48 | cout << "-----------stressing test multi thread----------" << endl; 49 | vector> vsp; 50 | 51 | for(int i = 0; i < threadNum; ++i) { 52 | shared_ptr temp(new Thread(threadFunc, "testFunc")); 53 | vsp.push_back(temp); 54 | } 55 | 56 | for(int i = 0; i < threadNum; ++i) { 57 | vsp[i]->start(); 58 | } 59 | 60 | sleep(3); 61 | } 62 | 63 | void other() { 64 | // 1 line 65 | cout << "-----------other test-----------" << endl; 66 | LOG << "Hello" << 'a' << 2 << 50.55555 << string("This is a string"); 67 | } 68 | 69 | int main() { 70 | // 500014 lines 71 | type_test(); 72 | sleep(3); 73 | 74 | stressing_single_thread(); 75 | sleep(3); 76 | 77 | other(); 78 | sleep(3); 79 | 80 | stressing_multi_thread(); 81 | sleep(3); 82 | return 0; 83 | } 84 | 85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /WebServer/old_version/src/client/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(HTTPClient HTTPClient.cc) -------------------------------------------------------------------------------- /WebServer/old_version/src/client/HTTPClient.cc: -------------------------------------------------------------------------------- 1 | // @Author: Lawson 2 | // @CreateDate: 2022/04/10 3 | // @LastModifiedDate: 2022/04/10 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | using namespace std; 18 | 19 | #define MAXSIZE 1024 20 | #define IPADDRESS "127.0.0.1" 21 | #define SERV_PORT 8888 22 | #define FDSIZE 1024 23 | #define EPOLLEVENTS 20 24 | 25 | int setSocketNonBlocking(int fd) { 26 | int flag = fcntl(fd, F_GETFL); 27 | if(flag == -1) { 28 | return -1; 29 | } 30 | 31 | flag |= O_NONBLOCK; 32 | if(fcntl(fd, F_SETFL, flag) == -1) { 33 | return -1; 34 | } 35 | 36 | return 0; 37 | } 38 | 39 | int main(int argc, char* argv[]) { 40 | // cout << "creating socket..." << endl; 41 | int sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 42 | if(sockfd == -1) { 43 | perror("create socket error!\n"); 44 | return 0; 45 | } 46 | struct sockaddr_in servaddr; 47 | bzero(&servaddr, sizeof(servaddr)); 48 | servaddr.sin_family = AF_INET; 49 | servaddr.sin_port = htons(SERV_PORT); 50 | inet_pton(AF_INET, IPADDRESS, &servaddr.sin_addr); 51 | char buff[4096]; 52 | buff[0] = '\0'; 53 | cout << "-------------------" << endl; 54 | const char* p; 55 | ssize_t n; 56 | // 发送空串 57 | p = " \r\n"; 58 | if(connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1) { 59 | perror("connect to server failed!"); 60 | return 0; 61 | } 62 | setSocketNonBlocking(sockfd); 63 | cout << "test1: " << endl; 64 | n = write(sockfd, p, strlen(p)); 65 | cout << "strlen(p) = " << strlen(p) << endl; 66 | sleep(1); 67 | n = read(sockfd, buff, sizeof(buff)); 68 | cout << "n = " << n << endl; 69 | cout << buff << endl; 70 | close(sockfd); 71 | sleep(1); 72 | 73 | // // 发"GET /page.jpg HTTP/1.1" 74 | // p = "GET /page.jpg HTTP/1.1\r\nHost: 192.168.52.135\r\n\r\n"; 75 | // sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 76 | // if(sockfd == -1) { 77 | // perror("create socket error"); 78 | // return 0; 79 | // } 80 | // if(connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1) { 81 | // perror("connect to server failed"); 82 | // return 0; 83 | // } 84 | // setSocketNonBlocking(sockfd); 85 | // cout << "test2: " << endl; 86 | // n = write(sockfd, p, strlen(p)); 87 | // cout << "strlen(p) = " << strlen(p) << endl; 88 | // sleep(1); 89 | // n = read(sockfd, buff, sizeof(buff)); 90 | // cout << "n = " << n << endl; 91 | // cout << buff << endl; 92 | // close(sockfd); 93 | // sleep(1); 94 | 95 | // 发 96 | // GET /index.html HTTP/1.1 97 | // Host: 192.168.52.135:8888 98 | // Content-Type: application/x-www-form-urlencoded 99 | // Connection: Keep-Alive 100 | for(int i = 0; i < 3; ++i) { 101 | p = "GET /index.html HTTP/1.1\r\nHost: 192.168.52.135\r\nContent-Type: application/x-www-form-urlencoded\r\nConnection: Keep-Alive\r\n\r\n"; 102 | sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 103 | if(sockfd == -1) { 104 | perror("create socket error"); 105 | return 0; 106 | } 107 | if(connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1) { 108 | perror("connect to server failed"); 109 | return 0; 110 | } 111 | setSocketNonBlocking(sockfd); 112 | cout << "test3: " << endl; 113 | n = write(sockfd, p, strlen(p)); 114 | cout << "strlen(p) = " << strlen(p) << endl; 115 | sleep(1); 116 | n = read(sockfd, buff, sizeof(buff)); 117 | cout << "n = " << n << endl; 118 | cout << buff << endl; 119 | close(sockfd); 120 | sleep(1); 121 | } 122 | 123 | 124 | return 0; 125 | } 126 | -------------------------------------------------------------------------------- /WebServer/old_version/src/connection/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | aux_source_directory(. DIR_CONNECTION_SRCS) 2 | 3 | add_library(connection ${DIR_CONNECTION_SRCS}) 4 | 5 | target_link_libraries(connection manager reactor LFUCache package libserver_base) 6 | 7 | -------------------------------------------------------------------------------- /WebServer/old_version/src/connection/connection.cc: -------------------------------------------------------------------------------- 1 | #include "connection.h" 2 | 3 | udpConnection::udpConnection(int port) : port_(port) { 4 | init(); 5 | addr_.sin_family = AF_INET; 6 | addr_.sin_addr.s_addr = htonl(INADDR_ANY); 7 | addr_.sin_port = htons(port_); 8 | } 9 | 10 | void udpConnection::init() { 11 | fd_ = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 12 | if(fd_ < 0) { 13 | LOG << "create UDP failed"; 14 | exit(0); 15 | } 16 | bzero(&addr_, sizeof(addr_)); 17 | } 18 | 19 | void udpConnection::checkMsg() { 20 | 21 | } 22 | 23 | std::vector udpPool::udpList_; 24 | MutexLock udpPool::mutex_; 25 | udpPool::udpPoolPtr udpPool::instance_ = nullptr; 26 | int udpPool::index_ = -1; 27 | 28 | udpPool::udpPoolPtr udpPool::getUdpPool() { 29 | { 30 | MutexLockGuard lock(mutex_); 31 | if(instance_ == nullptr) 32 | instance_ = udpPoolPtr(new udpPool()); 33 | } 34 | return instance_; 35 | } 36 | 37 | udpPool::udpPool() { 38 | int basePort = 10000; 39 | for(int i = 0; i < MAX_NUM; ++i) { 40 | udpList_.emplace_back(new udpConnection(basePort + i)); 41 | } 42 | } 43 | 44 | udpConnection::udpConnectionPtr udpPool::getNextUDP() { 45 | index_ = (index_ + 1) % MAX_NUM; 46 | return udpList_[index_]; 47 | } 48 | 49 | 50 | tcpConnection::tcpConnection(int port) : port_(port) { 51 | 52 | } 53 | 54 | -------------------------------------------------------------------------------- /WebServer/old_version/src/connection/connection.h: -------------------------------------------------------------------------------- 1 | // @Author: Lawson 2 | // @CreatedDate: 2022/05/11 3 | // @ModifiedDate: 2022/05/11 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include "../base/Logging.h" 25 | #include "../base/MutexLock.h" 26 | 27 | class udpConnection { 28 | public: 29 | using udpConnectionPtr = std::shared_ptr; 30 | udpConnection(int port); 31 | ~udpConnection() { close(fd_); } 32 | int getFd() { return fd_; } 33 | int getPort() {return port_; } 34 | void setAddr(sockaddr_in addr) { addr_ = std::move(addr); } 35 | 36 | void checkMsg(); 37 | 38 | private: 39 | int fd_; 40 | int port_; 41 | struct sockaddr_in addr_; 42 | void init(); 43 | }; 44 | 45 | class udpPool { 46 | public: 47 | using udpPoolPtr = std::shared_ptr; 48 | 49 | udpPool(); 50 | ~udpPool(); 51 | 52 | static udpPoolPtr getUdpPool(); 53 | static udpConnection::udpConnectionPtr getNextUDP(); 54 | 55 | private: 56 | static int index_; 57 | static std::vector udpList_; 58 | static MutexLock mutex_; 59 | static udpPoolPtr instance_; 60 | static const int MAX_NUM = 32; 61 | static void init(); 62 | }; 63 | 64 | class tcpConnection { 65 | public: 66 | using tcpConnectionPtr = std::shared_ptr; 67 | tcpConnection(int port); 68 | ~tcpConnection() { close(fd_); } 69 | int getFd() { return fd_; } 70 | int getPort() {return port_; } 71 | void setAddr(sockaddr_in addr) { addr_ = std::move(addr); } 72 | 73 | void checkMsg(); 74 | 75 | private: 76 | int fd_; 77 | int port_; 78 | struct sockaddr_in addr_; 79 | void init(); 80 | }; 81 | 82 | class tcpPool { 83 | public: 84 | using tcpPoolPtr = std::shared_ptr; 85 | 86 | tcpPool(); 87 | ~tcpPool(); 88 | 89 | static tcpPoolPtr getUdpPool(); 90 | static tcpConnection::tcpConnectionPtr getNextUDP(); 91 | 92 | private: 93 | static int index_; 94 | static std::vector tcpList_; 95 | static MutexLock mutex_; 96 | static tcpPoolPtr instance_; 97 | static const int MAX_NUM = 32; 98 | static void init(); 99 | }; 100 | 101 | -------------------------------------------------------------------------------- /WebServer/old_version/src/connection/ftpConnection.h: -------------------------------------------------------------------------------- 1 | // @Author: Lawson 2 | // @CreateDate: 2022/05/14 3 | // @LastModifiedDate: 2022/05/15 4 | 5 | #pragma once 6 | 7 | #include "../manager/fileOperator.h" 8 | #include "../reactor/Channel.h" 9 | #include "../manager/userManager.h" 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include // for transform command 18 | #include 19 | #include 20 | #include 21 | 22 | // 命令分隔符 23 | #define SEPARATOR " " 24 | 25 | enum ProcessState { 26 | //LOGIN_ERROR = 0, // 登录错误(密码或用户名错误) 27 | QUIT = 0, 28 | UPLOAD, 29 | LOGIN, 30 | PARSE, 31 | }; 32 | 33 | 34 | class ftpConnection { 35 | public: 36 | using CallBack = std::function; 37 | public: 38 | ftpConnection(sp_Channel ftpChannel, unsigned int connId, std::string defaultDir, unsigned short commandOffset = 1); 39 | virtual ~ftpConnection(); 40 | 41 | std::vector extractParameters(std::string command); 42 | void run(); 43 | int getFD(); 44 | size_t getConnectionId(); 45 | 46 | private: 47 | std::shared_ptr ftpChannel_; 48 | ProcessState processState_; 49 | userManager::userManagerPtr userManager_; 50 | std::string dir_; 51 | std::shared_ptr fo_; // For browsing, writing and reading 52 | 53 | 54 | CallBack callBackFunc[4]; 55 | 56 | size_t filePart_; 57 | std::vector directories_; 58 | std::vector files_; 59 | size_t connectionId_; 60 | std::string parameter_; 61 | 62 | void sendToClient(std::string response); 63 | bool commandEquals(std::string a, std::string b); 64 | std::string filterOutBlanks(std::string inString); 65 | static void getAllParametersAfter(std::vector parameterVector, unsigned int currentParameter, std::string& theRest); 66 | unsigned short commandOffset_; 67 | std::string inBuffer_; 68 | std::string outBuffer_; 69 | 70 | 71 | ProcessState login(); 72 | ProcessState quit(); 73 | ProcessState commandParser(); 74 | ProcessState upload(); 75 | ProcessState download(); 76 | 77 | void handleRead(); 78 | void handleWrite(); 79 | }; 80 | 81 | 82 | -------------------------------------------------------------------------------- /WebServer/old_version/src/connection/httpConnection.h: -------------------------------------------------------------------------------- 1 | // @Author: Lawson 2 | // @Date: 2022/03/28 3 | 4 | #pragma once 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "../reactor/Timer.h" 13 | #include "../base/noncopyable.h" 14 | #include "../LFUCache/LFUCache.h" 15 | 16 | class EventLoop; 17 | class TimerNode; 18 | class Channel; 19 | 20 | typedef std::shared_ptr sp_Channel; 21 | 22 | // 请求行中的方法 23 | enum HttpMethod { 24 | METHOD_POST = 1, 25 | METHOD_GET, 26 | METHOD_HEAD 27 | }; 28 | 29 | enum HttpVersion { 30 | HTTP_10 = 1, 31 | HTTP_11 32 | }; 33 | 34 | // HTTP请求解析状态 35 | /* 36 | enum ParseState { 37 | STATE_PARSE_URI = 1, // 处于解析URI的状态 38 | STATE_PARSE_HEADERS, // 处于解析请求头部的状态 39 | STATE_RECV_BODY, // 处于解析请求实体的状态 40 | STATE_ANALYSIS, // 处于处理请求的状态 41 | STATE_FINISH // 解析完毕 42 | }; 43 | */ 44 | enum ParseState { 45 | PARSE_ERROR = 0, // 解析错误 46 | PARSE_REQUSET, // 解析请求行 47 | PARSE_HEADER, // 解析头部 48 | PARSE_SUCCESS // 解析成功 49 | }; 50 | 51 | // 错误状态 52 | enum ErrorState{ 53 | NOT_FOUND = 404, 54 | BAD_REQUEST = 400 55 | }; 56 | 57 | // 连接状态 58 | enum ConnectionState { 59 | H_CONNECTED = 0, 60 | H_DISCONNECTING, 61 | H_DISCONNECTED 62 | }; 63 | 64 | // 建立后缀名与MIME的映射 65 | class MimeType : noncopyable { 66 | private: 67 | static void init(); 68 | static std::unordered_map mime_; 69 | // static std::unordered_map ErrorMsg_; 70 | static pthread_once_t once_control; 71 | // MimeType(); 72 | // MimeType(const MimeType& m); 73 | public: 74 | static std::string getMime(const std::string& suffix); 75 | // static std::string getErrorMsg(const int& ErrorNo); 76 | }; 77 | 78 | 79 | 80 | class httpConnection { 81 | typedef std::function CallBack; 82 | public: 83 | httpConnection(sp_Channel channel); 84 | ~httpConnection() {} 85 | void reset(); 86 | void release(); 87 | int getFd(); 88 | void resetTimer(); 89 | void setTimer(std::shared_ptr timer); 90 | // void seperateTimer(); 91 | std::shared_ptr getChannel() { return channel_; } 92 | // EventLoop* getLoop() { return loop_; } 93 | // void handleClose(); 94 | // void newEvent(); 95 | 96 | private: 97 | std::shared_ptr channel_; 98 | int nowReadPos_; 99 | ParseState parseState_; 100 | std::string inBuffer_; 101 | std::string outBuffer_; 102 | std::string basePath_; // 基本路径 103 | 104 | // 存放解析请求的结果 105 | HttpMethod method_; 106 | HttpVersion HTTPVersion_; 107 | bool keepAlive_; 108 | std::string fileName_; 109 | std::string fileType_; 110 | int fileSize_; 111 | ErrorState errorState_; 112 | std::map headers_; // 建立头部字段的映射 113 | 114 | CallBack handleParse_[4]; 115 | 116 | void handleRead(); 117 | void handleError(int err_num, std::string short_msg); 118 | void handleSuccess(); 119 | 120 | ParseState parseRequest(); 121 | ParseState parseHeader(); 122 | ParseState parseError(); 123 | ParseState parseSuccess(); 124 | 125 | bool findStrFromBuffer(std::string& msg, std::string str); 126 | }; 127 | 128 | typedef std::shared_ptr sp_HttpConnection; 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | -------------------------------------------------------------------------------- /WebServer/old_version/src/manager/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | aux_source_directory(. DIR_manager_SRCS) 2 | 3 | add_library(manager ${DIR_manager_SRCS}) 4 | 5 | target_link_libraries(manager memory libserver_base) -------------------------------------------------------------------------------- /WebServer/old_version/src/manager/fileManager.cc: -------------------------------------------------------------------------------- 1 | #include "fileManager.h" 2 | 3 | #define DEBUG_FILEMANAGER 4 | 5 | std::vector fileManager::fileList_; 6 | MutexLock fileManager::mutex_; 7 | fileManager::fileManagerPtr fileManager::instance_ = nullptr; 8 | 9 | fileManager::fileManager() { 10 | std::string filePath(getcwd(NULL, 0)); 11 | if(filePath.empty()) { 12 | LOG << "get filePath failed"; 13 | exit(0); 14 | } 15 | DIR* curDir = opendir(filePath.c_str()); 16 | if(curDir == nullptr) { 17 | LOG << "get filePath failed"; 18 | exit(0); 19 | } 20 | 21 | auto dirPtr = readdir(curDir); 22 | while(dirPtr != nullptr) { 23 | if(dirPtr->d_type == DT_REG) 24 | fileList_.emplace_back(dirPtr->d_name); 25 | dirPtr = readdir(curDir); 26 | } 27 | closedir(curDir); 28 | 29 | #ifdef DEBUG_FILEMANAGER 30 | std::cout << "fileList is: " << std::endl; 31 | for(const std::string& file : fileList_) { 32 | std::cout<< file << " "; 33 | } 34 | std::cout << std::endl; 35 | #endif 36 | } 37 | 38 | fileManager::~fileManager() {} 39 | 40 | 41 | 42 | fileManager::fileManagerPtr fileManager::getFileManager() { 43 | { 44 | MutexLockGuard lock(mutex_); 45 | if(instance_ == nullptr) 46 | instance_ = fileManagerPtr(new fileManager()); 47 | } 48 | return instance_; 49 | } 50 | 51 | -------------------------------------------------------------------------------- /WebServer/old_version/src/manager/fileManager.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "../base/MutexLock.h" 9 | #include "../base/Logging.h" 10 | 11 | #pragma once 12 | 13 | class fileManager { 14 | public: 15 | using fileManagerPtr = std::shared_ptr; 16 | 17 | fileManager(); 18 | ~fileManager(); 19 | 20 | static fileManagerPtr getFileManager(); 21 | static std::vector getFileList() { return fileList_; } 22 | static std::string getFileName(); 23 | 24 | 25 | private: 26 | static std::vector fileList_; 27 | static MutexLock mutex_; 28 | static fileManagerPtr instance_; 29 | }; 30 | -------------------------------------------------------------------------------- /WebServer/old_version/src/manager/fileOperator.h: -------------------------------------------------------------------------------- 1 | // @Author: Lawson 2 | // @CreateDate: 2022/05/13 3 | // @LastModifiedDate: 2022/05/13 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | // 缓冲区大小 22 | #define BUFFER_SIZE 4096 23 | 24 | // 用于指示服务器根目录 25 | #define SERVERROOTPATHSTRING "/" 26 | 27 | 28 | // bool strict 代表对其他目录的访问权 29 | // strict = true: 只能访问当前工作目录 30 | // strict = false: 可以访问其他目录 31 | class fileOperator { 32 | public: 33 | fileOperator(std::string dir); 34 | virtual ~fileOperator(); 35 | int readFile(std::string fileName); 36 | char* readFileBlock(unsigned long& sizeInBytes); 37 | int writeFileAtOnce(std::string fileName, char* content); 38 | int beginWriteFile(std::string fileName); 39 | int writeFileBlock(std::string content); 40 | int closeWriteFile(); 41 | bool changeDir(std::string newPath, bool strict = true); 42 | std::string getCurrentWorkingDir(bool showRootPath = true); 43 | bool createFile(std::string& fileName, bool strict = true); 44 | bool createAndCoverFile(std::string& fileName, bool strict = true); 45 | bool createDirectory(std::string& dirName, bool strict = true); 46 | bool deleteDirectory(std::string dirName, bool cancel = false, std::string pathToDir = ""); 47 | bool deleteFile(std::string fileName, bool strict = true); 48 | void browse(std::string dir, std::vector &directories, std::vector& files, bool strict = true); 49 | bool dirCanBeOpened(std::string dir); 50 | std::string getParentDir(); 51 | unsigned long getDirSize(std::string dirName); 52 | std::vector getStats(std::string fileName, struct stat Status); 53 | void clearListOfDeletedFiles(); 54 | void clearListOfDeletedDirectories(); 55 | std::vector getListOfDeletedFiles(); 56 | std::vector getListOfDeletedDirectories(); 57 | bool dirIsBelowServerRoot(std::string dirName); 58 | std::ofstream currentOpenFile_; 59 | std::ifstream currentOpenReadFile_; 60 | 61 | private: 62 | std::vector deletedDirectories_; 63 | std::vector deletedFiles_; 64 | void getValidDir(std::string& dirName); 65 | void getValidFile(std::string& fileName); 66 | void stripServerRootString(std::string& dirOrFileName); 67 | 68 | std::list completePath_; //从服务器根目录向上到当前工作目录的路径,每个列表元素包含一个目录 69 | static void IntToString(int i, std::string& res); 70 | }; 71 | 72 | -------------------------------------------------------------------------------- /WebServer/old_version/src/manager/tests/test_fileManager.cc: -------------------------------------------------------------------------------- 1 | #include "../fileManager.h" 2 | 3 | #include 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /WebServer/old_version/src/manager/userManager.cc: -------------------------------------------------------------------------------- 1 | #include "userManager.h" 2 | #include "../base/Logging.h" 3 | 4 | #define DEBUG 5 | 6 | 7 | std::unordered_map userManager::userInfo_; 8 | userManager::userManagerPtr userManager::instance_ = nullptr; 9 | MutexLock userManager::mutex_; 10 | 11 | userManager::userManager(std::string userInfoFile) { 12 | std::ifstream infile(userInfoFile); 13 | if(!infile.is_open()) { 14 | LOG << "open file userInfoFile failed"; 15 | exit(0); 16 | } 17 | char name[255]; 18 | char psw[255]; 19 | while(infile) { 20 | bzero(name, 255); 21 | bzero(psw, 255); 22 | infile.getline(name, 255); 23 | infile.getline(psw, 255); 24 | userInfo_[name] = psw; 25 | } 26 | #ifdef DEBUG 27 | LOG << "load userInfoFile successfully"; 28 | #endif 29 | } 30 | 31 | userManager::~userManager() {} 32 | 33 | userManager::userManagerPtr userManager::getUserManger(std::string userInfoFile) { 34 | { 35 | MutexLockGuard lock(mutex_); 36 | if(instance_ == nullptr) { 37 | // instance_ = userManagerPtr(newElement(userInfoFile), deleteElement); 38 | instance_ = userManagerPtr(new userManager(userInfoFile)); 39 | } 40 | } 41 | return instance_; 42 | } 43 | 44 | bool userManager::login(std::string name, std::string psw) { 45 | if(userInfo_.find(name) != userInfo_.end()) { 46 | return userInfo_[name] == psw; 47 | } 48 | 49 | return false; 50 | } 51 | 52 | -------------------------------------------------------------------------------- /WebServer/old_version/src/manager/userManager.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "../base/MutexLock.h" 8 | #include "../memory/MemoryPool.h" 9 | 10 | #pragma once 11 | 12 | class userManager { 13 | public: 14 | using userManagerPtr = std::shared_ptr; 15 | 16 | userManager(std::string userInfoFile); 17 | ~userManager(); 18 | 19 | static userManagerPtr getUserManger(std::string userInfoFile); 20 | static bool login(std::string name, std::string psw); 21 | 22 | private: 23 | static std::unordered_map userInfo_; 24 | static userManagerPtr instance_; 25 | static MutexLock mutex_; 26 | }; 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /WebServer/old_version/src/memory/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | aux_source_directory(. DIR_MEMORY_SRCS) 2 | 3 | add_library(memory ${DIR_MEMORY_SRCS}) 4 | 5 | target_link_libraries(memory libserver_base) 6 | 7 | add_subdirectory(tests) -------------------------------------------------------------------------------- /WebServer/old_version/src/memory/MemoryPool.cc: -------------------------------------------------------------------------------- 1 | #include "MemoryPool.h" 2 | #include 3 | 4 | // template 5 | MemoryPool::MemoryPool() {} 6 | 7 | // template 8 | MemoryPool::~MemoryPool() { 9 | Slot* cur = currentBolck_; 10 | while(cur) { 11 | Slot* next = cur->next; 12 | // free(reinterpret_cast(cur)); 13 | // 转化为 void 指针,是因为 void 类型不需要调用析构函数,只释放空间 14 | operator delete(reinterpret_cast(cur)); 15 | cur = next; 16 | } 17 | } 18 | 19 | // template 20 | void MemoryPool::init(int size) { 21 | assert(size > 0); 22 | slotSize_ = size; 23 | currentBolck_ = NULL; 24 | currentSlot_ = NULL; 25 | lastSlot_ = NULL; 26 | freeSlot_ = NULL; 27 | } 28 | 29 | // 计算对齐所需补的空间 30 | // template 31 | inline size_t MemoryPool::padPointer(char* p, size_t align) { 32 | size_t result = reinterpret_cast(p); 33 | return ((align - result) % align); 34 | } 35 | 36 | // template 37 | Slot* MemoryPool::allocateBlock() { 38 | char* newBlock = reinterpret_cast(operator new(BlockSize)); 39 | 40 | char* body = newBlock + sizeof(Slot*); 41 | // 计算为了对齐需要空出多少位置 42 | // size_t bodyPadding = padPointer(body, sizeof(slotSize_)); 43 | size_t bodyPadding = padPointer(body, static_cast(slotSize_)); 44 | 45 | // 注意:多个线程(eventLoop共用一个MemoryPool) 46 | Slot* useSlot; 47 | { 48 | MutexLockGuard lock(mutex_other_); 49 | // newBlock接到Block链表的头部 50 | reinterpret_cast(newBlock)->next = currentBolck_; 51 | currentBolck_ = reinterpret_cast(newBlock); 52 | // 为该Block开始的地方加上bodyPadding个char* 空间 53 | currentSlot_ = reinterpret_cast(body + bodyPadding); 54 | lastSlot_ = reinterpret_cast(newBlock + BlockSize - slotSize_ + 1); 55 | useSlot = currentSlot_; 56 | 57 | // slot指针一次移动8个字节 58 | currentSlot_ += (slotSize_ >> 3); 59 | // currentSlot_ += slotSize_; 60 | } 61 | 62 | return useSlot; 63 | } 64 | 65 | // template 66 | Slot* MemoryPool::nofree_solve() { 67 | if(currentSlot_ >= lastSlot_) 68 | return allocateBlock(); 69 | Slot* useSlot; 70 | { 71 | MutexLockGuard lock(mutex_other_); 72 | useSlot = currentSlot_; 73 | currentSlot_ += (slotSize_ >> 3); 74 | } 75 | 76 | return useSlot; 77 | } 78 | 79 | 80 | Slot* MemoryPool::allocate() { 81 | if(freeSlot_) { 82 | { 83 | MutexLockGuard lock(mutex_freeSlot_); 84 | if(freeSlot_) { 85 | Slot* result = freeSlot_; 86 | freeSlot_ = freeSlot_->next; 87 | return result; 88 | } 89 | } 90 | } 91 | 92 | return nofree_solve(); 93 | } 94 | 95 | // template 96 | inline void MemoryPool::deAllocate(Slot* p) { 97 | if(p) { 98 | // 将slot加入释放队列 99 | MutexLockGuard lock(mutex_freeSlot_); 100 | p->next = freeSlot_; 101 | freeSlot_ = p; 102 | } 103 | } 104 | 105 | // template 106 | MemoryPool& get_MemoryPool(int id) { 107 | static MemoryPool memorypool_[64]; 108 | return memorypool_[id]; 109 | } 110 | 111 | // 数组中分别存放Slot大小为8,16,...,512字节的BLock链表 112 | void init_MemoryPool() { 113 | for(int i = 0; i < 64; ++i) { 114 | get_MemoryPool(i).init((i + 1) << 3); 115 | } 116 | } 117 | 118 | // 超过512字节就直接new 119 | void* use_Memory(size_t size) { 120 | if(!size) 121 | return nullptr; 122 | if(size > 512) 123 | return operator new(size); 124 | 125 | // 相当于(size / 8)向上取整 126 | return reinterpret_cast(get_MemoryPool(((size + 7) >> 3) - 1).allocate()); 127 | } 128 | 129 | void free_Memory(size_t size, void* p) { 130 | if(!p) return; 131 | if(size > 512) { 132 | operator delete (p); 133 | return; 134 | } 135 | get_MemoryPool(((size + 7) >> 3) - 1).deAllocate(reinterpret_cast(p)); 136 | } -------------------------------------------------------------------------------- /WebServer/old_version/src/memory/MemoryPool.h: -------------------------------------------------------------------------------- 1 | // @Author: Lawson 2 | // @CreateDate: 2022/04/21 3 | // @ModifiedDate: 2022/04/21 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include "../base/MutexLock.h" 15 | 16 | #define BlockSize 4096 17 | 18 | struct Slot { 19 | Slot* next; 20 | }; 21 | 22 | // template 23 | class MemoryPool { 24 | public: 25 | MemoryPool(); 26 | ~MemoryPool(); 27 | 28 | void init(int size); 29 | 30 | // 分配或收回一个元素的内存空间 31 | Slot* allocate(); 32 | void deAllocate(Slot* p); 33 | private: 34 | int slotSize_; // 每个槽所占字节数 35 | 36 | Slot* currentBolck_; // 内存块链表的头指针 37 | Slot* currentSlot_; // 元素链表的头指针 38 | Slot* lastSlot_; // 可存放元素的最后指针 39 | Slot* freeSlot_; // 元素构造后释放掉的内存链表头指针 40 | 41 | MutexLock mutex_freeSlot_; 42 | MutexLock mutex_other_; 43 | 44 | size_t padPointer(char* p, size_t align); // 计算对齐所需空间 45 | Slot* allocateBlock(); // 申请内存块放进内存池 46 | Slot* nofree_solve(); 47 | }; 48 | 49 | void init_MemoryPool(); 50 | void* use_Memory(size_t size); 51 | void free_Memory(size_t size, void* p); 52 | 53 | // template 54 | MemoryPool& get_MemoryPool(int id); 55 | 56 | template 57 | T* newElement(Args&&... args) { 58 | T* p; 59 | if((p = reinterpret_cast(use_Memory(sizeof(T)))) != nullptr) 60 | // new(p) T1(value); 61 | // placement new:在指针p所指向的内存空间创建一个T1类型的对象,类似与realloc 62 | // 把已有的空间当成一个缓冲区来使用,减少了分配空间所耗费的时间 63 | // 因为直接用new操作符分配内存的话,在堆中查找足够大的剩余空间速度是比较慢的 64 | new(p) T(std::forward(args)...); // 完美转发 65 | 66 | return p; 67 | } 68 | 69 | // 调用p的析构函数,然后将其总内存池中释放 70 | template 71 | void deleteElement(T* p) { 72 | // printf("deleteElement...\n"); 73 | if(p) 74 | p->~T(); 75 | free_Memory(sizeof(T), reinterpret_cast(p)); 76 | // printf("deleteElement success\n"); 77 | } -------------------------------------------------------------------------------- /WebServer/old_version/src/memory/tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 将..目录下的所有源文件赋值给DIR_SRCS变量 2 | aux_source_directory(. Dir_source) 3 | 4 | add_executable(test_MemoryPool ${Dir_source}) 5 | 6 | # 将libserver_base与其他库链接(不加后缀) 7 | target_link_libraries(test_MemoryPool memory) 8 | 9 | 10 | -------------------------------------------------------------------------------- /WebServer/old_version/src/memory/tests/test_MemoryPool.cc: -------------------------------------------------------------------------------- 1 | #include "../MemoryPool.h" 2 | #include 3 | 4 | using namespace std; 5 | 6 | class Person { 7 | public: 8 | int id_; 9 | std::string name_; 10 | public: 11 | Person(int id, std::string name) : id_(id), name_(name) { 12 | printf("构造函数调用\n"); 13 | } 14 | ~Person() { 15 | printf("析构函数调用\n"); 16 | } 17 | }; 18 | 19 | void test01() { 20 | printf("creating a person\n"); 21 | shared_ptr p1(newElement(11, "Lawson"), deleteElement); 22 | printf("sizeof(name_) = %d\n", sizeof(p1->name_)); 23 | printf("sizeof(Person) = %d\n", sizeof(Person)); 24 | } 25 | 26 | int main() { 27 | test01(); 28 | } -------------------------------------------------------------------------------- /WebServer/old_version/src/package/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | aux_source_directory(. DIR_PACKAGE_SRCS) 2 | 3 | add_library(package ${DIR_PACKAGE_SRCS}) -------------------------------------------------------------------------------- /WebServer/old_version/src/package/Util.h: -------------------------------------------------------------------------------- 1 | // @Author: Lawson 2 | // @Date: 2022/03/25 3 | 4 | #pragma once 5 | #include 6 | #include 7 | #include 8 | 9 | // size_t用于数组下标和内存管理函数 10 | // ssize_t表示读写操作的数据块的大小 11 | ssize_t readn(int fd, void *buff, size_t n); 12 | ssize_t readn(int fd, std::string& inBuffer, bool& zero); 13 | ssize_t readn(int fd, std::string& inBuffer); 14 | 15 | ssize_t writen(int fd, void* buff, size_t n); 16 | ssize_t writen(int fd, std::string& sbuff); 17 | 18 | // 对open和close的封装 19 | int Open(const char *pathname,int oflags,mode_t mode); 20 | int Close(int srcfd); 21 | 22 | // epoll的封装 23 | int Epoll_create(int size); 24 | int Epoll_create1(int flags); 25 | int Epoll_ctl(int epfd, int op, int fd, epoll_event *event); 26 | int Epoll_wait(int epfd, epoll_event *events, int maxevents, int timeout); 27 | 28 | int Eventfd(unsigned int initval, int flags); 29 | 30 | void handle_for_sigpipe(); 31 | int setSocketNonBlocking(int fd); 32 | void setSocketNoDelay(int fd); 33 | void setSocketNoLinger(int fd); 34 | void shutDownWR(int fd); 35 | int socket_bind_listen(int port); 36 | -------------------------------------------------------------------------------- /WebServer/old_version/src/page/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Liluoquan/a-high-concurrency-webserver-in-linux/fb360a54709082cff606b8e52a65738bacc7440e/WebServer/old_version/src/page/favicon.ico -------------------------------------------------------------------------------- /WebServer/old_version/src/page/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | test page 6 | 7 | 8 |

Lawson's WebServer

9 |
10 |

Welcome to Lawson's WebServer!

11 |

this HttpServer is write by C++11 and this page is for testing.

12 | 13 | 14 | -------------------------------------------------------------------------------- /WebServer/old_version/src/page/music.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Liluoquan/a-high-concurrency-webserver-in-linux/fb360a54709082cff606b8e52a65738bacc7440e/WebServer/old_version/src/page/music.mp3 -------------------------------------------------------------------------------- /WebServer/old_version/src/page/page.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Liluoquan/a-high-concurrency-webserver-in-linux/fb360a54709082cff606b8e52a65738bacc7440e/WebServer/old_version/src/page/page.jpg -------------------------------------------------------------------------------- /WebServer/old_version/src/reactor/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | aux_source_directory(. DIR_REACTOR_SRCS) 2 | 3 | add_library(reactor ${DIR_REACTOR_SRCS} ${DIR_CONNECTION_SRCS}) 4 | 5 | target_link_libraries(reactor connection memory LFUCache libserver_base package) 6 | -------------------------------------------------------------------------------- /WebServer/old_version/src/reactor/Channel.cc: -------------------------------------------------------------------------------- 1 | // @Author: Lawson 2 | // @Date: 2022/03/30 3 | 4 | #include "Channel.h" 5 | #include "Epoll.h" 6 | #include "EventLoop.h" 7 | #include "../package/Util.h" 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | using namespace std; 15 | 16 | Channel::Channel(sp_EventLoop loop) 17 | : fd_(0), events_(0), deleted_(false), first_(true) , loop_(loop) {} 18 | 19 | Channel::Channel(sp_EventLoop loop, int fd) 20 | : fd_(fd), events_(0), deleted_(false), first_(true) , loop_(loop) {} 21 | 22 | Channel::~Channel() { 23 | // FIXME:close(fd_)? 24 | LOG << "close fd " << fd_; 25 | Close(fd_); 26 | } 27 | 28 | void Channel::handleRead() { 29 | if(readHandler_) { 30 | readHandler_(); 31 | } 32 | } 33 | 34 | void Channel::handleWrite() { 35 | if(writeHandler_) { 36 | writeHandler_(); 37 | } 38 | } 39 | 40 | void Channel::handleError() { 41 | if(errorHandler_) { 42 | errorHandler_(); 43 | } 44 | } 45 | 46 | void Channel::handleClose() { 47 | if(closeHandler_) { 48 | closeHandler_(); 49 | } 50 | } 51 | 52 | 53 | // 根据revents_的状态调用对应的回调函数 54 | void Channel::handleEvents() { 55 | // events_ = 0; 56 | if((revents_ & EPOLLHUP) && !(revents_ & EPOLLIN)) { 57 | // events_ = 0; 58 | // TODO:设置关闭回调函数 59 | handleClose(); 60 | return; 61 | } 62 | if(revents_ & EPOLLERR) { 63 | handleError(); 64 | // events_ = 0; 65 | return; 66 | } 67 | if(revents_ & (EPOLLIN /* | EPOLLPRI | EPOLLRDHUP */)) { 68 | handleRead(); 69 | } 70 | if(revents_ & EPOLLOUT) { 71 | handleWrite(); 72 | } 73 | } 74 | 75 | 76 | 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /WebServer/old_version/src/reactor/Channel.h: -------------------------------------------------------------------------------- 1 | // @Author: Lawson 2 | // @Date: 2022/03/30 3 | 4 | #pragma once 5 | #include "EventLoop.h" 6 | #include "../base/noncopyable.h" 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | class EventLoop; 13 | typedef std::shared_ptr sp_EventLoop; 14 | 15 | class Channel : noncopyable { 16 | typedef std::function CallBack; 17 | public: 18 | Channel(sp_EventLoop loop); 19 | Channel(sp_EventLoop loop, int fd); 20 | ~Channel(); 21 | 22 | int getFd() { return fd_; } 23 | void setFd(int fd) { fd_ = fd; } 24 | void setRevents(__uint32_t revt) { revents_ = revt; } // called by poller 25 | void setEvents(__uint32_t evt) { events_ = evt; } 26 | __uint32_t &getEvents() { return events_; } // 此处返回的是引用,因此外部可以更改events_的值 27 | bool isDeleted() { return deleted_; } 28 | void setDeleted(bool deleted) { deleted_ = deleted; } 29 | bool isFirst() { return first_; } 30 | void setnotFirst() { first_ = false; } 31 | std::weak_ptr getLoop() { return loop_; } 32 | 33 | void setReadHandler(CallBack&& readHandler) { readHandler_ = std::move(readHandler); } 34 | void setWriteHandler(CallBack&& writeHandler) { writeHandler_ = std::move(writeHandler); } 35 | void setCloseHandler(CallBack&& closeHandler) { closeHandler_ = std::move(closeHandler); } 36 | void setErrorHanler(CallBack&& errorHandler) { errorHandler_ = std::move(errorHandler); } 37 | 38 | void handleEvents(); // 根据revents_的状态调用对应的回调函数 39 | void handleRead(); 40 | void handleWrite(); 41 | void handleError(); 42 | void handleClose(); 43 | 44 | private: 45 | int fd_; 46 | __uint32_t events_; // Channel关心的事件 47 | __uint32_t revents_; // epoll/poll返回的活动事件 48 | bool deleted_; 49 | bool first_; 50 | std::weak_ptr loop_; 51 | 52 | CallBack readHandler_; 53 | CallBack writeHandler_; 54 | CallBack closeHandler_; 55 | CallBack errorHandler_; 56 | }; 57 | 58 | typedef std::shared_ptr sp_Channel; 59 | -------------------------------------------------------------------------------- /WebServer/old_version/src/reactor/Epoll.cc: -------------------------------------------------------------------------------- 1 | // @Author: Lawson 2 | // @Date: 2022/03/28 3 | 4 | #include "Epoll.h" 5 | #include "../package/Util.h" 6 | #include "../base/Logging.h" 7 | #include 8 | #include 9 | #include // 定义数据结构sockaddr_in 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include // 提供IP地址转换函数 16 | #include 17 | using namespace std; 18 | 19 | const int EVENTSNUM = 4096; // 最大活动事件数目,TODO:动态扩展,类似vector 20 | const int EPOLLWAIT_TIME = -1; // ms,-1:epoll_wait()无限期阻塞 21 | const int MAXFDS = 10000; //最大描述符数目 22 | 23 | typedef shared_ptr sp_Channel; 24 | 25 | 26 | // Epoll类管理一个epoll对象 27 | Epoll::Epoll() : epollFd_(Epoll_create1(EPOLL_CLOEXEC)), events_(EVENTSNUM) { 28 | assert(epollFd_ > 0); 29 | } 30 | 31 | Epoll::~Epoll() { 32 | Close(epollFd_); 33 | } 34 | 35 | // 注册新描述符 36 | void Epoll::epoll_add(const sp_Channel& request) { 37 | int fd = request->getFd(); 38 | 39 | struct epoll_event event; 40 | event.data.fd = fd; 41 | event.events = request->getEvents(); 42 | 43 | Epoll_ctl(epollFd_, EPOLL_CTL_ADD, fd, &event); 44 | 45 | channelMap_[fd] = move(request); 46 | // LOG << "add to poller"; 47 | }; 48 | 49 | // 修改描述符状态 50 | void Epoll::epoll_mod(const sp_Channel& request) { 51 | int fd = request->getFd(); 52 | 53 | struct epoll_event event; 54 | event.data.fd = fd; 55 | event.events = request->getEvents(); 56 | 57 | Epoll_ctl(epollFd_, EPOLL_CTL_MOD, fd, &event); 58 | } 59 | 60 | // 从epoll中删除描述符 61 | void Epoll::epoll_del(const sp_Channel& request) { 62 | int fd = request->getFd(); 63 | 64 | struct epoll_event event; 65 | event.data.fd = fd; 66 | event.events = request->getEvents(); 67 | 68 | // FIXME:貌似新版本可以不传入*event 69 | Epoll_ctl(epollFd_, EPOLL_CTL_DEL, fd, &event); 70 | 71 | channelMap_.erase(fd); 72 | } 73 | 74 | void Epoll::poll(std::vector& req) { 75 | int event_count = 76 | Epoll_wait(epollFd_, &*events_.begin(), events_.size(), EPOLLWAIT_TIME); 77 | for(int i = 0; i < event_count; ++i) { 78 | int fd = events_[i].data.fd; 79 | sp_Channel temp = channelMap_[fd]; 80 | temp->setRevents(events_[i].events); 81 | req.emplace_back(std::move(temp)); 82 | } 83 | // LOG << "Epoll finished"; 84 | } 85 | 86 | // // 返回活跃Channel 87 | // std::vector Epoll::poll() { 88 | // while(true) { 89 | // int event_count = 90 | // Epoll_wait(epollFd_, &*events_.begin(), events_.size(), EPOLLWAIT_TIME); 91 | // std::vector activeChannels = getEventsRequest(event_count); 92 | // if(activeChannels.size() > 0) return activeChannels; 93 | // } 94 | // } 95 | 96 | // // 根据活动事件将活动频道放入activeChannels 97 | // std::vector Epoll::getEventsRequest(int events_num) { 98 | // std::vector activeChannels; 99 | // for(int i = 0; i < events_num; ++i) { 100 | // // 获取有事件产生的描述符 101 | // int fd = events_[i].data.fd; 102 | // sp_Channel activeChannel = channelMap_[fd]; 103 | 104 | // if(activeChannel) { 105 | // activeChannel->setRevents(events_[i].events); 106 | // activeChannels.emplace_back(std::move(activeChannel)); 107 | // } 108 | // else { 109 | // LOG << "activeChannels is invalid"; 110 | // } 111 | // } 112 | 113 | // return activeChannels; 114 | // } 115 | 116 | 117 | 118 | 119 | -------------------------------------------------------------------------------- /WebServer/old_version/src/reactor/Epoll.h: -------------------------------------------------------------------------------- 1 | // @Author: Lawson 2 | // @Date: 2022/03/28 3 | 4 | #pragma once 5 | #include "Channel.h" 6 | #include "../connection/httpConnection.h" 7 | #include "Timer.h" 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | class Channel; 14 | typedef std::shared_ptr sp_Channel; 15 | 16 | class Epoll { 17 | public: 18 | Epoll(); 19 | ~Epoll(); 20 | void epoll_add(const sp_Channel& request); 21 | void epoll_mod(const sp_Channel& request); 22 | void epoll_del(const sp_Channel& request); 23 | void poll(std::vector& req); 24 | // std::vector poll(); 25 | // std::vector getEventsRequest(int events_num); 26 | // void add_timer(std::shared_ptr request_data, int timeout); 27 | // int getEpollFd() { return epollFd_; } 28 | // void handleExpired(); 29 | 30 | private: 31 | // static const int MAXFDS = 100000; 32 | int epollFd_; 33 | std::vector events_; // epoll_wait()返回的活动事件都放在这个数组里 34 | std::unordered_map channelMap_; 35 | }; 36 | 37 | typedef std::shared_ptr sp_Epoll; 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /WebServer/old_version/src/reactor/eventLoop.cc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Liluoquan/a-high-concurrency-webserver-in-linux/fb360a54709082cff606b8e52a65738bacc7440e/WebServer/old_version/src/reactor/eventLoop.cc -------------------------------------------------------------------------------- /WebServer/old_version/src/reactor/eventLoop.h: -------------------------------------------------------------------------------- 1 | // @Author: Lawson 2 | // @Date: 2022/07/13 3 | 4 | #pragma once 5 | 6 | #include "Channel.h" 7 | #include "Epoll.h" 8 | #include "../base/MutexLock.h" 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | namespace event { 15 | 16 | // Reactor模式的核心 每个Reactor线程内部调用一个EventLoop 17 | // 内部不停的进行epoll_wait调用 然后调用fd对应Channel的相应回调函数进行处理 18 | 19 | class EventLoop { 20 | using Functor = std::function; 21 | public: 22 | EventLoop(); 23 | ~EventLoop(); 24 | 25 | void loop(); // 开始事件循环 调用该函数的线程必须是该EventLoop所在线程,也就是Loop函数不能跨线程调用 26 | void stopLoop(); // 停止Loop 27 | void runInLoop(Functor&& func); // 如果当前线程就是创建此EventLoop的线程 就调用callback(关闭连接 EpollDel) 否则就放入等待执行函数区 28 | void queueInLoop(Functor&& func); // 把此函数放入等待执行函数区 如果当前是跨线程 或者正在调用等待的函数则唤醒 29 | 30 | // 把fd和绑定的事件注册到epoll内核事件表 31 | void addToPoller(std::shared_ptr channel, int timeout = 0); 32 | // 在epoll内核事件表修改fd所绑定的事件 33 | void addToPoller(std::shared_ptr channel, int timeout = 0); 34 | // 从epoll内核事件表中删除fd及其绑定的事件 35 | void removeFromPoller(std::shared_ptr channel, int timeout = 0); 36 | 37 | private: 38 | static int creatEventFd(); // 创建eventfd 类似管道的 进程间通信方式 39 | 40 | void handleRead(); // eventfd的读回调函数(因为event_fd写了数据,所以触发可读事件,从event_fd读数据) 41 | void handleUpdate(); // eventfd的更新事件回调函数(更新监听事件) 42 | void wakeup(); // 异步唤醒SubLoop的epoll_wait(向event_fd中写入数据) 43 | void doPendingFunctors(); // 执行正在等待的函数(SubLoop注册EpollAdd连接套接字以及绑定事件的函数) 44 | 45 | private: 46 | std::shared_ptr poller_; // io多路复用 分发器 47 | int eventFd_; // 用于异步唤醒SubLoop的Loop函数中的Poll(epoll_wait因为还没有注册fd会一直阻塞) 48 | std::shared_ptr wakeupChannel_; // 用于异步唤醒的 channel 49 | pid_t threadId; // 线程id 50 | 51 | mutable MutexLock mutex_; 52 | std::vector pendingFunctors_; // 正在等待处理的函数 53 | 54 | bool isStop_; // 是否停止事件循环 55 | bool isLooping_; // 是否正在事件循环 56 | bool isEventHandling_; // 是否正在处理事件 57 | bool isCallingPendingFunctor_; // 是否正在调用等待处理的函数 58 | 59 | }; 60 | 61 | 62 | } // namespace event 63 | 64 | 65 | -------------------------------------------------------------------------------- /WebServer/old_version/src/reactor/old/EventLoop.cc: -------------------------------------------------------------------------------- 1 | // @Author: Lawson 2 | // @Date: 2022/03/31 3 | 4 | #include "EventLoop.h" 5 | #include 6 | #include 7 | #include "../package/Util.h" 8 | #include "../base/Logging.h" 9 | #include "../memory/MemoryPool.h" 10 | 11 | using namespace std; 12 | 13 | bool EventLoop::quit_ = false; 14 | 15 | EventLoop::EventLoop() 16 | : poller_(newElement(), deleteElement), 17 | looping_(false), 18 | timerManager_(newElement(), deleteElement) 19 | { 20 | wakeupfd_ = Eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); 21 | } 22 | 23 | void EventLoop::removeFromPoller(sp_Channel channel) 24 | { 25 | poller_->epoll_del(channel); 26 | } 27 | 28 | void EventLoop::updatePoller(sp_Channel channel) 29 | { 30 | poller_->epoll_mod(channel); 31 | } 32 | 33 | void EventLoop::addToPoller(sp_Channel channel) 34 | { 35 | poller_->epoll_add(channel); 36 | } 37 | 38 | void EventLoop::addTimer(sp_Channel channel, int timeout) 39 | { 40 | timerManager_->addTimer(std::move(channel), timeout); 41 | } 42 | 43 | void EventLoop::loop() 44 | { 45 | pwakeupChannel_ = sp_Channel(newElement(shared_from_this()), deleteElement); 46 | pwakeupChannel_->setFd(wakeupfd_); 47 | pwakeupChannel_->setEvents(EPOLLIN | EPOLLET); 48 | pwakeupChannel_->setReadHandler(std::bind(&EventLoop::doPendingFunctors, shared_from_this())); 49 | addToPoller(pwakeupChannel_); 50 | 51 | std::vector ret; 52 | // LOG << "enter loop"; 53 | while (!quit_) 54 | { 55 | poller_->poll(ret); 56 | for (auto &it : ret) 57 | it->handleEvents(); 58 | ret.clear(); 59 | timerManager_->handleExpiredEvent(); 60 | } 61 | } 62 | 63 | void EventLoop::queueInLoop(Functor &&cb) 64 | { 65 | { 66 | MutexLockGuard lock(mutex_); 67 | pendingFunctors_.emplace_back(std::move(cb)); 68 | } 69 | 70 | uint64_t buffer = 1; 71 | if (write(wakeupfd_, &buffer, sizeof(buffer)) < 0) 72 | LOG << "wake up write error"; 73 | } 74 | 75 | void EventLoop::doPendingFunctors() 76 | { 77 | uint64_t buffer; 78 | if (read(wakeupfd_, &buffer, sizeof(buffer)) < 0) 79 | LOG << "wake up read error"; 80 | 81 | // 使用swap缩短了临界区的长度 82 | std::vector next; 83 | { 84 | MutexLockGuard lock(mutex_); 85 | next.swap(pendingFunctors_); 86 | } 87 | 88 | for (auto &it : next) 89 | it(); 90 | } 91 | 92 | void EventLoop::setquit(int a) 93 | { 94 | quit_ = true; 95 | } 96 | -------------------------------------------------------------------------------- /WebServer/old_version/src/reactor/old/EventLoop.h: -------------------------------------------------------------------------------- 1 | // @Author: Lawson 2 | // @Date: 2022/03/30 3 | 4 | #pragma once 5 | #include 6 | #include 7 | #include 8 | #include "Channel.h" 9 | #include "Epoll.h" 10 | #include "../package/Util.h" 11 | #include "Timer.h" 12 | #include "../base/Logging.h" 13 | #include "../base/Thread.h" 14 | #include 15 | 16 | class Channel; 17 | class Epoll; 18 | class TimerManager; 19 | typedef std::shared_ptr sp_Channel; 20 | typedef std::weak_ptr wp_Channel; 21 | typedef std::shared_ptr sp_Epoll; 22 | typedef std::shared_ptr sp_TimerManager; 23 | 24 | class EventLoop:public std::enable_shared_from_this{ 25 | private: 26 | typedef std::function Functor; 27 | std::vector pendingFunctors_; 28 | int wakeupfd_; 29 | sp_Channel pwakeupChannel_; 30 | sp_Epoll poller_; 31 | bool looping_; 32 | static bool quit_; 33 | sp_TimerManager timerManager_; 34 | MutexLock mutex_; 35 | 36 | public: 37 | EventLoop(); 38 | void addToPoller(sp_Channel channel); 39 | void updatePoller(sp_Channel channel); 40 | void removeFromPoller(sp_Channel channel); 41 | void loop(); 42 | void addTimer(sp_Channel channel,int timeout); 43 | void queueInLoop(Functor &&cb); 44 | void doPendingFunctors(); 45 | static void setquit(int); 46 | }; 47 | 48 | typedef std::shared_ptr sp_EventLoop; 49 | typedef std::weak_ptr wp_EventLoop; 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /WebServer/old_version/src/reactor/old/Timer.cc: -------------------------------------------------------------------------------- 1 | // @Author: Lawson 2 | // @Date: 2022/03/26 3 | 4 | #include "Timer.h" 5 | #include "../memory/MemoryPool.h" 6 | #include 7 | #include 8 | #include 9 | 10 | // 此处的timeout可以理解为请求的延迟关闭时间 11 | TimerNode::TimerNode(sp_Channel channel, int timeout) 12 | : channel_(channel) { 13 | struct timeval now; 14 | gettimeofday(&now, NULL); 15 | // 以毫秒计算 16 | // 到期时间 = 当前时间(秒余到10000以内换算成ms + 微妙换算成ms) + 超时时间(ms) 17 | expiredTime_ = 18 | (((now.tv_sec % 10000) * 1000) + (now.tv_usec / 1000)) + timeout; 19 | } 20 | 21 | TimerNode::~TimerNode() { 22 | 23 | } 24 | 25 | 26 | // 延长Timer的到时时间 27 | void TimerNode::update(int timeout) { 28 | struct timeval now; 29 | gettimeofday(&now, NULL); 30 | expiredTime_ = 31 | (((now.tv_sec % 10000) * 1000) + (now.tv_usec / 1000)) + timeout; 32 | } 33 | 34 | bool TimerNode::isValid() { 35 | struct timeval now; 36 | gettimeofday(&now, NULL); 37 | size_t temp = (((now.tv_sec % 10000) * 1000) + (now.tv_usec / 1000)); 38 | if(temp < expiredTime_) 39 | return true; 40 | else { 41 | // this->setDeleted(); 42 | return false; 43 | } 44 | } 45 | 46 | bool TimerNode::isDeleted() const{ 47 | return channel_->isDeleted(); 48 | } 49 | 50 | 51 | void TimerManager::addTimer(sp_Channel channel, int timeout) { 52 | sp_TimerNode new_node(newElement(channel, timeout), deleteElement); 53 | int fd = channel->getFd(); 54 | 55 | if(channel->isFirst()) { 56 | timerHeap_.push(new_node); 57 | channel->setnotFirst(); 58 | } 59 | timerMap_[fd] = std::move(new_node); 60 | } 61 | 62 | // 一个Channel对应多个TimerNode,当该TimerNode节点全部弹出时,删除该事件 63 | void TimerManager::handleExpiredEvent() { 64 | while(!timerHeap_.empty()) { 65 | sp_TimerNode ptimer_now = timerHeap_.top(); 66 | if(ptimer_now->isDeleted() || !ptimer_now->isValid()) { 67 | timerHeap_.pop(); 68 | sp_TimerNode timer = timerMap_[ptimer_now->getChannel()->getFd()]; 69 | if(ptimer_now == timer) { 70 | timerMap_.erase(ptimer_now->getChannel()->getFd()); 71 | ptimer_now->getChannel()->handleClose(); 72 | } 73 | else 74 | timerHeap_.push(timer); 75 | } 76 | else 77 | break; 78 | } 79 | } 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /WebServer/old_version/src/reactor/old/Timer.h: -------------------------------------------------------------------------------- 1 | // @Author: Lawson 2 | // @Date: 2022/03/26 3 | 4 | #pragma once 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "Channel.h" 12 | #include "../base/MutexLock.h" 13 | #include "../base/noncopyable.h" 14 | 15 | class Channel; 16 | typedef std::shared_ptr sp_Channel; 17 | 18 | // TimerNode用于处理HTTP请求 19 | class TimerNode { 20 | public: 21 | TimerNode(sp_Channel channel, int timeout); 22 | // TimerNode(TimerNode& tn); 23 | ~TimerNode(); 24 | void update(int timeout); 25 | bool isValid(); 26 | // void setDeleted() { deleted_ = true; } 27 | bool isDeleted() const; 28 | size_t getExpTime() const { return expiredTime_; } 29 | sp_Channel getChannel() const { return channel_; } 30 | 31 | private: 32 | // bool deleted_; 33 | sp_Channel channel_; 34 | size_t expiredTime_; // 定时器过期时间 35 | }; 36 | 37 | typedef std::shared_ptr sp_TimerNode; 38 | 39 | struct TimerCmp { 40 | bool operator() (sp_TimerNode& a, sp_TimerNode& b) const { 41 | return a->getExpTime() > b->getExpTime(); 42 | } 43 | }; 44 | 45 | // TimerManager用于管理TimerNode 46 | class TimerManager { 47 | public: 48 | void addTimer(sp_Channel channel, int timeout); 49 | void handleExpiredEvent(); 50 | 51 | private: 52 | std::priority_queue, TimerCmp> 53 | timerHeap_; // 小根堆 54 | std::unordered_map timerMap_; 55 | }; 56 | 57 | typedef std::shared_ptr sp_TimerManager; 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /WebServer/old_version/src/reactor/timer.cc: -------------------------------------------------------------------------------- 1 | // @Author: Lawson 2 | // @Date: 2022/07/12 3 | 4 | #include "timer.h" 5 | #include "../base/Logging.h" 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | namespace timer { 14 | 15 | Timer::Timer(std::shared_ptr pHttpConnection, int timeout) 16 | : pHttpConnection_(pHttpConnection), 17 | isDeleted_(false) { 18 | struct timeval now; 19 | gettimeofday(&now, NULL); 20 | // 以毫秒计算 21 | // 到期时间 = 当前时间(秒余到10000以内换算成毫秒 + 微妙换算成毫秒) + 超时时间(毫秒) 22 | expireTime_ = (((now.tv_sec % 10000) * 1000) + (now.tv_usec / 1000)) + timeout; 23 | } 24 | 25 | Timer::Timer(Timer& timer) : pHttpConnection_(timer.pHttpConnection_), expireTime_(0) {} 26 | 27 | // Timer析构时 (如果是因重新绑定新定时器而将此旧定时器删除的情况,http对象reset,所以不会调用Delete) 28 | // 如果是因为超时而将此定时器删除的情况 就会调用http的Delete(EpollDel, close(fd)) 29 | Timer::~Timer() { 30 | if (pHttpConnection_) { 31 | LOG << "Timeout, close sockfd: " << pHttpConnection_->getFd(); 32 | pHttpConnection_->release(); 33 | } 34 | } 35 | 36 | void Timer::update(int timeout) { 37 | struct timeval now; 38 | gettimeofday(&now, NULL); 39 | expireTime_ = (((now.tv_sec % 10000) * 1000) + (now.tv_usec / 1000)) + timeout; 40 | } 41 | 42 | bool Timer::isExpired() { 43 | struct timeval now; 44 | gettimeofday(&now, NULL); 45 | size_t curTime = (((now.tv_sec % 10000) * 1000) + (now.tv_usec / 1000)); 46 | if (curTime >= expireTime_) { 47 | isDeleted_ = true; 48 | return true; 49 | } 50 | 51 | return false; 52 | } 53 | 54 | void Timer::release() { 55 | pHttpConnection_->release(); 56 | isDeleted_ = true; 57 | } 58 | 59 | 60 | } // namespace timer -------------------------------------------------------------------------------- /WebServer/old_version/src/reactor/timerManager.cc: -------------------------------------------------------------------------------- 1 | // @Author: Lawson 2 | // @Date: 2022/07/12 3 | 4 | #include "timerManager.h" 5 | #include "../connection/httpConnection.h" 6 | 7 | #include 8 | 9 | namespace timer { 10 | 11 | void TimerManager::addTimer(std::shared_ptr pHttpConnection, int timeout) { 12 | // new 一个定时器,加到定时器队列中 13 | auto timer = std::make_shared(pHttpConnection, timeout); 14 | timerHeap_.emplace(timer); 15 | pHttpConnection->setTimer(timer); 16 | } 17 | 18 | // 处理到期事件 如果定时器被删除或者已经到期 就从定时器队列中删除 19 | // 定时器析构的时候 会调用http->close 会关闭http连接,EpollDel绑定的connect_fd 20 | void TimerManager::handleExpireEvent() { 21 | while (!timerHeap_.empty()) { 22 | auto timer = timerHeap_.top(); 23 | // 如果是被删除了(惰性删除 已经到期了但是还没被访问所以没被删) 或者到期了都会pop定时器 24 | if (timer->isDeleted() || timer->isExpired()) { 25 | timerHeap_.pop(); 26 | } 27 | else { 28 | break; 29 | } 30 | } 31 | } 32 | 33 | 34 | } // namespace timer 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /WebServer/old_version/src/server/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | aux_source_directory(. DIR_SERVER_SRCS) 2 | 3 | add_library(server ${DIR_SERVER_SRCS}) 4 | 5 | target_link_libraries(server manager memory reactor threadPool libserver_base package) 6 | -------------------------------------------------------------------------------- /WebServer/old_version/src/server/FTPServer.cc: -------------------------------------------------------------------------------- 1 | // @Author: Lawson 2 | // @CreateDate: 2022/05/05 3 | // @LastModifiedDate: 2022/05/05 4 | 5 | #include "FTPServer.h" 6 | #include "../package/Util.h" 7 | #include "../base/Logging.h" 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #define DEBUG 14 | #define USERINFOFILENAME "user.txt" 15 | 16 | using namespace std; 17 | 18 | FTPServer::FTPServer(int threadNum, int port, std::string dir, unsigned short commandOffset) 19 | : loop_(newElement(), deleteElement), 20 | acceptChannel_(newElement(loop_), deleteElement), 21 | threadNum_(threadNum), 22 | eventLoopThreadPool_(newElement(threadNum), deleteElement), 23 | started_(false), 24 | port_(port), 25 | listenFd_(socket_bind_listen(port)), 26 | dir_(dir), commandOffset_(commandOffset), connId_(0), 27 | userManager_(userManager::getUserManger(USERINFOFILENAME)) 28 | { 29 | 30 | if(setSocketNonBlocking(listenFd_) < 0) { 31 | LOG << "set socket non-blocking failed"; 32 | exit(EXIT_SUCCESS); 33 | } 34 | 35 | acceptChannel_->setFd(listenFd_); 36 | // std::cout << "dir_ = " << dir_ << std::endl; 37 | } 38 | 39 | FTPServer::~FTPServer() { 40 | Close(listenFd_); 41 | } 42 | 43 | void FTPServer::start() { 44 | eventLoopThreadPool_->start(); 45 | acceptChannel_->setEvents(EPOLLIN | EPOLLET); 46 | acceptChannel_->setReadHandler(bind(&FTPServer::handleNewConn, this)); 47 | 48 | loop_->addToPoller(acceptChannel_); 49 | LOG << "Server start!"; 50 | loop_->loop(); 51 | } 52 | 53 | void FTPServer::handleNewConn() { 54 | struct sockaddr_in client_addr; 55 | memset(&client_addr, 0, sizeof(struct sockaddr_in)); 56 | socklen_t client_addr_len = sizeof(client_addr); 57 | int accept_fd = 0; 58 | while((accept_fd = accept(listenFd_, (struct sockaddr*)&client_addr, 59 | &client_addr_len)) > 0) { 60 | 61 | // 设为非阻塞模式 62 | if (setSocketNonBlocking(accept_fd) < 0){ 63 | LOG << "Set non-blocking failed"; 64 | return; 65 | } 66 | 67 | 68 | LOG << "New connection from " << inet_ntoa(client_addr.sin_addr) << ":" 69 | << ntohs(client_addr.sin_port); 70 | 71 | if (accept_fd >= MAXFDS) { 72 | LOG << "to many fds"; 73 | close(accept_fd); 74 | continue; 75 | } 76 | 77 | // sp_EventLoop nextLoop = eventLoopThreadPool_->getNextLoop(); 78 | // sp_Channel loginChannel(newElement(nextLoop, accept_fd), deleteElement); 79 | // std::weak_ptr wpChannel = loginChannel; 80 | // loginChannel->setCloseHandler(bind(&FTPServer::handleClose, this, wpChannel)); 81 | // loginChannel->setReadHandler(bind(&FTPServer::login, this, wpChannel)); 82 | // loginChannel->setEvents(EPOLLIN | EPOLLET); 83 | // nextLoop->queueInLoop(std::bind(&EventLoop::addToPoller, nextLoop, move(loginChannel))); 84 | sp_EventLoop nextLoop = eventLoopThreadPool_->getNextLoop(); 85 | sp_Channel ftpChannel(newElement(nextLoop, accept_fd), deleteElement); 86 | std::weak_ptr wpChannel(ftpChannel); 87 | ftpChannel->setCloseHandler(std::bind(&FTPServer::handleClose, this, wpChannel)); 88 | 89 | sp_ftpConnection connFtp(newElement(ftpChannel, connId_, dir_, commandOffset_), deleteElement); 90 | ftpMap_[accept_fd] = std::move(connFtp); 91 | 92 | nextLoop->queueInLoop(std::bind(&EventLoop::addToPoller, nextLoop, std::move(ftpChannel))); 93 | } 94 | } 95 | 96 | void FTPServer::handleClose(std::weak_ptr channel) { 97 | sp_Channel ftpChannel = channel.lock(); 98 | 99 | loop_->queueInLoop(bind(&FTPServer::deleteFromMap, this, ftpChannel)); 100 | ftpChannel->getLoop().lock()->removeFromPoller(ftpChannel); 101 | 102 | LOG << "connection closed"; 103 | } 104 | 105 | void FTPServer::deleteFromMap(sp_Channel ftpChannel) { 106 | ftpMap_.erase(ftpChannel->getFd()); 107 | } 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | -------------------------------------------------------------------------------- /WebServer/old_version/src/server/FTPServer.h: -------------------------------------------------------------------------------- 1 | // @Author: Lawson 2 | // @CreateDate: 2022/05/05 3 | // @LastModifiedDate: 2022/05/05 4 | 5 | #pragma once 6 | 7 | #include 8 | #include "../reactor/EventLoop.h" 9 | #include "../threadPool/EventLoopThreadPool.h" 10 | #include "../memory/MemoryPool.h" 11 | #include "../manager/userManager.h" 12 | // #include "../manager/fileManager.h" 13 | #include "../manager/fileOperator.h" 14 | #include "../connection/ftpConnection.h" 15 | 16 | class FTPServer { 17 | using sp_ftpConnection = std::shared_ptr; 18 | public: 19 | FTPServer(int threadNum, int port, string dir, unsigned short commandOffset); 20 | ~FTPServer(); 21 | void start(); 22 | 23 | private: 24 | sp_EventLoop loop_; //accept线程 25 | sp_Channel acceptChannel_; 26 | int threadNum_; 27 | std::unique_ptr)*> eventLoopThreadPool_; 28 | bool started_; 29 | int port_; 30 | int listenFd_; 31 | static const int MAXFDS = 100000; 32 | 33 | std::string dir_; 34 | unsigned short commandOffset_; 35 | unsigned int connId_; 36 | 37 | // static userManager::userManagerPtr userManager_; 38 | // static std::string userInfoFileName_; 39 | userManager::userManagerPtr userManager_; 40 | std::unordered_map ftpMap_; 41 | // fileManager::fileManagerPtr fileManager_; 42 | 43 | void handleNewConn(); 44 | void handleClose(std::weak_ptr channel); 45 | void deleteFromMap(sp_Channel ftpChannel); 46 | }; 47 | 48 | 49 | -------------------------------------------------------------------------------- /WebServer/old_version/src/server/HTTPServer.cc: -------------------------------------------------------------------------------- 1 | // @Author: Lawson 2 | // @CreateDate: 2022/04/06 3 | // @LastModifiedDate: 2022/04/06 4 | 5 | #include "HTTPServer.h" 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "../package/Util.h" 12 | #include "../base/Logging.h" 13 | 14 | using namespace std; 15 | 16 | HTTPServer::HTTPServer(int threadNum, int port) 17 | : loop_(newElement(), deleteElement), 18 | acceptChannel_(newElement(loop_), deleteElement), 19 | threadNum_(threadNum), 20 | eventLoopThreadPool_(newElement(threadNum), deleteElement), 21 | started_(false), 22 | port_(port), 23 | listenFd_(socket_bind_listen(port_)) 24 | { 25 | if (setSocketNonBlocking(listenFd_) < 0) 26 | { 27 | perror("set socket non-blocking failed"); 28 | } 29 | 30 | acceptChannel_->setFd(listenFd_); 31 | // handle_for_sigpipe(); 32 | } 33 | 34 | HTTPServer::~HTTPServer() { 35 | Close(listenFd_); 36 | } 37 | 38 | void HTTPServer::start() 39 | { 40 | eventLoopThreadPool_->start(); // 创建线程池,开始每个eventloop.loop() 41 | acceptChannel_->setEvents(EPOLLIN | EPOLLET); 42 | acceptChannel_->setReadHandler(bind(&HTTPServer::handleNewConn, this)); 43 | 44 | loop_->addToPoller(acceptChannel_); 45 | LOG << "HTTPServer start!"; 46 | loop_->loop(); 47 | } 48 | 49 | void HTTPServer::handleNewConn() 50 | { 51 | struct sockaddr_in client_addr; 52 | memset(&client_addr, 0, sizeof(struct sockaddr_in)); 53 | socklen_t client_addr_len = sizeof(client_addr); 54 | int accept_fd = 0; 55 | while ((accept_fd = accept(listenFd_, (struct sockaddr *)&client_addr, 56 | &client_addr_len)) > 0) 57 | { 58 | // 设为非阻塞模式 59 | if (setSocketNonBlocking(accept_fd) < 0) 60 | { 61 | LOG << "Set non-blocking failed"; 62 | return; 63 | } 64 | 65 | sp_EventLoop nextLoop = eventLoopThreadPool_->getNextLoop(); 66 | LOG << "New connection from " << inet_ntoa(client_addr.sin_addr) << ":" 67 | << ntohs(client_addr.sin_port); 68 | 69 | // 限制服务器的最大并发连接数 70 | // TODO:关闭不常用的fd 71 | if (accept_fd >= MAXFDS) 72 | { 73 | close(accept_fd); 74 | continue; 75 | } 76 | 77 | // TODO:TCP包的传输问题 78 | setSocketNoDelay(accept_fd); 79 | setSocketNoLinger(accept_fd); 80 | 81 | sp_Channel connChannel(newElement(nextLoop, accept_fd), deleteElement); 82 | std::weak_ptr wpChannel = connChannel; 83 | 84 | connChannel->setCloseHandler(bind(&HTTPServer::handleClose, this, wpChannel)); 85 | 86 | 87 | // channel由HttpData持有 88 | // std::shared_ptr req_info(new HttpData(nextLoop, accept_fd)); 89 | // req_info->getChannel()->setHolder(req_info); 90 | // nextLoop->queueInLoop(std::bind(&HttpData::newEvent, req_info)); 91 | 92 | acceptChannel_->setEvents(EPOLLIN | EPOLLET); 93 | sp_HttpConnection connHttp(newElement(connChannel), deleteElement); 94 | HttpMap_[accept_fd] = move(connHttp); 95 | 96 | nextLoop->queueInLoop(bind(&EventLoop::addToPoller, nextLoop, move(connChannel))); 97 | } 98 | 99 | } 100 | 101 | void HTTPServer::handleClose(std::weak_ptr channel) { 102 | sp_Channel spChannel = channel.lock(); 103 | 104 | loop_->queueInLoop(bind(&HTTPServer::deleteFromMap, this, spChannel)); 105 | spChannel->getLoop().lock()->removeFromPoller(spChannel); 106 | 107 | LOG << "connection closed"; 108 | } 109 | 110 | void HTTPServer::deleteFromMap(sp_Channel requst) { 111 | HttpMap_.erase(requst->getFd()); 112 | } 113 | 114 | -------------------------------------------------------------------------------- /WebServer/old_version/src/server/HTTPServer.h: -------------------------------------------------------------------------------- 1 | // @Author: Lawson 2 | // @CreateDate: 2022/04/06 3 | // @LastModifiedDate: 2022/04/06 4 | 5 | #pragma once 6 | #include 7 | #include 8 | #include "../reactor/EventLoop.h" 9 | #include "../threadPool/EventLoopThreadPool.h" 10 | #include "../memory/MemoryPool.h" 11 | #include "../connection/httpConnection.h" 12 | 13 | typedef std::shared_ptr sp_HttpConnection; 14 | 15 | class HTTPServer { 16 | public: 17 | HTTPServer(int threadNum, int port); 18 | ~HTTPServer(); 19 | void start(); 20 | 21 | private: 22 | sp_EventLoop loop_; // accept线程 23 | sp_Channel acceptChannel_; 24 | int threadNum_; 25 | std::unique_ptr)*> eventLoopThreadPool_; 26 | bool started_; 27 | int port_; 28 | int listenFd_; 29 | static const int MAXFDS = 100000; 30 | std::unordered_map HttpMap_; 31 | 32 | void handleNewConn(); 33 | // void handleThisConn() { loop_->updatePoller(acceptChannel_); } 34 | void handleClose(std::weak_ptr channel); 35 | void deleteFromMap(sp_Channel channel); 36 | }; -------------------------------------------------------------------------------- /WebServer/old_version/src/threadPool/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | aux_source_directory(. DIR_THREADPOOL_SRCS) 2 | 3 | add_library(threadPool ${DIR_THREADPOOL_SRCS}) 4 | 5 | target_link_libraries(threadPool memory reactor libserver_base package) 6 | -------------------------------------------------------------------------------- /WebServer/old_version/src/threadPool/EventLoopThread.cc: -------------------------------------------------------------------------------- 1 | // @Author: Lawson 2 | // @Date: 2022/04/01 3 | 4 | #include "EventLoopThread.h" 5 | #include "../memory/MemoryPool.h" 6 | #include 7 | #include 8 | 9 | EventLoopThread::EventLoopThread() 10 | : loop_(newElement(), deleteElement), 11 | thread_(newElement(std::bind(&EventLoopThread::threadFunc, this), "EventLoopThread"), 12 | deleteElement) 13 | { 14 | } 15 | 16 | EventLoopThread::~EventLoopThread() 17 | { 18 | } 19 | 20 | sp_EventLoop EventLoopThread::getLoop() 21 | { 22 | return loop_; 23 | } 24 | 25 | void EventLoopThread::start() 26 | { 27 | thread_->start(); 28 | } 29 | 30 | void EventLoopThread::threadFunc() 31 | { 32 | loop_->loop(); 33 | } 34 | -------------------------------------------------------------------------------- /WebServer/old_version/src/threadPool/EventLoopThread.h: -------------------------------------------------------------------------------- 1 | // @Author: Lawson 2 | // @Date: 2022/04/01 3 | 4 | #pragma once 5 | #include "../reactor/EventLoop.h" 6 | #include "../base/Condition.h" 7 | #include "../base/MutexLock.h" 8 | #include "../base/Thread.h" 9 | #include "../base/noncopyable.h" 10 | #include "../memory/MemoryPool.h" 11 | 12 | 13 | class EventLoopThread { 14 | public: 15 | EventLoopThread(); 16 | ~EventLoopThread(); 17 | void start(); 18 | sp_EventLoop getLoop(); 19 | 20 | private: 21 | void threadFunc(); //线程运行函数 22 | sp_EventLoop loop_; 23 | std::unique_ptr)*> thread_; 24 | }; 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /WebServer/old_version/src/threadPool/EventLoopThreadPool.cc: -------------------------------------------------------------------------------- 1 | // Author: Lawson 2 | // Date: 2022/04/01 3 | 4 | #include "EventLoopThreadPool.h" 5 | #include "../memory/MemoryPool.h" 6 | 7 | EventLoopThreadPool::EventLoopThreadPool(int numThreads) 8 | : numThreads_(numThreads), 9 | index_(0) { 10 | threads_.reserve(numThreads); 11 | for(int i = 0; i < numThreads_; ++i) { 12 | std::shared_ptr t(newElement(), deleteElement); 13 | threads_.emplace_back(t); 14 | } 15 | } 16 | 17 | void EventLoopThreadPool::start() { 18 | for(auto& thread : threads_) { 19 | thread->start(); 20 | } 21 | } 22 | 23 | sp_EventLoop EventLoopThreadPool::getNextLoop() { 24 | index_ = (index_ + 1) % numThreads_; 25 | return threads_[index_]->getLoop(); 26 | } 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /WebServer/old_version/src/threadPool/EventLoopThreadPool.h: -------------------------------------------------------------------------------- 1 | // @Author: Lawson 2 | // @Date: 2022/04/01 3 | 4 | #pragma once 5 | #include 6 | #include 7 | #include "EventLoopThread.h" 8 | #include "../base/Logging.h" 9 | #include "../base/noncopyable.h" 10 | 11 | // 线程池的本质是生产者消费者模型 12 | class EventLoopThreadPool { 13 | public: 14 | EventLoopThreadPool(int numThreads); 15 | ~EventLoopThreadPool() { LOG << "~EventLoopThreadPool()"; } 16 | 17 | void start(); 18 | sp_EventLoop getNextLoop(); 19 | 20 | private: 21 | int numThreads_; 22 | int index_; 23 | std::vector> threads_; 24 | }; 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /WebServer/pages/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Liluoquan/a-high-concurrency-webserver-in-linux/fb360a54709082cff606b8e52a65738bacc7440e/WebServer/pages/favicon.ico -------------------------------------------------------------------------------- /WebServer/pages/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | test page 6 | 7 | 8 |

Lawson's WebServer

9 |
10 |

Welcome to Lawson's WebServer!

11 |

this HttpServer is write by C++11 and this page is for testing.

12 | 13 | 14 | -------------------------------------------------------------------------------- /WebServer/pages/music.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Liluoquan/a-high-concurrency-webserver-in-linux/fb360a54709082cff606b8e52a65738bacc7440e/WebServer/pages/music.mp3 -------------------------------------------------------------------------------- /WebServer/pages/page.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Liluoquan/a-high-concurrency-webserver-in-linux/fb360a54709082cff606b8e52a65738bacc7440e/WebServer/pages/page.jpg -------------------------------------------------------------------------------- /WebServer/run_server.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #服务器绑定端口号 4 | port=8888 5 | #日志路径 6 | log_file_name=./server.log 7 | #是否打开日志 8 | open_log=0 9 | #日志也输出到标准错误流 10 | log_to_stderr=1 11 | #输出日志颜色 12 | color_log_to_stderr=1 13 | #打印的最小日志等级 14 | min_log_level=0 15 | #线程池 16 | thread_num=6 17 | #最大缓存页面数量 18 | page_cache_capacity=10 19 | 20 | #运行 21 | ./bin/web_server -p $port -t $thread_num -f $log_file_name \ 22 | -o $open_log -s $log_to_stderr \ 23 | -c $color_log_to_stderr -l $min_log_level \ 24 | -d $capacity 25 | -------------------------------------------------------------------------------- /WebServer/src/client/ftp_client.cc: -------------------------------------------------------------------------------- 1 | // @Author: Lawson 2 | // @CreateDate: 2022/05/06 3 | // @LastModifiedDate: 2022/05/06 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | 18 | #include "utility/socket_utils.h" 19 | 20 | using namespace std; 21 | 22 | #define MAXSIZE 1024 23 | #define IPADDRESS "127.0.0.1" 24 | #define SERV_PORT 4242 25 | #define FDSIZE 1024 26 | #define EPOLLEVENTS 20 27 | 28 | #define DEBUG_FTPCLIENT 29 | 30 | 31 | int main(int argc, char* argv[]) { 32 | std::cout << "it's FTPClient!" << std::endl; 33 | char buff[4096]; 34 | buff[0] = '\0'; 35 | 36 | int sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 37 | if(sockfd == -1) { 38 | cout << "create socket error!\n"; 39 | return 0; 40 | } 41 | 42 | // setSocketNonBlocking(sockfd); 43 | struct sockaddr_in serverAddr; 44 | bzero(&serverAddr, sizeof(sockaddr_in)); 45 | serverAddr.sin_family = AF_INET; 46 | serverAddr.sin_port = htons(SERV_PORT); 47 | inet_pton(AF_INET, IPADDRESS, &serverAddr.sin_addr); 48 | 49 | std::string user_name, user_password; 50 | std::string msg; 51 | 52 | #ifndef DEBUG_FTPCLIENT 53 | std::cout<<"please input your user name and password seperated by space.\n"; 54 | std::cin >> user_name >> user_password; 55 | #else 56 | user_name = "admin"; 57 | user_password = "123456"; 58 | #endif 59 | 60 | msg = "%" + user_name + "%" + user_password; 61 | 62 | if(connect(sockfd, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) == -1) { 63 | std::cout << "connect to server failed!" << std::endl; 64 | return 0; 65 | } 66 | utility::SetSocketNonBlocking(sockfd); 67 | 68 | #ifdef DEBUG_FTPCLIENT 69 | cout << "send userInfo now" << std::endl; 70 | #endif 71 | sleep(1); 72 | write(sockfd, msg.c_str(), msg.size()); 73 | 74 | #ifdef DEBUG_FTPCLIENT 75 | cout << "the msg send to server is: " << msg << std::endl; 76 | // cout << "the msg.c_str() send to server is: " << msg.c_str() << std::endl; 77 | #endif 78 | sleep(1); 79 | read(sockfd, buff, sizeof(buff)); 80 | msg = buff; 81 | 82 | #ifdef DEBUG_FTPCLIENT 83 | // cout << "the msg receive from server is: " << msg << std::endl; 84 | #endif 85 | 86 | if(msg.find("correct") == std::string::npos) { 87 | std::cout << "your user name or password is incorrect." << std::endl; 88 | return 0; 89 | } 90 | 91 | #ifdef DEBUG_FTPCLIENT 92 | 93 | std::string cmd; 94 | bool zero = false; 95 | utility::Read(sockfd, msg, zero); 96 | std::cout << "msg1 is: " << msg << std::endl; 97 | while(true) { 98 | std::cout << "enter your cmd: " << std::endl; 99 | getline(std::cin, cmd); 100 | utility::Write(sockfd, cmd); 101 | msg.clear(); 102 | ssize_t readSum = utility::Read(sockfd, msg, zero); 103 | if(readSum < 0 || zero) { 104 | break; 105 | } 106 | std::cout << "msg2 is: " << msg << std::endl; 107 | 108 | } 109 | 110 | cout << "FTPClient close" << endl; 111 | #endif 112 | } -------------------------------------------------------------------------------- /WebServer/src/client/http_client.cc: -------------------------------------------------------------------------------- 1 | // @Author: Lawson 2 | // @CreateDate: 2022/04/10 3 | // @LastModifiedDate: 2022/04/10 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | 18 | using namespace std; 19 | 20 | #define MAXSIZE 1024 21 | #define IPADDRESS "127.0.0.1" 22 | #define SERV_PORT 8888 23 | #define FDSIZE 1024 24 | #define EPOLLEVENTS 20 25 | 26 | int setSocketNonBlocking(int fd) { 27 | int flag = fcntl(fd, F_GETFL); 28 | if(flag == -1) { 29 | return -1; 30 | } 31 | 32 | flag |= O_NONBLOCK; 33 | if(fcntl(fd, F_SETFL, flag) == -1) { 34 | return -1; 35 | } 36 | 37 | return 0; 38 | } 39 | 40 | int main(int argc, char* argv[]) { 41 | // cout << "creating socket..." << endl; 42 | int sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 43 | if(sockfd == -1) { 44 | perror("create socket error!\n"); 45 | return 0; 46 | } 47 | struct sockaddr_in servaddr; 48 | bzero(&servaddr, sizeof(servaddr)); 49 | servaddr.sin_family = AF_INET; 50 | servaddr.sin_port = htons(SERV_PORT); 51 | inet_pton(AF_INET, IPADDRESS, &servaddr.sin_addr); 52 | char buff[4096]; 53 | buff[0] = '\0'; 54 | cout << "-------------------" << endl; 55 | const char* p; 56 | ssize_t n; 57 | // 发送空串 58 | p = " \r\n"; 59 | if(connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1) { 60 | perror("connect to server failed!"); 61 | return 0; 62 | } 63 | setSocketNonBlocking(sockfd); 64 | cout << "test1: " << endl; 65 | n = write(sockfd, p, strlen(p)); 66 | cout << "strlen(p) = " << strlen(p) << endl; 67 | sleep(1); 68 | n = read(sockfd, buff, sizeof(buff)); 69 | cout << "n = " << n << endl; 70 | cout << buff << endl; 71 | close(sockfd); 72 | sleep(1); 73 | 74 | // // 发"GET /page.jpg HTTP/1.1" 75 | // p = "GET /page.jpg HTTP/1.1\r\nHost: 192.168.52.135\r\n\r\n"; 76 | // sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 77 | // if(sockfd == -1) { 78 | // perror("create socket error"); 79 | // return 0; 80 | // } 81 | // if(connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1) { 82 | // perror("connect to server failed"); 83 | // return 0; 84 | // } 85 | // setSocketNonBlocking(sockfd); 86 | // cout << "test2: " << endl; 87 | // n = write(sockfd, p, strlen(p)); 88 | // cout << "strlen(p) = " << strlen(p) << endl; 89 | // sleep(1); 90 | // n = read(sockfd, buff, sizeof(buff)); 91 | // cout << "n = " << n << endl; 92 | // cout << buff << endl; 93 | // close(sockfd); 94 | // sleep(1); 95 | 96 | // 发 97 | // GET /index.html HTTP/1.1 98 | // Host: 192.168.52.135:8888 99 | // Content-Type: application/x-www-form-urlencoded 100 | // Connection: Keep-Alive 101 | for(int i = 0; i < 3; ++i) { 102 | p = "GET /index.html HTTP/1.1\r\nHost: 192.168.52.135\r\nContent-Type: application/x-www-form-urlencoded\r\nConnection: Keep-Alive\r\n\r\n"; 103 | sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 104 | if(sockfd == -1) { 105 | perror("create socket error"); 106 | return 0; 107 | } 108 | if(connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1) { 109 | perror("connect to server failed"); 110 | return 0; 111 | } 112 | setSocketNonBlocking(sockfd); 113 | cout << "test3: " << endl; 114 | n = write(sockfd, p, strlen(p)); 115 | cout << "strlen(p) = " << strlen(p) << endl; 116 | sleep(1); 117 | n = read(sockfd, buff, sizeof(buff)); 118 | cout << "n = " << n << endl; 119 | cout << buff << endl; 120 | close(sockfd); 121 | sleep(1); 122 | } 123 | 124 | 125 | return 0; 126 | } 127 | -------------------------------------------------------------------------------- /WebServer/src/event/channel.cpp: -------------------------------------------------------------------------------- 1 | #include "event/channel.h" 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | #include "event/poller.h" 10 | #include "event/event_loop.h" 11 | 12 | namespace event { 13 | 14 | Channel::Channel() { 15 | fd_ = 0; 16 | events_ = 0; 17 | last_events_ = 0; 18 | } 19 | 20 | Channel::Channel(int fd) { 21 | fd_ = fd; 22 | events_ = 0; 23 | last_events_ = 0; 24 | } 25 | 26 | Channel::~Channel() {} 27 | 28 | // IO事件的回调函数 EventLoop中调用Loop开始事件循环 会调用Poll得到就绪事件 29 | // 然后依次调用此函数处理就绪事件 30 | void Channel::HandleEvents() { 31 | events_ = 0; 32 | // 触发挂起事件 并且没触发可读事件 33 | if ((revents_ & EPOLLHUP) && !(revents_ & EPOLLIN)) { 34 | events_ = 0; 35 | return; 36 | } 37 | // 触发错误事件 38 | if (revents_ & EPOLLERR) { 39 | HandleError(); 40 | events_ = 0; 41 | return; 42 | } 43 | // 触发可读事件 | 高优先级可读 | 对端(客户端)关闭连接 44 | if (revents_ & (EPOLLIN | EPOLLPRI | EPOLLRDHUP)) { 45 | HandleRead(); 46 | } 47 | // 触发可写事件 48 | if (revents_ & EPOLLOUT) { 49 | HandleWrite(); 50 | } 51 | 52 | //处理更新监听事件(EpollMod) 53 | HandleUpdate(); 54 | } 55 | 56 | //处理读事件的回调函数 57 | void Channel::HandleRead() { 58 | if (read_handler_) { 59 | read_handler_(); 60 | } 61 | } 62 | 63 | //处理写事件的回调函数 64 | void Channel::HandleWrite() { 65 | if (write_handler_) { 66 | write_handler_(); 67 | } 68 | } 69 | 70 | //处理更新事件的回调 71 | void Channel::HandleUpdate() { 72 | if (update_handler_) { 73 | update_handler_(); 74 | } 75 | } 76 | 77 | //处理错误事件的回调函数 78 | void Channel::HandleError() { 79 | if (error_handler_) { 80 | error_handler_(); 81 | } 82 | } 83 | 84 | } // namespace event -------------------------------------------------------------------------------- /WebServer/src/event/event_loop_thread.cpp: -------------------------------------------------------------------------------- 1 | #include "event/event_loop_thread.h" 2 | 3 | namespace event { 4 | 5 | //IO线程,绑定线程函数,也就是Loop 6 | EventLoopThread::EventLoopThread() 7 | : sub_loop_(NULL), 8 | is_exiting_(false), 9 | mutex_(), 10 | condition_(mutex_), 11 | thread_(std::bind(&EventLoopThread::Worker, this), "EventLoopThread") { 12 | } 13 | 14 | EventLoopThread::~EventLoopThread() { 15 | //停止loop后 线程join等待停止loop运行完 16 | is_exiting_ = true; 17 | if (sub_loop_ != NULL) { 18 | sub_loop_->StopLoop(); 19 | thread_.Join(); 20 | } 21 | } 22 | 23 | // 执行线程函数, 在线程函数还没运行起来的时候 一直阻塞 运行起来了才唤醒返回该event_loop 24 | EventLoop* EventLoopThread::StartLoop() { 25 | assert(!thread_.is_started()); 26 | //执行线程函数 27 | thread_.Start(); 28 | { 29 | locker::LockGuard lock(mutex_); 30 | // 一直阻塞等到线程函数运行起来 再唤醒返回 31 | while (sub_loop_ == NULL) { 32 | condition_.wait(); 33 | } 34 | } 35 | 36 | return sub_loop_; 37 | } 38 | 39 | // 线程函数(内部先唤醒StartLoop, 然后调用Loop事件循环) 40 | void EventLoopThread::Worker() { 41 | EventLoop event_loop; 42 | { 43 | locker::LockGuard lock(mutex_); 44 | sub_loop_ = &event_loop; 45 | // 已经运行线程函数了 唤醒StartLoop返回此event_loop对象 46 | condition_.notify(); 47 | } 48 | 49 | // Loop事件循环 50 | event_loop.Loop(); 51 | sub_loop_ = NULL; 52 | } 53 | 54 | } // namespace event 55 | -------------------------------------------------------------------------------- /WebServer/src/event/event_loop_thread_pool.cpp: -------------------------------------------------------------------------------- 1 | #include "event/event_loop_thread_pool.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "log/logging.h" 8 | 9 | namespace event { 10 | // IO线程池 11 | EventLoopThreadPool::EventLoopThreadPool(EventLoop* main_loop, int thread_num) 12 | : main_loop_(main_loop), 13 | thread_num_(thread_num), 14 | is_started_(false), 15 | next_(0) { 16 | if (thread_num_ <= 0) { 17 | LOG(FATAL) << "thread num <= 0"; 18 | } 19 | sub_loop_threads_.reserve(thread_num_); 20 | sub_loops_.reserve(thread_num_); 21 | } 22 | 23 | EventLoopThreadPool::~EventLoopThreadPool() { 24 | LOG(DEBUG) << "~EventLoopThreadPool()"; 25 | } 26 | 27 | // 主线程(主Loop对象)创建event_loop线程池 28 | void EventLoopThreadPool::Start() { 29 | assert(main_loop_->is_in_loop_thread()); 30 | is_started_ = true; 31 | 32 | // 创建event_loop_thread_pool,并将开始Loop事件循环的EventLoop对象存入array中 33 | for (int i = 0; i < thread_num_; ++i) { 34 | auto event_loop_thread = std::make_shared(); 35 | sub_loop_threads_.push_back(event_loop_thread); 36 | sub_loops_.push_back(event_loop_thread->StartLoop()); 37 | } 38 | } 39 | 40 | // 从已经开始Loop事件循环的EventLoop对象列表中 返回一个EventLoop对象 如果此时还没有 就返回主loop 41 | EventLoop* EventLoopThreadPool::GetNextLoop() { 42 | // 调用这个函数的必须是主loop线程 43 | assert(main_loop_->is_in_loop_thread()); 44 | assert(is_started_); 45 | 46 | // 如果此时还没有开始Loop的EventLoop对象 就返回主loop 47 | auto event_loop = main_loop_; 48 | if (!sub_loops_.empty()) { 49 | event_loop = sub_loops_[next_]; 50 | next_ = (next_ + 1) % thread_num_; 51 | } 52 | 53 | return event_loop; 54 | } 55 | 56 | } // namespace event 57 | -------------------------------------------------------------------------------- /WebServer/src/log/log_stream.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "log/log_stream.h" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | namespace log { 13 | //定义小BufferSize和大BufferSize的固定缓冲区类 14 | template class FixedBuffer; 15 | template class FixedBuffer; 16 | 17 | //用于format int 18 | static const char digits[] = "9876543210123456789"; 19 | static const char* zero = digits + 9; 20 | 21 | template 22 | static size_t IntToString(char buffer[], T number) { 23 | char* buf = buffer; 24 | 25 | //从数字的个位开始 去每个字 将其转成char 26 | do { 27 | int index = static_cast(number % 10); 28 | number /= 10; 29 | *buf++ = zero[index]; 30 | } while (number != 0); 31 | 32 | //如果这个值是负数 就加上-号 33 | if (number < 0) { 34 | *buf++ = '-'; 35 | } 36 | *buf = '\0'; 37 | //前面是从个位开始往上算的 ,这里要反转过来(begin, end) 38 | std::reverse(buffer, buf); 39 | 40 | return buf - buffer; 41 | } 42 | 43 | //格式化int类型 44 | template 45 | void LogStream::FormatInt(T number) { 46 | // buffer容不下kMaxNumericSize个字符的话会被直接丢弃 47 | if (buffer_.capacity() >= kMaxNumberSize) { 48 | size_t size = IntToString(buffer_.current_buffer(), number); 49 | buffer_.add(size); 50 | } 51 | } 52 | 53 | //重载输出流运算符 bool型 54 | LogStream& LogStream::operator<<(bool express) { 55 | Write(express ? "1" : "0", 1); 56 | return *this; 57 | } 58 | 59 | //重载输出流运算符 整形 60 | LogStream& LogStream::operator<<(short number) { 61 | *this << static_cast(number); 62 | return *this; 63 | } 64 | 65 | LogStream& LogStream::operator<<(unsigned short number) { 66 | *this << static_cast(number); 67 | return *this; 68 | } 69 | 70 | LogStream& LogStream::operator<<(int number) { 71 | FormatInt(number); 72 | return *this; 73 | } 74 | 75 | LogStream& LogStream::operator<<(unsigned int number) { 76 | FormatInt(number); 77 | return *this; 78 | } 79 | 80 | LogStream& LogStream::operator<<(long number) { 81 | FormatInt(number); 82 | return *this; 83 | } 84 | 85 | LogStream& LogStream::operator<<(unsigned long number) { 86 | FormatInt(number); 87 | return *this; 88 | } 89 | 90 | LogStream& LogStream::operator<<(long long number) { 91 | FormatInt(number); 92 | return *this; 93 | } 94 | 95 | LogStream& LogStream::operator<<(unsigned long long number) { 96 | FormatInt(number); 97 | return *this; 98 | } 99 | 100 | LogStream& LogStream::operator<<(float number) { 101 | *this << static_cast(number); 102 | return *this; 103 | } 104 | 105 | LogStream& LogStream::operator<<(double number) { 106 | if (buffer_.capacity() >= kMaxNumberSize) { 107 | int size = snprintf(buffer_.current_buffer(), kMaxNumberSize, "%.12g", number); 108 | buffer_.add(size); 109 | } 110 | return *this; 111 | } 112 | 113 | LogStream& LogStream::operator<<(long double number) { 114 | if (buffer_.capacity() >= kMaxNumberSize) { 115 | int size = snprintf(buffer_.current_buffer(), kMaxNumberSize, "%.12Lg", number); 116 | buffer_.add(size); 117 | } 118 | return *this; 119 | } 120 | 121 | //重载输出流运算符 字符串 122 | LogStream& LogStream::operator<<(char str) { 123 | Write(&str, 1); 124 | return *this; 125 | } 126 | 127 | LogStream& LogStream::operator<<(const char* str) { 128 | if (str) { 129 | Write(str, strlen(str)); 130 | } else { 131 | Write("(null)", 6); 132 | } 133 | return *this; 134 | } 135 | 136 | LogStream& LogStream::operator<<(const unsigned char* str) { 137 | return operator<<(reinterpret_cast(str)); 138 | } 139 | 140 | LogStream& LogStream::operator<<(const std::string& str) { 141 | Write(str.c_str(), str.size()); 142 | return *this; 143 | } 144 | 145 | } // namespace log -------------------------------------------------------------------------------- /WebServer/src/manager/file_manager.cc: -------------------------------------------------------------------------------- 1 | #include "manager/file_manager.h" 2 | #include "log/logging.h" 3 | 4 | #define DEBUG_FILEMANAGER 5 | 6 | namespace manager 7 | { 8 | 9 | std::vector FileManager::fileList_; 10 | locker::MutexLock FileManager::mutex_; 11 | FileManager::fileManagerPtr FileManager::instance_ = nullptr; 12 | 13 | FileManager::FileManager() { 14 | std::string filePath(getcwd(NULL, 0)); 15 | if(filePath.empty()) { 16 | LOG(DEBUG) << "get filePath failed"; 17 | exit(0); 18 | } 19 | DIR* curDir = opendir(filePath.c_str()); 20 | if(curDir == nullptr) { 21 | LOG(DEBUG) << "get filePath failed"; 22 | exit(0); 23 | } 24 | 25 | auto dirPtr = readdir(curDir); 26 | while(dirPtr != nullptr) { 27 | if(dirPtr->d_type == DT_REG) 28 | fileList_.emplace_back(dirPtr->d_name); 29 | dirPtr = readdir(curDir); 30 | } 31 | closedir(curDir); 32 | 33 | #ifdef DEBUG_FILEMANAGER 34 | std::cout << "fileList is: " << std::endl; 35 | for(const std::string& file : fileList_) { 36 | std::cout<< file << " "; 37 | } 38 | std::cout << std::endl; 39 | #endif 40 | } 41 | 42 | FileManager::~FileManager() {} 43 | 44 | FileManager::fileManagerPtr FileManager::getFileManager() { 45 | { 46 | locker::LockGuard lock(mutex_); 47 | if(instance_ == nullptr) 48 | instance_ = fileManagerPtr(new FileManager()); 49 | } 50 | return instance_; 51 | } 52 | 53 | } // namespace manager 54 | 55 | 56 | -------------------------------------------------------------------------------- /WebServer/src/manager/user_manager.cc: -------------------------------------------------------------------------------- 1 | #include "manager/user_manager.h" 2 | 3 | #include "log/logging.h" 4 | 5 | // #define DEBUG 6 | 7 | namespace manager 8 | { 9 | 10 | std::unordered_map UserManager::userInfo_; 11 | UserManager::userManagerPtr UserManager::instance_ = nullptr; 12 | locker::MutexLock UserManager::mutex_; 13 | 14 | UserManager::UserManager(std::string userInfoFile) { 15 | std::ifstream infile(userInfoFile); 16 | if(!infile.is_open()) { 17 | LOG(WARNING) << "open file userInfoFile failed"; 18 | exit(0); 19 | } 20 | char name[255]; 21 | char psw[255]; 22 | while(infile) { 23 | bzero(name, 255); 24 | bzero(psw, 255); 25 | infile.getline(name, 255); 26 | infile.getline(psw, 255); 27 | userInfo_[name] = psw; 28 | } 29 | #ifdef DEBUG 30 | LOG(DEBUG) << "load userInfoFile successfully"; 31 | #endif 32 | } 33 | 34 | UserManager::~UserManager() {} 35 | 36 | UserManager::userManagerPtr UserManager::getUserManger(std::string userInfoFile) { 37 | { 38 | locker::LockGuard lock(mutex_); 39 | if(instance_ == nullptr) { 40 | // instance_ = userManagerPtr(newElement(userInfoFile), deleteElement); 41 | instance_ = userManagerPtr(new UserManager(userInfoFile)); 42 | } 43 | } 44 | return instance_; 45 | } 46 | 47 | bool UserManager::login(std::string name, std::string psw) { 48 | if(userInfo_.find(name) != userInfo_.end()) { 49 | return userInfo_[name] == psw; 50 | } 51 | 52 | return false; 53 | } 54 | 55 | } // namespace manager 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /WebServer/src/memory/memory_pool.cpp: -------------------------------------------------------------------------------- 1 | #include "memory/memory_pool.h" 2 | #include 3 | 4 | namespace memoryPool 5 | { 6 | 7 | // template 8 | MemoryPool::MemoryPool() {} 9 | 10 | // template 11 | MemoryPool::~MemoryPool() { 12 | Slot* cur = currentBolck_; 13 | while(cur) { 14 | Slot* next = cur->next; 15 | // free(reinterpret_cast(cur)); 16 | // 转化为 void 指针,是因为 void 类型不需要调用析构函数,只释放空间 17 | operator delete(reinterpret_cast(cur)); 18 | cur = next; 19 | } 20 | } 21 | 22 | // template 23 | void MemoryPool::init(int size) { 24 | assert(size > 0); 25 | slotSize_ = size; 26 | currentBolck_ = NULL; 27 | currentSlot_ = NULL; 28 | lastSlot_ = NULL; 29 | freeSlot_ = NULL; 30 | } 31 | 32 | // 计算对齐所需补的空间 33 | // template 34 | inline size_t MemoryPool::padPointer(char* p, size_t align) { 35 | size_t result = reinterpret_cast(p); 36 | return ((align - result) % align); 37 | } 38 | 39 | // template 40 | Slot* MemoryPool::allocateBlock() { 41 | char* newBlock = reinterpret_cast(operator new(BlockSize)); 42 | 43 | char* body = newBlock + sizeof(Slot*); 44 | // 计算为了对齐需要空出多少位置 45 | // size_t bodyPadding = padPointer(body, sizeof(slotSize_)); 46 | size_t bodyPadding = padPointer(body, static_cast(slotSize_)); 47 | 48 | // 注意:多个线程(eventLoop共用一个MemoryPool) 49 | Slot* useSlot; 50 | { 51 | locker::LockGuard lock(mutex_other_); 52 | // newBlock接到Block链表的头部 53 | reinterpret_cast(newBlock)->next = currentBolck_; 54 | currentBolck_ = reinterpret_cast(newBlock); 55 | // 为该Block开始的地方加上bodyPadding个char* 空间 56 | currentSlot_ = reinterpret_cast(body + bodyPadding); 57 | lastSlot_ = reinterpret_cast(newBlock + BlockSize - slotSize_ + 1); 58 | useSlot = currentSlot_; 59 | 60 | // slot指针一次移动8个字节 61 | currentSlot_ += (slotSize_ >> 3); 62 | // currentSlot_ += slotSize_; 63 | } 64 | 65 | return useSlot; 66 | } 67 | 68 | // template 69 | Slot* MemoryPool::nofree_solve() { 70 | if(currentSlot_ >= lastSlot_) 71 | return allocateBlock(); 72 | Slot* useSlot; 73 | { 74 | locker::LockGuard lock(mutex_other_); 75 | useSlot = currentSlot_; 76 | currentSlot_ += (slotSize_ >> 3); 77 | } 78 | 79 | return useSlot; 80 | } 81 | 82 | 83 | Slot* MemoryPool::allocate() { 84 | if(freeSlot_) { 85 | { 86 | locker::LockGuard lock(mutex_freeSlot_); 87 | if(freeSlot_) { 88 | Slot* result = freeSlot_; 89 | freeSlot_ = freeSlot_->next; 90 | return result; 91 | } 92 | } 93 | } 94 | 95 | return nofree_solve(); 96 | } 97 | 98 | // template 99 | inline void MemoryPool::deAllocate(Slot* p) { 100 | if(p) { 101 | // 将slot加入释放队列 102 | locker::LockGuard lock(mutex_freeSlot_); 103 | p->next = freeSlot_; 104 | freeSlot_ = p; 105 | } 106 | } 107 | 108 | // template 109 | MemoryPool& get_MemoryPool(int id) { 110 | static MemoryPool memorypool_[64]; 111 | return memorypool_[id]; 112 | } 113 | 114 | // 数组中分别存放Slot大小为8,16,...,512字节的BLock链表 115 | void init_MemoryPool() { 116 | for(int i = 0; i < 64; ++i) { 117 | get_MemoryPool(i).init((i + 1) << 3); 118 | } 119 | } 120 | 121 | // 超过512字节就直接new 122 | void* use_Memory(size_t size) { 123 | if(!size) 124 | return nullptr; 125 | if(size > 512) 126 | return operator new(size); 127 | 128 | // 相当于(size / 8)向上取整 129 | return reinterpret_cast(get_MemoryPool(((size + 7) >> 3) - 1).allocate()); 130 | } 131 | 132 | void free_Memory(size_t size, void* p) { 133 | if(!p) return; 134 | if(size > 512) { 135 | operator delete (p); 136 | return; 137 | } 138 | get_MemoryPool(((size + 7) >> 3) - 1).deAllocate(reinterpret_cast(p)); 139 | } 140 | 141 | } // namespace memoryPool 142 | 143 | 144 | -------------------------------------------------------------------------------- /WebServer/src/thread/thread.cpp: -------------------------------------------------------------------------------- 1 | #include "thread/thread.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | namespace current_thread { 13 | // TLS 14 | __thread int tls_thread_id = 0; //线程id 15 | __thread const char* tls_thread_name = "default"; //线程名字 16 | } // namespace current_thread 17 | 18 | namespace thread { 19 | // Thread类 20 | Thread::Thread(const Worker& worker, const std::string& thread_name) 21 | : worker_(worker), 22 | pthread_id_(0), 23 | thread_id_(0), 24 | thread_name_(thread_name), 25 | is_started_(false), 26 | is_joined_(false) { 27 | if (thread_name_.empty()) { 28 | thread_name_ = "Thread"; 29 | } 30 | } 31 | 32 | Thread::~Thread() { 33 | //如果线程已经开始 但是没有join 就detach线程 34 | if (is_started_ && !is_joined_) { 35 | pthread_detach(pthread_id_); 36 | } 37 | } 38 | 39 | //开始线程 调用Run Run会调用ThreadData的Run函数 执行worker线程函数 40 | void Thread::Start() { 41 | assert(!is_started_); 42 | is_started_ = true; 43 | 44 | //创建线程并执行线程函数 45 | if (pthread_create(&pthread_id_, NULL, &Run, this) != 0) { 46 | is_started_ = false; 47 | } 48 | } 49 | 50 | //join线程 51 | int Thread::Join() { 52 | assert(is_started_); 53 | assert(!is_joined_); 54 | is_joined_ = true; 55 | 56 | return pthread_join(pthread_id_, NULL); 57 | } 58 | 59 | // 调用ThreadData的Run函数 执行worker线程函数 60 | void* Thread::Run(void* arg) { 61 | Thread* thread = static_cast(arg); 62 | thread->Run(); 63 | 64 | return NULL; 65 | } 66 | 67 | void Thread::Run() { 68 | //赋值线程id 69 | thread_id_ = current_thread::thread_id(); 70 | //设置线程名 71 | current_thread::tls_thread_name = thread_name_.empty() ? "Thread" : thread_name_.c_str(); 72 | prctl(PR_SET_NAME, current_thread::tls_thread_name); 73 | 74 | //执行线程函数 75 | worker_(); 76 | current_thread::tls_thread_name = "finished"; 77 | } 78 | 79 | } // namespace thread 80 | -------------------------------------------------------------------------------- /WebServer/src/thread/worker_thread_pool.cpp: -------------------------------------------------------------------------------- 1 | #include "thread/worker_thread_pool.h" 2 | #include "thread/block_queue.hpp" 3 | 4 | namespace thread { 5 | WorkerThreadPool::WorkerThreadPool(int thread_num) 6 | : pthreads_id_(NULL), 7 | thread_num_(thread_num) { 8 | if (thread_num <= 0) { 9 | exit(1); 10 | } 11 | // 线程id初始化 12 | pthreads_id_ = new pthread_t[thread_num_]; 13 | if (!pthreads_id_) { 14 | exit(1); 15 | } 16 | 17 | for (int i = 0; i < thread_num; ++i) { 18 | // 创建线程 tid,线程属性attr,线程函数入口func,线程函数参数arg 19 | if (pthread_create(pthreads_id_ + i, NULL, Worker, this) != 0) { 20 | delete[] pthreads_id_; 21 | exit(1); 22 | } 23 | // 分离线程 后面不用再对线程进行回收 24 | if (pthread_detach(pthreads_id_[i])) { 25 | delete[] pthreads_id_; 26 | exit(1); 27 | } 28 | } 29 | } 30 | 31 | // 释放线程池 32 | WorkerThreadPool::~WorkerThreadPool() { 33 | delete[] pthreads_id_; 34 | } 35 | 36 | // 线程处理函数 37 | void* WorkerThreadPool::Worker(void* arg) { 38 | WorkerThreadPool* thread_pool = (WorkerThreadPool*)arg; 39 | thread_pool->Run(); 40 | 41 | return NULL; 42 | } 43 | 44 | // 执行任务 45 | void WorkerThreadPool::Run() { 46 | while (true) { 47 | auto channels = SingletonBlockQueue::GetInstance()->Pop(); 48 | for (auto channel : channels) { 49 | //处理每个就绪事件(不同channel绑定了不同的callback) 50 | if (channel) { 51 | channel->HandleEvents(); 52 | } 53 | } 54 | } 55 | } 56 | 57 | } // namespace thread 58 | -------------------------------------------------------------------------------- /WebServer/src/timer/timer.cpp: -------------------------------------------------------------------------------- 1 | #include "timer/timer.h" 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | #include "http/http_connection.h" 10 | #include "log/logging.h" 11 | 12 | namespace timer { 13 | 14 | Timer::Timer(std::shared_ptr http_connection, int timeout) 15 | : http_connection_(http_connection), 16 | is_deleted_(false) { 17 | // 以毫秒计算 到期时间 = 当前时间(秒余到10000以内换算成毫秒 + 微妙换算成毫秒) + 超时时间(毫秒) 18 | struct timeval now; 19 | gettimeofday(&now, NULL); 20 | expire_time_ = (((now.tv_sec % 10000) * 1000) + (now.tv_usec / 1000)) + timeout; 21 | } 22 | 23 | // 拷贝构造函数 24 | Timer::Timer(Timer& timer) 25 | : http_connection_(timer.http_connection_), 26 | expire_time_(0) { 27 | } 28 | 29 | // 定时器析构时 (如果是因重新绑定新定时器而将此旧定时器删除的情况,http对象reset,所以不会调用Delete) 30 | // 如果是因为超时而将此定时器删除的情况 就会调用http的Delete(EpollDel, close(fd)) 31 | Timer::~Timer() { 32 | if (http_connection_) { 33 | LOG(INFO) << "Timeout, close sockfd: " << http_connection_->connect_fd(); 34 | http_connection_->Delete(); 35 | } 36 | } 37 | 38 | // 更新到期时间 = 当前时间 + 超时时间 39 | void Timer::Update(int timeout) { 40 | struct timeval now; 41 | gettimeofday(&now, NULL); 42 | expire_time_ = (((now.tv_sec % 10000) * 1000) + (now.tv_usec / 1000)) + timeout; 43 | } 44 | 45 | // 是否到期 46 | bool Timer::is_expired() { 47 | struct timeval now; 48 | gettimeofday(&now, NULL); 49 | size_t current_time = (((now.tv_sec % 10000) * 1000) + (now.tv_usec / 1000)); 50 | if (current_time >= expire_time_) { 51 | is_deleted_ = true; 52 | return true; 53 | } 54 | 55 | return false; 56 | } 57 | 58 | // 释放http 59 | void Timer::Release() { 60 | http_connection_.reset(); 61 | is_deleted_ = true; 62 | } 63 | 64 | } // namespace timer 65 | -------------------------------------------------------------------------------- /WebServer/src/timer/timer_heap.cpp: -------------------------------------------------------------------------------- 1 | #include "timer/timer_heap.h" 2 | 3 | #include 4 | 5 | #include "http/http_connection.h" 6 | 7 | namespace timer { 8 | //向小根堆中添加定时器 9 | void TimerHeap::AddTimer(std::shared_ptr http_connection, int timeout) { 10 | //new一个定时器 加上到小根堆中 11 | auto timer = std::make_shared(http_connection, timeout); 12 | timer_heap_.push(timer); 13 | http_connection->set_timer(timer); 14 | } 15 | 16 | // 处理到期事件 如果定时器被删除或者已经到期 就从小根堆中删除 17 | // 定时器析构的时候 会调用http->close 会关闭http连接,EpollDel绑定的connect_fd 18 | void TimerHeap::HandleExpireEvent() { 19 | while (!timer_heap_.empty()) { 20 | auto timer = timer_heap_.top(); 21 | // 如果是被删除了(惰性删除 已经到期了但是还没被访问所以没被删) 或者到期了都会pop定时器 22 | if (timer->is_deleted() || timer->is_expired()) { 23 | timer_heap_.pop(); 24 | } else { 25 | break; 26 | } 27 | } 28 | } 29 | 30 | } // namespace timer 31 | -------------------------------------------------------------------------------- /img/短连接测试.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Liluoquan/a-high-concurrency-webserver-in-linux/fb360a54709082cff606b8e52a65738bacc7440e/img/短连接测试.jpg -------------------------------------------------------------------------------- /img/长连接测试.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Liluoquan/a-high-concurrency-webserver-in-linux/fb360a54709082cff606b8e52a65738bacc7440e/img/长连接测试.jpg --------------------------------------------------------------------------------