├── .gitignore
├── .ycm_extra_conf.py
├── LICENSE
├── Makefile
├── README.md
├── docs
├── INSTALL
├── README
└── benchmark.md
├── examples
├── helper.cpp
├── helper.h
├── io.cpp
├── io.h
├── redis.cpp
├── redis.h
├── xcurl.cpp
└── xcurl.h
├── include
├── event.h
├── network.h
└── threads.h
├── libevlite.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ ├── IDEWorkspaceChecks.plist
│ │ └── libevlite.xccheckout
└── xcshareddata
│ └── xcschemes
│ ├── echoserver.xcscheme
│ ├── pingpong.xcscheme
│ └── pingpong_client.xcscheme
├── src
├── channel.c
├── channel.h
├── config.h
├── driver.c
├── driver.h
├── ephashtable.c
├── ephashtable.h
├── epoll.c
├── event-internal.h
├── event.c
├── ikcp.c
├── ikcp.h
├── kqueue.c
├── lock.h
├── message.c
├── message.h
├── network-internal.h
├── network.c
├── queue.h
├── session.c
├── session.h
├── threads-internal.h
├── threads.c
├── timer.c
├── utils.c
└── utils.h
└── test
├── accept-lock-echoserver.c
├── chatroom.h
├── chatroom_client.cpp
├── chatroom_server.cpp
├── echoclient.cpp
├── echoserver.cpp
├── echostress.c
├── pingpong.c
├── pingpongclient.c
├── raw_echoserver.c
├── slice.h
├── test_addtimer.c
├── test_events.c
├── test_iothreads.c
├── test_multicurl.cpp
├── test_queue.c
└── test_sidlist.c
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | *.opannotate
3 | *.opreport
4 | tags
5 | *.o
6 | *.swp
7 | !xcshareddata
8 | xcuserdata
9 | *.pbxuser
10 | *~.nib
11 | .vscode/*
12 |
--------------------------------------------------------------------------------
/.ycm_extra_conf.py:
--------------------------------------------------------------------------------
1 | # This file is NOT licensed under the GPLv3, which is the license for the rest
2 | # of YouCompleteMe.
3 | #
4 | # Here's the license text for this file:
5 | #
6 | # This is free and unencumbered software released into the public domain.
7 | #
8 | # Anyone is free to copy, modify, publish, use, compile, sell, or
9 | # distribute this software, either in source code form or as a compiled
10 | # binary, for any purpose, commercial or non-commercial, and by any
11 | # means.
12 | #
13 | # In jurisdictions that recognize copyright laws, the author or authors
14 | # of this software dedicate any and all copyright interest in the
15 | # software to the public domain. We make this dedication for the benefit
16 | # of the public at large and to the detriment of our heirs and
17 | # successors. We intend this dedication to be an overt act of
18 | # relinquishment in perpetuity of all present and future rights to this
19 | # software under copyright law.
20 | #
21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
24 | # IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
25 | # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
26 | # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27 | # OTHER DEALINGS IN THE SOFTWARE.
28 | #
29 | # For more information, please refer to
30 |
31 | from distutils.sysconfig import get_python_inc
32 | import platform
33 | import os.path as p
34 | import subprocess
35 |
36 | DIR_OF_THIS_SCRIPT = p.abspath( p.dirname( __file__ ) )
37 | DIR_OF_THIRD_PARTY = p.join( DIR_OF_THIS_SCRIPT, 'third_party' )
38 | DIR_OF_WATCHDOG_DEPS = p.join( DIR_OF_THIRD_PARTY, 'watchdog_deps' )
39 | SOURCE_EXTENSIONS = [ '.cpp', '.cxx', '.cc', '.c', '.m', '.mm' ]
40 |
41 | database = None
42 |
43 | # These are the compilation flags that will be used in case there's no
44 | # compilation database set (by default, one is not set).
45 | # CHANGE THIS LIST OF FLAGS. YES, THIS IS THE DROID YOU HAVE BEEN LOOKING FOR.
46 | flags = [
47 | '-Wall',
48 | '-Wextra',
49 | #'-Werror',
50 | '-Wno-long-long',
51 | '-Wno-variadic-macros',
52 | '-fexceptions',
53 | '-DNDEBUG',
54 | # You 100% do NOT need -DUSE_CLANG_COMPLETER and/or -DYCM_EXPORT in your flags;
55 | # only the YCM source code needs it.
56 | '-DUSE_CLANG_COMPLETER',
57 | '-DYCM_EXPORT=',
58 | '-DYCM_ABSEIL_SUPPORTED',
59 | # THIS IS IMPORTANT! Without the '-x' flag, Clang won't know which language to
60 | # use when compiling headers. So it will guess. Badly. So C++ headers will be
61 | # compiled as C headers. You don't want that so ALWAYS specify the '-x' flag.
62 | # For a C project, you would set this to 'c' instead of 'c++'.
63 | '-x',
64 | 'c++',
65 | '-std=c++17',
66 | '-I', 'src',
67 | '-I', 'include',
68 | '-I', 'src/test',
69 | '-I', 'src/examples',
70 | '-isystem', '/usr/local/include',
71 | '-isystem', '/usr/include/c++/9',
72 | '-isystem', '/usr/include',
73 | '-isystem', '/usr/include/x86_64-linux-gnu/c++/9',
74 | '-isystem', '/usr/include/x86_64-linux-gnu',
75 | '-isystem', 'cpp/absl',
76 | '-isystem', 'cpp/pybind11',
77 | '-isystem', 'cpp/whereami',
78 | '-isystem', 'cpp/BoostParts',
79 | '-isystem', get_python_inc(),
80 | '-isystem', 'cpp/llvm/include',
81 | '-isystem', 'cpp/llvm/tools/clang/include',
82 | '-I', 'cpp/ycm',
83 | '-I', 'cpp/ycm/ClangCompleter',
84 | '-isystem', 'cpp/ycm/tests/gmock/googlemock/include',
85 | '-isystem', 'cpp/ycm/tests/gmock/googletest/include',
86 | '-isystem', 'cpp/ycm/benchmarks/benchmark/include',
87 | ]
88 |
89 | # Set this to the absolute path to the folder (NOT the file!) containing the
90 | # compile_commands.json file to use that instead of 'flags'. See here for
91 | # more details: http://clang.llvm.org/docs/JSONCompilationDatabase.html
92 | #
93 | # You can get CMake to generate this file for you by adding:
94 | # set( CMAKE_EXPORT_COMPILE_COMMANDS 1 )
95 | # to your CMakeLists.txt file.
96 | #
97 | # Most projects will NOT need to set this to anything; you can just change the
98 | # 'flags' list of compilation flags. Notice that YCM itself uses that approach.
99 | compilation_database_folder = ''
100 |
101 |
102 | def IsHeaderFile( filename ):
103 | extension = p.splitext( filename )[ 1 ]
104 | return extension in [ '.h', '.hxx', '.hpp', '.hh' ]
105 |
106 |
107 | def FindCorrespondingSourceFile( filename ):
108 | if IsHeaderFile( filename ):
109 | basename = p.splitext( filename )[ 0 ]
110 | for extension in SOURCE_EXTENSIONS:
111 | replacement_file = basename + extension
112 | if p.exists( replacement_file ):
113 | return replacement_file
114 | return filename
115 |
116 |
117 | def PathToPythonUsedDuringBuild():
118 | try:
119 | filepath = p.join( DIR_OF_THIS_SCRIPT, 'PYTHON_USED_DURING_BUILDING' )
120 | with open( filepath ) as f:
121 | return f.read().strip()
122 | except OSError:
123 | return None
124 |
125 |
126 | def Settings( **kwargs ):
127 | # Do NOT import ycm_core at module scope.
128 | import ycm_core
129 |
130 | global database
131 | if database is None and p.exists( compilation_database_folder ):
132 | database = ycm_core.CompilationDatabase( compilation_database_folder )
133 |
134 | language = kwargs[ 'language' ]
135 |
136 | if language == 'cfamily':
137 | # If the file is a header, try to find the corresponding source file and
138 | # retrieve its flags from the compilation database if using one. This is
139 | # necessary since compilation databases don't have entries for header files.
140 | # In addition, use this source file as the translation unit. This makes it
141 | # possible to jump from a declaration in the header file to its definition
142 | # in the corresponding source file.
143 | filename = FindCorrespondingSourceFile( kwargs[ 'filename' ] )
144 |
145 | if not database:
146 | return {
147 | 'flags': flags,
148 | 'include_paths_relative_to_dir': DIR_OF_THIS_SCRIPT,
149 | 'override_filename': filename
150 | }
151 |
152 | compilation_info = database.GetCompilationInfoForFile( filename )
153 | if not compilation_info.compiler_flags_:
154 | return {}
155 |
156 | # Bear in mind that compilation_info.compiler_flags_ does NOT return a
157 | # python list, but a "list-like" StringVec object.
158 | final_flags = list( compilation_info.compiler_flags_ )
159 |
160 | # NOTE: This is just for YouCompleteMe; it's highly likely that your project
161 | # does NOT need to remove the stdlib flag. DO NOT USE THIS IN YOUR
162 | # ycm_extra_conf IF YOU'RE NOT 100% SURE YOU NEED IT.
163 | try:
164 | final_flags.remove( '-stdlib=libc++' )
165 | except ValueError:
166 | pass
167 |
168 | return {
169 | 'flags': final_flags,
170 | 'include_paths_relative_to_dir': compilation_info.compiler_working_dir_,
171 | 'override_filename': filename
172 | }
173 |
174 | if language == 'python':
175 | return {
176 | 'interpreter_path': PathToPythonUsedDuringBuild()
177 | }
178 |
179 | return {}
180 |
181 |
182 | def PythonSysPath( **kwargs ):
183 | sys_path = kwargs[ 'sys_path' ]
184 |
185 | interpreter_path = kwargs[ 'interpreter_path' ]
186 | major_version = subprocess.check_output( [
187 | interpreter_path, '-c', 'import sys; print( sys.version_info[ 0 ] )' ]
188 | ).rstrip().decode( 'utf8' )
189 |
190 | sys_path[ 0:0 ] = [ p.join( DIR_OF_THIS_SCRIPT ),
191 | p.join( DIR_OF_THIRD_PARTY, 'bottle' ),
192 | p.join( DIR_OF_THIRD_PARTY, 'regex-build' ),
193 | p.join( DIR_OF_THIRD_PARTY, 'frozendict' ),
194 | p.join( DIR_OF_THIRD_PARTY, 'jedi_deps', 'jedi' ),
195 | p.join( DIR_OF_THIRD_PARTY, 'jedi_deps', 'parso' ),
196 | p.join( DIR_OF_WATCHDOG_DEPS, 'watchdog', 'build', 'lib3' ),
197 | p.join( DIR_OF_WATCHDOG_DEPS, 'pathtools' ),
198 | p.join( DIR_OF_THIRD_PARTY, 'waitress' ) ]
199 |
200 | sys_path.append( p.join( DIR_OF_THIRD_PARTY, 'jedi_deps', 'numpydoc' ) )
201 | return sys_path
202 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2012, spriteray@gmail.com
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 |
7 | * Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 |
10 | * Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 |
2 | # ------------------------------------------------------------------------------
3 | OS = $(shell uname)
4 |
5 | APP = libevlite
6 | VERSION = 9.9.9
7 | PREFIX = /usr/local
8 |
9 | # 主版本号
10 | MAJORVER = $(firstword $(subst ., ,$(VERSION)))
11 |
12 | # ------------------------------------------------------------------------------
13 | # FreeBSD采用clang做为编译器
14 | ifeq ($(OS),FreeBSD)
15 | CC = clang
16 | CXX = clang++
17 | else
18 | CC = gcc
19 | CXX = g++
20 | endif
21 |
22 | #
23 | # 编译选项
24 | #
25 | # USE_ATOMIC - 使用原子操作
26 | # USE_REUSESESSION - 重用会话(提高效率)
27 | #
28 |
29 | # 默认选项
30 | LFLAGS = -ggdb -lpthread
31 | CFLAGS = -Wall -Wformat=0 -Iinclude/ -Isrc/ -Itest/ -ggdb -fPIC -O2 -DNDEBUG -D__EVENT_VERSION__=\"$(REALNAME)\" -DUSE_ATOMIC #-DUSE_REUSESESSION
32 | CXXFLAGS = -Wall -Wformat=0 -Iinclude/ -Isrc/ -Itest/ -ggdb -fPIC -O2 -DNDEBUG -D__EVENT_VERSION__=\"$(REALNAME)\" -DUSE_ATOMIC #-DUSE_REUSESESSION
33 |
34 | # 动态库编译选项
35 | ifeq ($(OS),Darwin)
36 | LIBNAME = $(APP).dylib
37 | SONAME = $(APP).$(MAJORVER).dylib
38 | REALNAME= $(APP).$(VERSION).dylib
39 | SOFLAGS = -dynamiclib -Wl,-install_name,$(SONAME) -compatibility_version $(MAJORVER) -current_version $(VERSION)
40 | else
41 | LIBNAME = $(APP).so
42 | SONAME = $(LIBNAME).$(MAJORVER)
43 | REALNAME= $(LIBNAME).$(VERSION)
44 | SOFLAGS = -shared -Wl,-soname,$(SONAME)
45 | endif
46 |
47 | # Linux定制参数
48 | ifeq ($(OS),Linux)
49 | LFLAGS = -ggdb -pthread -lrt
50 | CFLAGS += -finline-limit=1000
51 | CXXFLAGS+= -finline-limit=1000
52 | endif
53 |
54 | # ------------------------------------------------------------------------------
55 | # 安装目录lib, include
56 | LIBPATH = $(PREFIX)/lib
57 | INCLUDEPATH = $(PREFIX)/include
58 |
59 | #
60 | # 利用git tag发布软件版本
61 | #
62 | #APPNAME=`git describe | awk -F- '{print $$1}'`
63 | #VERSION=`git describe | awk -F- '{print $$2}'`
64 | #MAJORVER=`git describe | awk -F- '{print $$2}' | awk -F. '{print $$1}'`
65 | #
66 | #LIBNAME=$(APPNAME).so
67 | #SONAME=$(APPNAME).so.$(MAJORVER)
68 | #REALNAME=$(APPNAME).so.$(VERSION)
69 | #
70 |
71 | # ------------------------------------------------------------------------------
72 | OBJS = ikcp.o driver.o utils.o ephashtable.o \
73 | epoll.o kqueue.o timer.o \
74 | event.o \
75 | threads.o \
76 | message.o channel.o session.o \
77 | network.o
78 |
79 | # ------------------------------------------------------------------------------
80 | all : $(REALNAME)
81 |
82 | install : all
83 | rm -rf $(INCLUDEPATH)/evlite
84 | cp -a include $(INCLUDEPATH)/evlite
85 | rm -rf $(LIBPATH)/$(REALNAME); cp $(REALNAME) $(LIBPATH)
86 | rm -rf $(LIBPATH)/$(SONAME); ln -s $(REALNAME) $(LIBPATH)/$(SONAME)
87 | rm -rf $(LIBPATH)/$(LIBNAME); ln -s $(REALNAME) $(LIBPATH)/$(LIBNAME)
88 |
89 | $(REALNAME) : $(OBJS)
90 | $(CC) $(SOFLAGS) $(LFLAGS) $^ -o $@
91 | rm -rf $(SONAME); ln -s $@ $(SONAME)
92 | rm -rf $(LIBNAME); ln -s $@ $(LIBNAME)
93 |
94 | test : test_multicurl pingpong_client test_events test_addtimer test_queue test_sidlist echoserver-lock echoserver iothreads_dispatcher
95 |
96 | test_events : test_events.o $(OBJS)
97 | $(CC) $^ -o $@ $(LFLAGS)
98 |
99 | test_addtimer : test_addtimer.o $(OBJS)
100 | $(CC) $^ -o $@ $(LFLAGS)
101 |
102 | test_queue : test_queue.o
103 | $(CC) $^ -o $@ $(LFLAGS)
104 |
105 | test_sidlist : test_sidlist.o utils.o
106 | $(CC) $^ -o $@ $(LFLAGS)
107 |
108 | echoserver-lock : accept-lock-echoserver.o $(OBJS)
109 | $(CC) $^ -o $@ $(LFLAGS)
110 |
111 | echoclient : io.o echoclient.o $(OBJS)
112 | $(CXX) $^ -o $@ $(LFLAGS)
113 |
114 | echoserver : io.o echoserver.o $(OBJS)
115 | $(CXX) $^ -o $@ $(LFLAGS)
116 |
117 | raw_echoserver : raw_echoserver.o $(OBJS)
118 | $(CC) $^ -o $@ $(LFLAGS)
119 |
120 | pingpong : pingpong.o $(OBJS)
121 | $(CC) $^ -o $@ $(LFLAGS)
122 |
123 | echostress :
124 | $(CC) test/echostress.c -o $@ -I/usr/local/include -L/usr/local/lib -levent
125 |
126 | iothreads_dispatcher : test_iothreads.o $(OBJS)
127 | $(CC) $(LFLAGS) $^ -o $@
128 |
129 | chatroom : chatroom_server chatroom_client
130 |
131 | chatroom_server: io.o chatroom_server.o $(OBJS)
132 | $(CXX) $^ -o $@ $(LFLAGS)
133 |
134 | chatroom_client: io.o chatroom_client.o $(OBJS)
135 | $(CXX) $^ -o $@ $(LFLAGS)
136 |
137 | redis_client : io.o redis.o helper.o $(OBJS)
138 | $(CXX) $^ -o $@ $(LFLAGS) -lhiredis
139 |
140 | pingpong_client : pingpongclient.o $(OBJS)
141 | $(CXX) $^ -o $@ $(LFLAGS)
142 |
143 | test_multicurl : xcurl.o test_multicurl.o $(OBJS)
144 | $(CXX) $^ -o $@ $(LFLAGS) -lcurl
145 |
146 | clean :
147 | rm -rf *.o
148 | rm -rf *.log
149 | rm -rf core
150 | rm -rf *.core
151 | rm -rf core.*
152 | rm -rf vgcore.*
153 | rm -rf $(SONAME)
154 | rm -rf $(LIBNAME)
155 | rm -rf $(REALNAME)
156 | rm -rf test_events event.fifo
157 | rm -rf test_queue test_sidlist
158 | rm -rf chatroom_client chatroom_server
159 | rm -rf test_multicurl test_addtimer echoclient echostress raw_echoserver echoserver pingpong echoserver-lock iothreads_dispatcher redis_client pingpong_client
160 |
161 | # --------------------------------------------------------
162 | #
163 | # gmake的规则
164 | #
165 | %.o : %.c
166 | $(CC) $(CFLAGS) -Wno-unused-function -c $^ -o $@
167 |
168 | %.o : %.cpp
169 | $(CXX) $(CXXFLAGS) -std=c++11 -Wno-unused-function -Itest/ -Iexamples/ -c $^ -o $@
170 |
171 | VPATH = src:include:test:examples
172 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # libevlite网络通信库(Linux, Darwin, \*BSD)
2 |
3 | ## 1. 基础事件模块( `include/event.h` )
4 | ==支持的IO复用机制: epoll和kqueue==
5 | ### 1.1 事件类型说明
6 | - 读事件(`EV_READ`)
7 | - 写事件(`EV_WRITE`)
8 | - 超时事件(`EV_TIMEOUT`)
9 | - 在三种事件类型的基础上, 支持事件驻留在事件集中的永久模式(`EV_PERSIST`)
10 |
11 | ### 1.2 基于事件(`event_t`)的方法说明
12 | - 设置事件属性 `event_set()`
13 | - 设置事件回调函数 `event_set_callback()`
14 |
15 | ### 1.3 基于事件集(`evsets_t`)的方法说明
16 | - 向事件集中添加事件 `evsets_add()`
17 | - 从事件集中删除事件 `evsets_del()`
18 | - 分发并处理事件 `evsets_dispatch()`
19 |
20 | ## 2. 网络线程模块( `include/threads.h` )
21 |
22 | ## 3. 通信模块( `include/networks.h` )
23 |
24 | ### 3.1 创建网络通信层 `iolayer_create()`
25 | - nthreads: 指定网络线程的个数
26 | - nclients: 推荐连接数
27 | - precision: 事件集的时间精度(建议值8ms)
28 | - immediately: 数据是否会立刻推送到网络层,对实时性要求很高的场景, 建议设置为1
29 |
30 | ### 3.2 设置网络通信层的方法(仅在IO线程中才能使用)
31 | - 设置线程上下文: `iolayer_set_iocontext()`
32 | - 设置网络层数据改造方法: `iolayer_set_transform()`
33 |
34 | ### 3.3 监听端口/开启服务端 `iolayer_listen()`
35 | - type: 网络类型, 支持`TCP`, `UDP`和`KCP`
36 | - host: 绑定的地址
37 | - port: 监听的端口号
38 | - options: 服务器全局参数(当前主要是`KCP`的参数配置)
39 | - callback: 新会话创建成功的回调
40 | - context: 上下文参数
41 |
42 | ### 3.4 连接远程服务/开启客户端 `iolayer_connect()`
43 |
44 | ### 3.5 关联描述符的读写事件 `iolayer_associate()`
45 |
46 | ### 3.6 设置会话的方法(仅在IO线程中才能使用)
47 | - 设置会话的超时时间 `iolayer_set_timeout()`
48 | - 设置会话的保活时间 `iolayer_set_keepalive()`
49 | - 设置会话的IO服务逻辑 `iolayer_set_service()`
50 | - 设置会话的读事件常驻事件集 `iolayer_set_persist()`
51 | - 设置会话的发送队列长度限制 `iolayer_set_sndqlimit()`
52 | - 设置会话的最大传输单元(仅限`KCP`有效) `iolayer_set_mtu()`
53 | - 设置会话的最小重传时间(仅限`KCP`有效) `iolayer_set_minrto()`
54 | - 设置会话的发送接收窗口(仅限`KCP`有效) `iolayer_set_wndsize()`
55 |
56 | ### 3.7 发送数据 `iolayer_send()`
57 |
58 | ### 3.8 广播数据 `iolayer_broadcast()`, `iolayer_broadcast2()`
59 |
60 | ### 3.9 关闭会话 `iolayer_shutdown()`, `iolayer_shutdowns()`
61 |
62 | ### 3.10 提交任务到网络层 `iolayer_invoke()`, `iolayer_perform()`
63 |
64 | ### 3.11 停止服务 `iolayer_stop()`
65 | - 停止对外提供接入服务, 不再接受新的连接;
66 | - 停止所有连接的接收服务, 不再回调`ioservice_t::process()`
67 |
68 | ### 3.12 销毁网络层 `iolayer_destroy()`
69 |
--------------------------------------------------------------------------------
/docs/INSTALL:
--------------------------------------------------------------------------------
1 |
2 | linux :
3 | make os=linux install
4 |
5 | freebsd :
6 | gmake os=bsd install(如果你安装了gmake)
7 | 或者直接make install -f Makefile.bsd
8 |
--------------------------------------------------------------------------------
/docs/README:
--------------------------------------------------------------------------------
1 |
2 | event事件操作库
3 |
4 | include\ - 对外接口目录,提供给使用者的include文件
5 | src\ - 具体实现部分
6 | docs\ - 文档
7 | test\ - 测试目录
8 | Makefile.* - Makefile文件
9 |
10 | 二、基于FreeBSD的事件库([ FreeBSD7.4, Xeon E5410 * 1, 8G ])
11 |
12 | 1. 测试结果:回显服务的压力测试,在没有超时参与的基础上, 性能比libevent高出10%左右。
13 |
14 | 2. 出现的问题:
15 | 1) 在1000个连接的情况下,总有10个左右的连接的close事件丢失了
16 | 所需要监控的描述符已经注册到kqueue中,基本定位到kevent()中;event事件库和libevent都存在。初步怀疑是测试环境有问题。
17 |
18 |
19 | 三、基于linux的事件库([ Centos 6.0(linux-2.6.32), Pentium(R) Dual-Core E6700 3.20GHz, 512M ])
20 |
21 | 1. 测试结果:
22 | 1) 效率比内核2.6.18内核带来了20%的提升。
23 | 2) 回显服务的压力测试,在没有超时参与的基础上,性能比libevent高出17%左右.
24 | 3) 在超时时间设定为5s的情况下,性能比libevent高出160%左右。
25 | Connections 吞吐量[event] 吞吐量[libevent]
26 | 1000 113MBytes/s 41MBytes/s
27 | 1000 110MBytes/s 43MBytes/s
28 | 10000 119MBytes/s 20MBytes/s
29 | 10000 110MBytes/s 37MBytes/s
30 |
31 | 2. 出现的问题:
32 | 1) 1000个连接时候的上下文切换达到50K, 但20000个连接的切换才300多;[已解决, vmstat统计问题]
33 | Connections CS 吞吐量
34 | 1000 55000 110MBytes/s
35 | 2000 40000 109MBytes/s
36 | 3000 47000 108MBytes/s
37 | 4000 49000 104MBytes/s
38 | 5000 50000 109MBytes/s
39 | 6000 9000,[330~38000] 130MBytes/s
40 | 7000 6000,[300~19000] 131MBytes/s
41 | 8000 1000,[300~18000] 127MBytes/s
42 | 10000 350 130MBytes/s
43 |
44 | 2) 同样1000个连接的时候, IO线程等待时间为0时(IO线程真正分摊压力), 上下文切换大量降低,但吞吐量锐减;
45 |
46 | 四、Accept-Lock模型的回显服务器
47 |
48 | 1. 模型介绍:
49 | Accept-Lock模型,能在在多个IO线程中,高效的公平的分摊IO的压力,绝对比fd硬hash来的高效。
50 |
51 | 2. 测试结果:
52 | 1) accept事件总是在一个线程中发生, 并没有原先设计的效果。从压力测试的脚本来看,这样的结果也是可以理解的。
53 | 毕竟所有连接都成功后,才开始发送数据的,所以一开始的线程基本没有什么压力。
54 |
55 | 五、同样的开发环境中,centos6.0比freebsd8.2快了近30%。
56 |
57 | 六、吞吐量横向比较(muduo, Ubuntu 14.04.5, Intel(R) Xeon(R) CPU E5606 @ 2.13GHz, 8核8G)
58 | moduo 1000个连接,4个IO线程,4K的数据包,197.515234375 MiB/s throughput
59 | libevlite 1000个连接,4个IO线程,4K的数据包,245.58203125 MiB/s throughput
60 |
61 |
--------------------------------------------------------------------------------
/docs/benchmark.md:
--------------------------------------------------------------------------------
1 | # libevlite性能测试
2 |
3 |
4 |
5 | ### 一、吞吐量测试结果
6 |
7 | ##### 1. 硬件配置
8 |
9 | 2CPU4Core
10 |
11 | CPU型号 Intel(R) Xeon(R) CPU E5606 @ 2.13GHz
12 |
13 | 8G内存
14 |
15 | Ubuntu 14.04.5
16 |
17 | ##### 2. 4K数据包,4个IO线程
18 |
19 | | 连接数 | 1000 | 2000 | 10000 |
20 | | --------- | ------- | ------- | ------- |
21 | | muduo | 197.515 | 232.825 | 244.675 |
22 | | libevlite | 245.582 | 238.293 | 244.478 |
23 |
24 | ##### 3. 16K数据包,4个IO线程
25 |
26 | | 连接数 | 1000 | 2000 | 10000 |
27 | | --------- | ------- | ------- | ------- |
28 | | muduo | 596.692 | 598.942 | 588.075 |
29 | | libevlite | 630.339 | 598.021 | 571.337 |
--------------------------------------------------------------------------------
/examples/helper.cpp:
--------------------------------------------------------------------------------
1 |
2 | #include
3 |
4 | #include "helper.h"
5 |
6 | Slice RedisCommand::ping()
7 | {
8 | char * buffer = NULL;
9 | ssize_t length = redisFormatCommand( &buffer, "PING" );
10 |
11 | if ( length < 0 )
12 | {
13 | return Slice();
14 | }
15 |
16 | return Slice( buffer, length );
17 | }
18 |
19 | Slice RedisCommand::echo( const std::string & text )
20 | {
21 | char * buffer = NULL;
22 | ssize_t length = redisFormatCommand(
23 | &buffer, "ECHO \"%s\"", text.c_str() );
24 |
25 | if ( length < 0 )
26 | {
27 | return Slice();
28 | }
29 |
30 | return Slice( buffer, length );
31 | }
32 |
33 | Slice RedisCommand::auth( const std::string & password )
34 | {
35 | char * buffer = NULL;
36 | ssize_t length = redisFormatCommand(
37 | &buffer, "AUTH %s", password.c_str() );
38 |
39 | if ( length < 0 )
40 | {
41 | return Slice();
42 | }
43 |
44 | return Slice( buffer, length );
45 | }
46 |
47 | Slice RedisCommand::get( const std::string & key )
48 | {
49 | char * buffer = NULL;
50 | ssize_t length = redisFormatCommand(
51 | &buffer, "GET %s", key.c_str() );
52 |
53 | if ( length < 0 )
54 | {
55 | return Slice();
56 | }
57 |
58 | return Slice( buffer, length );
59 | }
60 |
61 | Slice RedisCommand::mget( const std::vector & keys )
62 | {
63 | size_t ncmds = keys.size() + 1;
64 | size_t argvlen[ ncmds ];
65 | const char * argv[ ncmds ];
66 |
67 | argv[0] = "MGET";
68 | argvlen[0] = 4;
69 |
70 | for ( size_t i = 0; i < keys.size(); ++i )
71 | {
72 | argv[i+1] = keys[i].c_str();
73 | argvlen[i+1] = keys[i].size();
74 | }
75 |
76 | char * buffer = NULL;
77 | ssize_t length = redisFormatCommandArgv(
78 | &buffer,
79 | keys.size()+1, argv, argvlen );
80 |
81 | if ( length < 0 )
82 | {
83 | return Slice();
84 | }
85 |
86 | return Slice( buffer, length );
87 | }
88 |
89 | Slice RedisCommand::set( const std::string & key, const std::string & value )
90 | {
91 | char * buffer = NULL;
92 | ssize_t length = redisFormatCommand(
93 | &buffer, "SET %s %b",
94 | key.c_str(), value.data(), value.size() );
95 |
96 | if ( length < 0 )
97 | {
98 | return Slice();
99 | }
100 |
101 | return Slice( buffer, length );
102 | }
103 |
104 | Slice RedisCommand::incr( const std::string & key )
105 | {
106 | char * buffer = NULL;
107 | ssize_t length = redisFormatCommand(
108 | &buffer, "INCR %s", key.c_str() );
109 |
110 | if ( length < 0 )
111 | {
112 | return Slice();
113 | }
114 |
115 | return Slice( buffer, length );
116 | }
117 |
118 | Slice RedisCommand::incrby( const std::string & key, int32_t value )
119 | {
120 | char * buffer = NULL;
121 | ssize_t length = redisFormatCommand(
122 | &buffer, "INCRBY %s %d", key.c_str(), value );
123 |
124 | if ( length < 0 )
125 | {
126 | return Slice();
127 | }
128 |
129 | return Slice( buffer, length );
130 | }
131 |
132 | Slice RedisCommand::decr( const std::string & key )
133 | {
134 | char * buffer = NULL;
135 | ssize_t length = redisFormatCommand(
136 | &buffer, "DECR %s", key.c_str() );
137 |
138 | if ( length < 0 )
139 | {
140 | return Slice();
141 | }
142 |
143 | return Slice( buffer, length );
144 | }
145 |
146 | Slice RedisCommand::decrby( const std::string & key, int32_t value )
147 | {
148 | char * buffer = NULL;
149 | ssize_t length = redisFormatCommand(
150 | &buffer, "DECRBY %s %d", key.c_str(), value );
151 |
152 | if ( length < 0 )
153 | {
154 | return Slice();
155 | }
156 |
157 | return Slice( buffer, length );
158 | }
159 |
160 | Slice RedisCommand::lpush( const std::string & key, const std::vector & values )
161 | {
162 | size_t ncmds = values.size() + 2;
163 |
164 | size_t argvlen[ ncmds ];
165 | const char * argv[ ncmds ];
166 |
167 | argv[0] = "LPUSH";
168 | argvlen[0] = 5;
169 | argv[1] = key.c_str();
170 | argvlen[1] = key.size();
171 |
172 | for ( size_t i = 0; i < values.size(); ++i )
173 | {
174 | argv[i+2] = values[i].c_str();
175 | argvlen[i+2] = values[i].size();
176 | }
177 |
178 | char * buffer = NULL;
179 | ssize_t length = redisFormatCommandArgv(
180 | &buffer,
181 | ncmds, argv, argvlen );
182 |
183 | if ( length < 0 )
184 | {
185 | return Slice();
186 | }
187 |
188 | return Slice( buffer, length );
189 | }
190 |
191 | Slice RedisCommand::rpush( const std::string & key, const std::vector & values )
192 | {
193 | size_t ncmds = values.size() + 2;
194 |
195 | size_t argvlen[ ncmds ];
196 | const char * argv[ ncmds ];
197 |
198 | argv[0] = "RPUSH";
199 | argvlen[0] = 5;
200 | argv[1] = key.c_str();
201 | argvlen[1] = key.size();
202 |
203 | for ( size_t i = 0; i < values.size(); ++i )
204 | {
205 | argv[i+2] = values[i].c_str();
206 | argvlen[i+2] = values[i].size();
207 | }
208 |
209 | char * buffer = NULL;
210 | ssize_t length = redisFormatCommandArgv(
211 | &buffer,
212 | ncmds, argv, argvlen );
213 |
214 | if ( length < 0 )
215 | {
216 | return Slice();
217 | }
218 |
219 | return Slice( buffer, length );
220 | }
221 |
222 | Slice RedisCommand::lrange( const std::string & key, int32_t startidx, int32_t stopidx )
223 | {
224 | char * buffer = NULL;
225 | ssize_t length = redisFormatCommand(
226 | &buffer, "LRANGE %s %d %d", key.c_str(), startidx, stopidx );
227 |
228 | if ( length < 0 )
229 | {
230 | return Slice();
231 | }
232 |
233 | return Slice( buffer, length );
234 | }
235 |
236 | Slice RedisCommand::subscribe( const std::string & channel )
237 | {
238 | char * buffer = NULL;
239 | ssize_t length = redisFormatCommand(
240 | &buffer, "SUBSCRIBE %s", channel.c_str() );
241 |
242 | if ( length < 0 )
243 | {
244 | return Slice();
245 | }
246 |
247 | return Slice( buffer, length );
248 | }
249 |
250 | Slice RedisCommand::unsubscribe( const std::string & channel )
251 | {
252 | char * buffer = NULL;
253 | ssize_t length = redisFormatCommand(
254 | &buffer, "UNSUBSCRIBE %s", channel.c_str() );
255 |
256 | if ( length < 0 )
257 | {
258 | return Slice();
259 | }
260 |
261 | return Slice( buffer, length );
262 | }
263 |
264 | Slice RedisCommand::publish( const std::string & channel, const std::string & message )
265 | {
266 | char * buffer = NULL;
267 | ssize_t length = redisFormatCommand(
268 | &buffer, "PUBLISH %s \"%s\"", channel.c_str(), message.c_str() );
269 |
270 | if ( length < 0 )
271 | {
272 | return Slice();
273 | }
274 |
275 | return Slice( buffer, length );
276 | }
277 |
278 | template<> long long int ResultHelper::parse( redisReply * reply )
279 | {
280 | assert( reply->type == REDIS_REPLY_INTEGER );
281 | return reply->integer;
282 | }
283 |
284 | template<> std::string ResultHelper::parse( redisReply * reply )
285 | {
286 | assert( reply->type == REDIS_REPLY_STRING );
287 | return std::string( reply->str, reply->len );
288 | }
289 |
290 | template<> RedisStrList ResultHelper::parse( redisReply * reply )
291 | {
292 | RedisStrList values;
293 |
294 | assert( reply->type == REDIS_REPLY_ARRAY );
295 | for ( size_t i = 0; i < reply->elements; ++i )
296 | {
297 | if ( reply->element[i]->type != REDIS_REPLY_STRING )
298 | {
299 | values.push_back( std::string() );
300 | }
301 | else
302 | {
303 | values.push_back( std::string(reply->element[i]->str, reply->element[i]->len) );
304 | }
305 | }
306 |
307 | return values;
308 | }
309 |
--------------------------------------------------------------------------------
/examples/helper.h:
--------------------------------------------------------------------------------
1 |
2 | #ifndef __SRC_REDIS_COMMAND_H__
3 | #define __SRC_REDIS_COMMAND_H__
4 |
5 | #include
6 | #include
7 |
8 | #include "slice.h"
9 |
10 | class RedisCommand
11 | {
12 | public :
13 | // PING
14 | static Slice ping();
15 | // ECHO
16 | static Slice echo( const std::string & text );
17 | // 验证命令
18 | static Slice auth( const std::string & password );
19 | // 获取数据
20 | static Slice get( const std::string & key );
21 | static Slice mget( const std::vector & keys );
22 | // 更新命令
23 | static Slice set(
24 | const std::string & key, const std::string & value );
25 | // 自增
26 | static Slice incr( const std::string & key );
27 | static Slice incrby( const std::string & key, int32_t value );
28 | // 自减
29 | static Slice decr( const std::string & key );
30 | static Slice decrby( const std::string & key, int32_t value );
31 | // list
32 | static Slice lpush( const std::string & key, const std::vector & values );
33 | static Slice rpush( const std::string & key, const std::vector & values );
34 | static Slice lrange( const std::string & key, int32_t startidx, int32_t stopidx );
35 | // 订阅命令
36 | static Slice subscribe( const std::string & channel );
37 | // 取消订阅命令
38 | static Slice unsubscribe( const std::string & channel );
39 | // 发布命令
40 | static Slice publish( const std::string & channel, const std::string & message );
41 | };
42 |
43 | typedef std::vector RedisStrList;
44 |
45 | struct ResultHelper
46 | {
47 | template static T parse( redisReply * reply ) { return T(); }
48 | };
49 |
50 | #endif
51 |
--------------------------------------------------------------------------------
/examples/io.h:
--------------------------------------------------------------------------------
1 |
2 | #ifndef __SRC_IO_IO_H__
3 | #define __SRC_IO_IO_H__
4 |
5 | #include
6 | #include
7 | #include
8 |
9 | #include "event.h"
10 | #include "network.h"
11 |
12 | typedef std::vector sids_t;
13 |
14 | enum class NetType
15 | {
16 | TCP = NETWORK_TCP,
17 | UDP = NETWORK_UDP,
18 | KCP = NETWORK_KCP,
19 | };
20 |
21 | //
22 | // 会话, 非线程安全的
23 | //
24 |
25 | class IIOService;
26 |
27 | class IIOSession
28 | {
29 | public :
30 | IIOSession();
31 | virtual ~IIOSession();
32 |
33 | public :
34 | //
35 | // 网络事件
36 | // 多个网络线程中被触发
37 | //
38 |
39 | virtual int32_t onStart() { return 0; }
40 | virtual ssize_t onProcess( const char * buffer, size_t nbytes ) { return 0; }
41 | virtual char * onTransform( const char * buffer, size_t & nbytes ) { return const_cast(buffer); }
42 | virtual int32_t onTimeout() { return 0; }
43 | virtual int32_t onKeepalive() { return 0; }
44 | virtual int32_t onError( int32_t result ) { return 0; }
45 | virtual int32_t onPerform( int32_t type, void * task, int32_t interval ) { return 0; }
46 | virtual void onShutdown( int32_t way ) {}
47 |
48 | public :
49 | //
50 | // 在网络线程中对会话的操作
51 | //
52 |
53 | // 获取会话ID
54 | sid_t id() const { return m_Sid; }
55 |
56 | // 获取主机端口
57 | uint16_t port() const { return m_Port; }
58 | // 获取主机地址
59 | const std::string & host() const { return m_Host; }
60 |
61 | // 获取线程上下文参数
62 | void * iocontext() const { return m_IOContext; }
63 |
64 | // 激活/关闭读事件永驻事件库
65 | // 激活后, 极端的情况下能提高IO性能40%左右
66 | void enablePersist();
67 | void disablePersist();
68 | // 设置超时/保活时间
69 | void setTimeout( int32_t seconds );
70 | void setKeepalive( int32_t seconds );
71 | // 设置host和port
72 | void setEndpoint( const std::string & host, uint16_t port );
73 | // 设置发送队列长度
74 | void setSendqueueLimit( int32_t limit );
75 | // 设置KCP的MTU
76 | void setMTU( int32_t mtu );
77 | // 设置KCP的MinRTO
78 | void setMinRTO( int32_t minrto );
79 | // 设置KCP的窗口大小
80 | void setWindowSize( int32_t sndwnd, int32_t rcvwnd );
81 |
82 | // 发送数据
83 | int32_t send( const std::string & buffer );
84 | int32_t send( const char * buffer, size_t nbytes, bool isfree = false );
85 |
86 | // 关闭会话
87 | int32_t shutdown();
88 |
89 | protected :
90 | friend class IIOService;
91 |
92 | // 初始化会话
93 | void init( sid_t id,
94 | void * context, iolayer_t layer,
95 | const std::string & host, uint16_t port );
96 |
97 | // 内部回调函数
98 | static int32_t onStartSession( void * context );
99 | static ssize_t onProcessSession( void * context, const char * buffer, size_t nbytes );
100 | static char * onTransformSession( void * context, const char * buffer, size_t * nbytes );
101 | static int32_t onTimeoutSession( void * context );
102 | static int32_t onKeepaliveSession( void * context );
103 | static int32_t onErrorSession( void * context, int32_t result );
104 | static int32_t onPerformSession( void * context, int32_t type, void * task, int32_t interval );
105 | static void onShutdownSession( void * context, int32_t way );
106 |
107 | private :
108 | sid_t m_Sid;
109 | uint16_t m_Port;
110 | std::string m_Host;
111 | iolayer_t m_Layer;
112 | void * m_IOContext;
113 | };
114 |
115 | //
116 | // 网络通信层
117 | //
118 |
119 | class IIOService
120 | {
121 | public :
122 | IIOService( uint8_t nthreads,
123 | uint32_t nclients, int32_t precision = 8, bool immediately = false, bool transform = false );
124 | virtual ~IIOService();
125 |
126 | public :
127 | // 初始化/销毁IO上下文
128 | virtual void * initIOContext() { return NULL; }
129 | virtual void finalIOContext( void * context ) { return; }
130 |
131 | // 数据改造
132 | virtual char * onTransform( const char * buffer, size_t & nbytes ) { return const_cast(buffer); }
133 |
134 | // 回调事件
135 | // 需要调用者自己实现
136 | // 有可能在IIOService的多个网络线程中被触发
137 |
138 | // 连接事件
139 | virtual bool onConnectFailed( int32_t result, const char * host, uint16_t port ) { return false; }
140 | virtual IIOSession * onConnectSucceed( sid_t id, const char * host, uint16_t port ) { return NULL; }
141 | // 接受事件
142 | virtual IIOSession * onAccept( sid_t id, NetType type, uint16_t listenport, const char * host, uint16_t port ) { return NULL; }
143 |
144 | public :
145 | //
146 | // 线程安全的API
147 | //
148 |
149 | // 开启/停止服务
150 | bool start();
151 | void stop();
152 |
153 | // 暂停对外服务(不可恢复)
154 | void halt();
155 |
156 | // 获取版本号
157 | static const char * version();
158 |
159 | // 获取IOLAYER
160 | iolayer_t iolayer() const { return m_IOLayer; }
161 |
162 | // 监听
163 | bool listen( NetType type,
164 | const char * host, uint16_t port,
165 | const options_t * options = nullptr );
166 |
167 | // 是否正在异步连接
168 | bool isConnecting( const char * host, uint16_t port );
169 |
170 | // 连接远程服务器
171 | // 参数:
172 | // host - 主机地址
173 | // port - 主机端口
174 | // seconds - 超时时间, <=0 非阻塞的连接; >0 带超时时间的阻塞连接
175 | //
176 | // 返回值:
177 | // -1 - 连接失败
178 | // 0 - 正在连接
179 | // >0 - 连接成功返回会话ID
180 | sid_t connect( const char * host, uint16_t port, int32_t seconds = 0 );
181 |
182 | // 关联描述符
183 | // 参数:
184 | // fd - 关联的描述符
185 | // privdata- 关联的私有数据
186 | // reattach- 重新绑定新的描述符(相当于重连)
187 | // cb - 关联成功后的回调函数
188 | // context - 上下文参数
189 | //
190 | // 返回值:
191 | // -1 - 关联失败
192 | // 0 - 正在连接
193 | int32_t associate( int32_t fd, void * privdata,
194 | reattacher_t reattach, associator_t cb, void * context );
195 |
196 | // 发送数据
197 | int32_t send( sid_t id, const std::string & buffer );
198 | int32_t send( sid_t id, const char * buffer, size_t nbytes, bool isfree = false );
199 |
200 | // 广播数据
201 | int32_t broadcast( const std::string & buffer );
202 | int32_t broadcast( const char * buffer, size_t nbytes );
203 | int32_t broadcast( const sids_t & ids, const std::string & buffer );
204 | int32_t broadcast( const sids_t & ids, const char * buffer, size_t nbytes );
205 |
206 | // 终止会话
207 | int32_t shutdown( sid_t id );
208 | int32_t shutdown( const sids_t & ids );
209 |
210 | // 提交任务到网络层
211 | int32_t invoke( void * task, taskcloner_t clone, taskexecutor_t execute );
212 | int32_t perform( sid_t sid, int32_t type, void * task, taskrecycler_t recycle, int32_t interval = -1 );
213 |
214 | private :
215 | // 监听上下文
216 | struct ListenContext
217 | {
218 | NetType type;
219 | uint16_t port;
220 | IIOService * service;
221 |
222 | ListenContext()
223 | : port( 0 ),
224 | service( NULL )
225 | {}
226 |
227 | ListenContext( NetType t, uint16_t p, IIOService * s )
228 | : type( t ),
229 | port( p ),
230 | service( s )
231 | {}
232 | };
233 |
234 | // 连接上下文
235 | struct ConnectContext
236 | {
237 | sid_t sid;
238 | uint16_t port;
239 | std::string host;
240 | IIOService * service;
241 |
242 | ConnectContext()
243 | : sid( 0 ),
244 | port( 0 ),
245 | service( NULL )
246 | {}
247 |
248 | ConnectContext( const char * h, uint16_t p, IIOService * s )
249 | : sid( 0 ),
250 | port( p ),
251 | host( h ),
252 | service( s )
253 | {}
254 | };
255 |
256 | typedef std::vector ListenContexts;
257 | typedef std::vector ConnectContexts;
258 |
259 | private :
260 | // 初始化会话
261 | // 在定制化非常强的场景下使用
262 | void initSession( sid_t id,
263 | IIOSession * session, void * iocontext,
264 | const std::string & host, uint16_t port );
265 |
266 | // 通知连接结果
267 | void notifyConnectResult(
268 | ConnectContext * context,
269 | int32_t result, sid_t id, int32_t ack );
270 |
271 | static char * onTransformService( void * context, const char * buffer, size_t * nbytes );
272 | static int32_t onAcceptSession( void * context, void * iocontext, sid_t id, const char * host, uint16_t port );
273 | static int32_t onConnectSession( void * context, void * iocontext, int32_t result, const char * host, uint16_t port, sid_t id );
274 |
275 | private :
276 | iolayer_t m_IOLayer;
277 | bool m_Transform;
278 | bool m_Immediately;
279 | int32_t m_Precision;
280 | uint8_t m_ThreadsCount;
281 | uint32_t m_SessionsCount;
282 | void ** m_IOContextGroup;
283 |
284 | private :
285 | pthread_cond_t m_Cond;
286 | pthread_mutex_t m_Lock;
287 | ListenContexts m_ListenContexts; // 正在监听的会话
288 | ConnectContexts m_ConnectContexts; // 正在连接的会话
289 | };
290 |
291 | #endif
292 |
--------------------------------------------------------------------------------
/examples/redis.h:
--------------------------------------------------------------------------------
1 |
2 | #ifndef __SRC_REDIS_REDIS_H__
3 | #define __SRC_REDIS_REDIS_H__
4 |
5 | #include
6 | #include
7 | #include
8 |
9 | #include "io.h"
10 | #include "slice.h"
11 |
12 | class IRedisClient : public IIOService
13 | {
14 | public :
15 | // nthreads - 线程数
16 | // nconnections - 最大连接数
17 | IRedisClient( uint8_t nthreads, uint32_t nconnections );
18 | virtual ~IRedisClient();
19 |
20 | virtual void datasets( uint32_t ctxid, redisReply * response ) = 0;
21 | virtual void error( const Slice & request, uint32_t ctxid, const std::string & errstr ) = 0;
22 |
23 | public :
24 | // 初始化
25 | // nconnections - 默认初始化连接数
26 | bool initialize(
27 | const std::string & host, uint16_t port,
28 | uint32_t connections = 4, const std::string & token = "" );
29 | // 销毁
30 | void finalize();
31 |
32 | // 订阅
33 | int32_t subscribe( const std::string & channel );
34 | int32_t unsubscribe( const std::string & channel );
35 | // 提交
36 | int32_t submit( const Slice & cmd, uint32_t ctxid = 0 );
37 | // 提交(支持pipeline)
38 | int32_t submit( const Slices & cmds, uint32_t ctxid = 0 );
39 |
40 | public :
41 | // 绑定
42 | int32_t attach();
43 |
44 | // 获取token
45 | const std::string & getToken() const { return m_Token; }
46 |
47 | private :
48 | // 初始化/销毁IO上下文
49 | virtual void * initIOContext();
50 | virtual void finalIOContext( void * context );
51 |
52 | static void * cloneTask( void * task );
53 | static void performTask( void * iocontext, void * task );
54 | static int32_t reattach( int32_t fd, void * privdata );
55 | static int32_t associatecb( void * context,
56 | void * iocontext, int32_t result, int32_t fd, void * privdata, sid_t sid );
57 |
58 | private :
59 | std::string m_Host;
60 | uint16_t m_Port;
61 | std::string m_Token;
62 | uint32_t m_Connections;
63 | };
64 |
65 | #endif
66 |
--------------------------------------------------------------------------------
/examples/xcurl.h:
--------------------------------------------------------------------------------
1 |
2 | #ifndef __SRC_HTTP_XCURL_H__
3 | #define __SRC_HTTP_XCURL_H__
4 |
5 | //
6 | // https://curl.se/libcurl/c/hiperfifo.html
7 | // http://www.voidcn.com/article/p-nzggwldk-bpx.html
8 | //
9 |
10 | #include