From 3b2bf691f0ae8cd7fe3722f6d1f232089d889d7e Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 29 Nov 2023 15:21:35 +0800 Subject: [PATCH 1/3] The default buffer size of a socket should not be hardcoded in the program; it should be configurable. Additionally, in Linux, adjusting kernel parameters can be more effective in improving the performance or throughput of a program in scenarios such as high-latency "long fat networks" or high-concurrency situations, compared to using setsockopt. --- CMakeLists.txt | 8 +++++++- src/Network/Socket.cpp | 1 + src/Network/Socket.h | 13 +++++++------ src/Network/sockutil.cpp | 7 +++++++ src/Network/sockutil.h | 16 +++++++++++++++- 5 files changed, 37 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ba4b1b7d8..8be35a6d8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,13 @@ list(APPEND CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE) check_struct_has_member("struct mmsghdr" msg_hdr sys/socket.h HAVE_MMSG_HDR) check_symbol_exists(sendmmsg sys/socket.h HAVE_SENDMMSG_API) check_symbol_exists(recvmmsg sys/socket.h HAVE_RECVMMSG_API) - +# check the socket buffer size set by the upper cmake project, if it is set, use the setting of the upper cmake project, otherwise set it to 256K +# if the socket buffer size is set to 0, it means that the socket buffer size is not set, and the kernel default value is used(just for linux) +if(NOT DEFINED SOCKET_DEFAULT_BUFFER_SIZE) + add_definitions(-DSOCKET_DEFAULT_BUFFER_SIZE=262144) +else() + add_definitions(-DSOCKET_DEFAULT_BUFFER_SIZE=${SOCKET_DEFAULT_BUFFER_SIZE}) +endif() if(HAVE_MMSG_HDR) add_definitions(-DHAVE_MMSG_HDR) endif() diff --git a/src/Network/Socket.cpp b/src/Network/Socket.cpp index cb47b2492..bb8afc06c 100644 --- a/src/Network/Socket.cpp +++ b/src/Network/Socket.cpp @@ -31,6 +31,7 @@ static SockException toSockException(int error) { case UV_EAGAIN: return SockException(Err_success, "success"); case UV_ECONNREFUSED: return SockException(Err_refused, uv_strerror(error), error); case UV_ETIMEDOUT: return SockException(Err_timeout, uv_strerror(error), error); + case UV_ECONNRESET: return SockException(Err_reset, uv_strerror(error), error); default: return SockException(Err_other, uv_strerror(error), error); } } diff --git a/src/Network/Socket.h b/src/Network/Socket.h index c071730b9..15d3d34d1 100644 --- a/src/Network/Socket.h +++ b/src/Network/Socket.h @@ -51,13 +51,14 @@ namespace toolkit { //错误类型枚举 typedef enum { - Err_success = 0, //成功 + Err_success = 0, //成功 success Err_eof, //eof - Err_timeout, //超时 - Err_refused,//连接被拒绝 - Err_dns,//dns解析失败 - Err_shutdown,//主动关闭 - Err_other = 0xFF,//其他错误 + Err_timeout, //超时 socket timeout + Err_refused,//连接被拒绝 socket refused + Err_reset,//连接被重置 socket reset + Err_dns,//dns解析失败 dns resolve failed + Err_shutdown,//主动关闭 socket shutdown + Err_other = 0xFF,//其他错误 other error } ErrCode; //错误信息类 diff --git a/src/Network/sockutil.cpp b/src/Network/sockutil.cpp index 3670665d1..27fa0ad3b 100644 --- a/src/Network/sockutil.cpp +++ b/src/Network/sockutil.cpp @@ -279,6 +279,10 @@ int SockUtil::setNoBlocked(int fd, bool noblock) { } int SockUtil::setRecvBuf(int fd, int size) { + if(size <= 0){ + // use the system default value + return 0; + } int ret = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *) &size, sizeof(size)); if (ret == -1) { TraceL << "setsockopt SO_RCVBUF failed"; @@ -287,6 +291,9 @@ int SockUtil::setRecvBuf(int fd, int size) { } int SockUtil::setSendBuf(int fd, int size) { + if(size <= 0){ + return 0; + } int ret = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (char *) &size, sizeof(size)); if (ret == -1) { TraceL << "setsockopt SO_SNDBUF failed"; diff --git a/src/Network/sockutil.h b/src/Network/sockutil.h index 9fb1b0f95..c01cb5e63 100644 --- a/src/Network/sockutil.h +++ b/src/Network/sockutil.h @@ -42,8 +42,22 @@ namespace toolkit { int ioctl(int fd, long cmd, u_long *ptr); int close(int fd); #endif // defined(_WIN32) - #define SOCKET_DEFAULT_BUF_SIZE (256 * 1024) +#if defined(SOCKET_DEFAULT_BUFFER_SIZE) + #if SOCKET_DEFAULT_BUFFER_SIZE == 0 + #if defined(__linux__) + // just for linux, because in some high-throughput environments, + // kernel control is more efficient and reasonable than program + // settings. For example, refer to cloudflare's blog + #undef SOCKET_DEFAULT_BUF_SIZE + #define SOCKET_DEFAULT_BUF_SIZE 0 + #endif + #else + #undef SOCKET_DEFAULT_BUF_SIZE + #define SOCKET_DEFAULT_BUF_SIZE SOCKET_DEFAULT_BUFFER_SIZE + #endif +#endif + #define TCP_KEEPALIVE_INTERVAL 30 #define TCP_KEEPALIVE_PROBE_TIMES 9 #define TCP_KEEPALIVE_TIME 120 From f758b3a9e29ab9794ebbba2a4009b108c8a01bc2 Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 29 Nov 2023 17:29:50 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E5=9B=A0=E4=B8=BA=E6=88=91=E8=87=AA?= =?UTF-8?q?=E5=B7=B1=E4=BD=BF=E7=94=A8=E8=BF=98=E6=9C=89=E5=85=B6=E4=BB=96?= =?UTF-8?q?=E9=80=BB=E8=BE=91=E6=89=80=E4=BB=A5=E5=A4=8D=E5=88=B6=E6=97=B6?= =?UTF-8?q?=E5=A4=A7=E6=84=8F=E4=BA=86,=E5=BF=98=E8=AE=B0=E7=B2=BE?= =?UTF-8?q?=E7=AE=80=E4=BA=86,=20=E7=8E=B0=E5=9C=A8=E7=B2=BE=E7=AE=80?= =?UTF-8?q?=E4=B8=8B=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 37 +++++++++++++++++++++++++++++-------- src/Network/sockutil.h | 24 ++++++++++-------------- 2 files changed, 39 insertions(+), 22 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8be35a6d8..42b244b27 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,13 +8,7 @@ list(APPEND CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE) check_struct_has_member("struct mmsghdr" msg_hdr sys/socket.h HAVE_MMSG_HDR) check_symbol_exists(sendmmsg sys/socket.h HAVE_SENDMMSG_API) check_symbol_exists(recvmmsg sys/socket.h HAVE_RECVMMSG_API) -# check the socket buffer size set by the upper cmake project, if it is set, use the setting of the upper cmake project, otherwise set it to 256K -# if the socket buffer size is set to 0, it means that the socket buffer size is not set, and the kernel default value is used(just for linux) -if(NOT DEFINED SOCKET_DEFAULT_BUFFER_SIZE) - add_definitions(-DSOCKET_DEFAULT_BUFFER_SIZE=262144) -else() - add_definitions(-DSOCKET_DEFAULT_BUFFER_SIZE=${SOCKET_DEFAULT_BUFFER_SIZE}) -endif() + if(HAVE_MMSG_HDR) add_definitions(-DHAVE_MMSG_HDR) endif() @@ -25,24 +19,39 @@ if(HAVE_RECVMMSG_API) add_definitions(-DHAVE_RECVMMSG_API) endif() - +# check the socket buffer size set by the upper cmake project, if it is set, use the setting of the upper cmake project, otherwise set it to 256K +# if the socket buffer size is set to 0, it means that the socket buffer size is not set, and the kernel default value is used(just for linux) +if(DEFINED SOCKET_DEFAULT_BUF_SIZE) + if (SOCKET_DEFAULT_BUF_SIZE EQUAL 0) + message(STATUS "Socket default buffer size is not set, use the kernel default value") + else() + message(STATUS "Socket default buffer size is set to ${SOCKET_DEFAULT_BUF_SIZE}") + endif () + add_definitions(-DSOCKET_DEFAULT_BUF_SIZE=${SOCKET_DEFAULT_BUF_SIZE}) +endif() #加载自定义模块 +#Load custom modules set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake") #设置库文件路径 +#Set the library file path set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib) #设置可执行程序路径 +#Set the executable program path set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) #设置子目录 +#Set subdirectories set(SUB_DIR_LIST "Network" "Poller" "Thread" "Util") if(WIN32) list(APPEND SUB_DIR_LIST "win32") #防止Windows.h包含Winsock.h + #Prevent Windows.h from including Winsock.h add_definitions(-DWIN32_LEAN_AND_MEAN) set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) endif() #安装目录 +#Installation directory if(WIN32) set(INSTALL_PATH_LIB $ENV{HOME}/${PROJECT_NAME}/lib) set(INSTALL_PATH_INCLUDE $ENV{HOME}/${PROJECT_NAME}/include) @@ -53,12 +62,15 @@ endif() foreach(SUB_DIR ${SUB_DIR_LIST}) #遍历源文件 + #Traverse source file aux_source_directory(src/${SUB_DIR} SRC_LIST) #安装头文件至系统目录 + #Install header file to system directory install(DIRECTORY src/${SUB_DIR} DESTINATION ${INSTALL_PATH_INCLUDE} FILES_MATCHING PATTERN "*.h") endforeach() #非苹果平台移除.mm类型的文件 +#Remove .mm type files from non-apple platforms if(NOT APPLE) list(REMOVE_ITEM SRC_LIST "src/Network/Socket_ios.mm") endif() @@ -75,6 +87,7 @@ set(ENABLE_MYSQL ON CACHE BOOL "enable mysql") #查找openssl是否安装 +#Find out if openssl is installed find_package(OpenSSL QUIET) if(OPENSSL_FOUND AND ENABLE_OPENSSL) message(STATUS "找到openssl库:\"${OPENSSL_INCLUDE_DIR}\",ENABLE_OPENSSL宏已打开") @@ -84,6 +97,7 @@ if(OPENSSL_FOUND AND ENABLE_OPENSSL) endif() #查找mysql是否安装 +#Find out if mysql is installed find_package(MYSQL QUIET) if(MYSQL_FOUND AND ENABLE_MYSQL) message(STATUS "找到mysqlclient库:\"${MYSQL_INCLUDE_DIR}\",ENABLE_MYSQL宏已打开") @@ -94,8 +108,10 @@ if(MYSQL_FOUND AND ENABLE_MYSQL) endif() #打印库文件 +#Print library files message(STATUS "将链接依赖库:${LINK_LIB_LIST}") #使能c++11 +#Enable c++11 set(CMAKE_CXX_STANDARD 11) if(NOT WIN32) @@ -104,6 +120,7 @@ if(NOT WIN32) endif() #编译动态库 +#Compile dynamic library if(NOT IOS AND NOT ANDROID AND NOT WIN32) add_library(${PROJECT_NAME}_shared SHARED ${SRC_LIST}) target_include_directories(${PROJECT_NAME}_shared PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src) @@ -113,15 +130,19 @@ if(NOT IOS AND NOT ANDROID AND NOT WIN32) endif() #编译静态库 +#Compile static library add_library(${PROJECT_NAME}_static STATIC ${SRC_LIST}) #引用头文件路径 +#Reference header file path target_include_directories(${PROJECT_NAME}_static PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src) set_target_properties(${PROJECT_NAME}_static PROPERTIES OUTPUT_NAME "${PROJECT_NAME}") #安装静态库至系统目录 +#Install static library to system directory install(TARGETS ${PROJECT_NAME}_static ARCHIVE DESTINATION ${INSTALL_PATH_LIB}) #测试程序 +#Test program if(NOT IOS) add_subdirectory(tests) endif() diff --git a/src/Network/sockutil.h b/src/Network/sockutil.h index c01cb5e63..9f7af5c1a 100644 --- a/src/Network/sockutil.h +++ b/src/Network/sockutil.h @@ -42,22 +42,18 @@ namespace toolkit { int ioctl(int fd, long cmd, u_long *ptr); int close(int fd); #endif // defined(_WIN32) + +#if !defined(SOCKET_DEFAULT_BUF_SIZE) +#define SOCKET_DEFAULT_BUF_SIZE (256 * 1024) +#else +#if SOCKET_DEFAULT_BUF_SIZE == 0 && !defined(__linux__) +// just for linux, because in some high-throughput environments, +// kernel control is more efficient and reasonable than program +// settings. For example, refer to cloudflare's blog +#undef SOCKET_DEFAULT_BUF_SIZE #define SOCKET_DEFAULT_BUF_SIZE (256 * 1024) -#if defined(SOCKET_DEFAULT_BUFFER_SIZE) - #if SOCKET_DEFAULT_BUFFER_SIZE == 0 - #if defined(__linux__) - // just for linux, because in some high-throughput environments, - // kernel control is more efficient and reasonable than program - // settings. For example, refer to cloudflare's blog - #undef SOCKET_DEFAULT_BUF_SIZE - #define SOCKET_DEFAULT_BUF_SIZE 0 - #endif - #else - #undef SOCKET_DEFAULT_BUF_SIZE - #define SOCKET_DEFAULT_BUF_SIZE SOCKET_DEFAULT_BUFFER_SIZE - #endif #endif - +#endif #define TCP_KEEPALIVE_INTERVAL 30 #define TCP_KEEPALIVE_PROBE_TIMES 9 #define TCP_KEEPALIVE_TIME 120 From 31679bcb37e959c3e3a8fd88458bb4aea068bc8d Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 30 Nov 2023 11:34:49 +0800 Subject: [PATCH 3/3] =?UTF-8?q?IDE=E5=BF=98=E8=AE=B0=E6=8C=87=E5=AE=9A?= =?UTF-8?q?=E9=A1=B9=E7=9B=AE=E4=B8=8B=E7=9A=84clang-format=E4=BA=86,=20?= =?UTF-8?q?=E9=87=8D=E6=96=B0=E6=A0=BC=E5=BC=8F=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Network/sockutil.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Network/sockutil.cpp b/src/Network/sockutil.cpp index 27fa0ad3b..7778e2abc 100644 --- a/src/Network/sockutil.cpp +++ b/src/Network/sockutil.cpp @@ -279,7 +279,7 @@ int SockUtil::setNoBlocked(int fd, bool noblock) { } int SockUtil::setRecvBuf(int fd, int size) { - if(size <= 0){ + if (size <= 0) { // use the system default value return 0; } @@ -291,7 +291,7 @@ int SockUtil::setRecvBuf(int fd, int size) { } int SockUtil::setSendBuf(int fd, int size) { - if(size <= 0){ + if (size <= 0) { return 0; } int ret = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (char *) &size, sizeof(size));