├── .gitignore ├── CMakeLists.txt ├── README.md ├── ikcp.c ├── ikcp.h └── kcpp.h /.gitignore: -------------------------------------------------------------------------------- 1 | .history/ 2 | 3 | # Visual Studio 2015 user specific files 4 | .vs/ 5 | 6 | # VisualStudioCode 7 | .vscode 8 | 9 | build/ 10 | 11 | vs2015/ -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # CMake 最低版本号要求 2 | cmake_minimum_required (VERSION 2.8) 3 | 4 | # support C++11 5 | SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") 6 | 7 | set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib) 8 | set (LIB_NAME kcpp) 9 | 10 | if(UNIX) 11 | if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) 12 | # set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-long-long -pedantic") 13 | # set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -w") # Inhibit all warning messages. 14 | set(CXX_FLAGS 15 | -g 16 | # -DVALGRIND 17 | # -DMUDUO_STD_STRING 18 | -DCHECK_PTHREAD_RETURN_VALUE 19 | -D_FILE_OFFSET_BITS=64 20 | -Wall 21 | -Wextra 22 | -Werror 23 | # -Wconversion 24 | -Wno-unused-parameter 25 | # -Wold-style-cast 26 | -Wno-multichar 27 | -Wno-unused-function 28 | -Wno-reorder 29 | -Woverloaded-virtual 30 | -Wpointer-arith 31 | # -Wshadow 32 | -Wwrite-strings 33 | -march=native 34 | # -MMD 35 | -std=c++0x 36 | -rdynamic 37 | ) 38 | string(REPLACE ";" " " CMAKE_CXX_FLAGS "${CXX_FLAGS}") 39 | endif() 40 | endif() 41 | 42 | 43 | set(kcp_SRCS ikcp.c) 44 | 45 | add_library(${LIB_NAME} ${kcp_SRCS}) 46 | target_link_libraries(${LIB_NAME}) 47 | 48 | include_directories(${CMAKE_CURRENT_SOURCE_DIR}) 49 | 50 | 51 | 52 | if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/test) 53 | message(STATUS "has test subdirectory.") 54 | add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/test) 55 | else() 56 | message(STATUS "has no test subdirectory.") 57 | endif() -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Lightweight KCP Session Implementation - kcpp 2 | 3 | `kcpp` truly enables you to use KCP just by including a single header file and writing a few lines of code, without having to worry about how to organize the code to adapt to KCP. 4 | 5 | - You only need to include the single header file `kcpp.h`. 6 | - You only need to call `KcpSession::Send`, `KcpSession::Recv`, and `KcpSession::Update` to complete UDP connection state management, session control, and RUDP protocol scheduling. 7 | 8 | # What is KCP? 9 | 10 | KCP is a high-performance, reliable, and lightweight transport layer protocol designed to accelerate UDP-based data transmission. It provides an efficient alternative to TCP while maintaining UDP’s low-latency benefits. Originally developed by skywind3000, KCP is widely used in real-time applications such as gaming, live streaming, VPNs, and P2P networking. 11 | 12 | # Features 13 | 14 | - Single-header-only 15 | - Session implementation 16 | - Dynamic redundancy 17 | - Two-channel 18 | - Reliable 19 | - Unreliable 20 | 21 | # kcpp Examples 22 | 23 | - [realtime-server](https://github.com/no5ix/realtime-server): A real-time dedicated game server (FPS / MOBA). 24 | - [realtime-server-ue4-demo](https://github.com/no5ix/realtime-server-ue4-demo): A UE4 state synchronization demo for the real-time server. [Video Preview](https://hulinhong.com) 25 | 26 | # kcpp Usage 27 | 28 | The main loop is supposed to be as follows: 29 | 30 | ```c++ 31 | Game.Init(); 32 | 33 | // kcpp initialization 34 | kcpp::KcpSession myKcpSess( 35 | KcpSession::RoleTypeE, 36 | std::bind(udp_output, _1, _2), 37 | std::bind(udp_input), 38 | std::bind(timer) 39 | ); 40 | 41 | while (!isGameOver) { 42 | myKcpSess.Update(); 43 | 44 | while (myKcpSess.Recv(data, len)) { 45 | if (len > 0) { 46 | Game.HandleRecvData(data, len); 47 | } else if (len < 0) { 48 | Game.HandleRecvError(len); 49 | } 50 | } 51 | 52 | if (myKcpSess.CheckCanSend()) { 53 | myKcpSess.Send(data, len); 54 | } else { 55 | Game.HandleCanNotSendForNow(); 56 | } 57 | 58 | Game.Logic(); 59 | Game.Render(); 60 | } 61 | ``` 62 | 63 | The `Recv`, `Send`, and `Update` functions of kcpp are guaranteed to be non-blocking. 64 | Please read [TestKcppClient.cpp](https://github.com/no5ix/kcpp/blob/master/TestKcppClient.cpp) and [TestKcppServer.cpp](https://github.com/no5ix/kcpp/blob/master/TestKcppServer.cpp) for some basic usage examples. 65 | 66 | # KCP Source Code Annotations 67 | 68 | This project also comes with an annotated version of the KCP source code, `ikcp.h` and `ikcp.c`. It can be regarded as another detailed explanation of KCP, which is convenient for self-study and helps others get started more quickly. The original code is from: https://github.com/skywind3000/kcp. Thanks to skywind3000 for bringing such a concise and excellent project. 69 | 70 | Readers interested in open-source projects for real-time combat games like FPS / MOBA can also visit [realtime-server](https://github.com/no5ix/realtime-server). Welcome to communicate. 71 | 72 | Note: Tabs are used for indentation in the project, and tab is set to 2 spaces. 73 | 74 | Almost every paragraph has annotations, and key data structures are accompanied by diagrams. For example: 75 | 76 | ``` 77 | ... 78 | // 79 | // The data packets sent by KCP have their own packet structure. The packet header is 24 bytes in total and contains some necessary information. The specific content and size are as follows: 80 | // 81 | // |<------------ 4 bytes ------------>| 82 | // +--------+--------+--------+--------+ 83 | // | conv | conv: Conversation, the session serial number used to identify whether the sent and received data packets are consistent. 84 | // +--------+--------+--------+--------+ cmd: Command, the instruction type, representing the type of this Segment. 85 | // | cmd | frg | wnd | frg: Fragment, the segmentation serial number. The segments are numbered from large to small, and 0 indicates that the data packet has been received completely. 86 | // +--------+--------+--------+--------+ wnd: Window, the window size. 87 | // | ts | ts: Timestamp, the sending timestamp. 88 | // +--------+--------+--------+--------+ 89 | // | sn | sn: Sequence Number, the Segment serial number. 90 | // +--------+--------+--------+--------+ 91 | // | una | una: Unacknowledged, the current unacknowledged serial number, 92 | // +--------+--------+--------+--------+ which means that all packets before this serial number have been received. 93 | // | len | len: Length, the length of the subsequent data. 94 | // +--------+--------+--------+--------+ 95 | // 96 | ... 97 | 98 | //--------------------------------------------------------------------- 99 | // ... 100 | // rcv_queue: The queue for receiving messages. The data in rcv_queue is continuous, while the data in rcv_buf may be intermittent. 101 | // nrcv_que: The number of Segments in the receiving queue rcv_queue, which needs to be less than rcv_wnd. 102 | // rcv_queue is shown in the following diagram: 103 | // +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ 104 | // ... | 2 | 3 | 4 | ............................................... 105 | // +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ 106 | // ^ ^ ^ 107 | // | | | 108 | // rcv_nxt rcv_nxt + nrcv_que rcv_nxt + rcv_wnd 109 | // 110 | // snd_buf: The buffer for sending messages. 111 | // snd_buf is shown in the following diagram: 112 | // +---+---+---+---+---+---+---+---+---+---+---+---+---+ 113 | // ... | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | ........... 114 | // +---+---+---+---+---+---+---+---+---+---+---+---+---+ 115 | // ^ ^ ^ 116 | // | | | 117 | // snd_una snd_nxt snd_una + snd_wnd 118 | // 119 | // 120 | // rcv_buf: The buffer for receiving messages. 121 | // rcv_buf is shown in the following diagram. The data in rcv_queue is continuous, while the data in rcv_buf may be intermittent. 122 | // +---+---+---+---+---+---+---+---+---+---+---+---+---+ 123 | // ... | 2 | 4 | 6 | 7 | 8 | 9 | ........... 124 | // +---+---+---+---+---+---+---+---+---+---+---+---+---+ 125 | // 126 | ... 127 | ``` 128 | 129 | 130 | 131 | 132 | 133 | # 轻量级的kcp会话实现-kcpp 134 | 135 | `kcpp`真正实现了只需要包含一个头文件再随意写几行代码就可以用上kcp, 而无需烦心如何组织代码来适配kcp 136 | 137 | - 只需包含 `kcpp.h` 这一个头文件即可 138 | - 只需调用 `KcpSession::Send` 和 `KcpSession::Recv` 和 `KcpSession::Update` 即可完成UDP的链接状态管理、会话控制、 RUDP协议调度 139 | 140 | 141 | 142 | # kcp源码注释 143 | 144 | 本项目还附了一个注释版的kcp源码 `ikcp.h` 和 `ikcp.c`, 算是另一种的 kcp详解, 方便自己学习也为大家更快的上手, 原始代码来自: https://github.com/skywind3000/kcp , 感谢 skywind3000 带来这么短小精悍的好项目 145 | 146 | 对 FPS / MOBA 类实时对战游戏开源项目感兴趣的读者还可以移步 [realtime-server](https://github.com/no5ix/realtime-server) , 欢迎交流 147 | 148 | 注 : 项目中使用 tab 缩进且设置了tab = 2 space 149 | 150 | 几乎每个段落都有注释, 且关键数据结构还带有图解, 比如 : 151 | 152 | ``` 153 | ... 154 | // 155 | // kcp发送的数据包设计了自己的包结构,包头一共24bytes,包含了一些必要的信息,具体内容和大小如下: 156 | // 157 | // |<------------ 4 bytes ------------>| 158 | // +--------+--------+--------+--------+ 159 | // | conv | conv:Conversation, 会话序号,用于标识收发数据包是否一致 160 | // +--------+--------+--------+--------+ cmd: Command, 指令类型,代表这个Segment的类型 161 | // | cmd | frg | wnd | frg: Fragment, 分段序号,分段从大到小,0代表数据包接收完毕 162 | // +--------+--------+--------+--------+ wnd: Window, 窗口大小 163 | // | ts | ts: Timestamp, 发送的时间戳 164 | // +--------+--------+--------+--------+ 165 | // | sn | sn: Sequence Number, Segment序号 166 | // +--------+--------+--------+--------+ 167 | // | una | una: Unacknowledged, 当前未收到的序号, 168 | // +--------+--------+--------+--------+ 即代表这个序号之前的包均收到 169 | // | len | len: Length, 后续数据的长度 170 | // +--------+--------+--------+--------+ 171 | // 172 | ... 173 | 174 | //--------------------------------------------------------------------- 175 | // ... 176 | // rcv_queue 接收消息的队列, rcv_queue的数据是连续的,rcv_buf可能是间隔的 177 | // nrcv_que // 接收队列rcv_queue中的Segment数量, 需要小于 rcv_wnd 178 | // rcv_queue 如下图所示 179 | // +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ 180 | // ... | 2 | 3 | 4 | ............................................... 181 | // +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ 182 | // ^ ^ ^ 183 | // | | | 184 | // rcv_nxt rcv_nxt + nrcv_que rcv_nxt + rcv_wnd 185 | // 186 | // snd_buf 发送消息的缓存 187 | // snd_buf 如下图所示 188 | // +---+---+---+---+---+---+---+---+---+---+---+---+---+ 189 | // ... | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | ........... 190 | // +---+---+---+---+---+---+---+---+---+---+---+---+---+ 191 | // ^ ^ ^ 192 | // | | | 193 | // snd_una snd_nxt snd_una + snd_wnd 194 | // 195 | // 196 | // rcv_buf 接收消息的缓存 197 | // rcv_buf 如下图所示, rcv_queue的数据是连续的,rcv_buf可能是间隔的 198 | // +---+---+---+---+---+---+---+---+---+---+---+---+---+ 199 | // ... | 2 | 4 | 6 | 7 | 8 | 9 | ........... 200 | // +---+---+---+---+---+---+---+---+---+---+---+---+---+ 201 | // 202 | ... 203 | ``` 204 | -------------------------------------------------------------------------------- /ikcp.c: -------------------------------------------------------------------------------- 1 | //===================================================================== 2 | // 3 | // KCP - A Better ARQ Protocol Implementation 4 | // skywind3000 (at) gmail.com, 2010-2011 5 | // 6 | // Features: 7 | // + Average RTT reduce 30% - 40% vs traditional ARQ like tcp. 8 | // + Maximum RTT reduce three times vs tcp. 9 | // + Lightweight, distributed as a single source file. 10 | // 11 | //===================================================================== 12 | #include "ikcp.h" 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | //===================================================================== 21 | // KCP BASIC 22 | //===================================================================== 23 | const IUINT32 IKCP_RDC_CHK_INTERVAL = 100; 24 | const IUINT32 IKCP_RDC_RTT_LIMIT = 111; 25 | const IUINT32 IKCP_RDC_CLOSE_TRY_THRESHOLD = 26; 26 | const IUINT32 IKCP_RDC_LOSS_RATE_LIMIT = 5; 27 | 28 | const IUINT32 IKCP_RTO_NDL = 30; // no delay min rto 29 | const IUINT32 IKCP_RTO_MIN = 100; // normal min rto 30 | const IUINT32 IKCP_RTO_DEF = 200; 31 | const IUINT32 IKCP_RTO_MAX = 60000; 32 | const IUINT32 IKCP_CMD_PUSH = 81; // cmd: push data 33 | const IUINT32 IKCP_CMD_ACK = 82; // cmd: ack 34 | const IUINT32 IKCP_CMD_WASK = 83; // cmd: window probe (ask) 35 | const IUINT32 IKCP_CMD_WINS = 84; // cmd: window size (tell) 36 | const IUINT32 IKCP_ASK_SEND = 1; // need to send IKCP_CMD_WASK 37 | const IUINT32 IKCP_ASK_TELL = 2; // need to send IKCP_CMD_WINS 38 | const IUINT32 IKCP_WND_SND = 32; 39 | const IUINT32 IKCP_WND_RCV = 128; // must >= max fragment size 40 | const IUINT32 IKCP_MTU_DEF = 1400; 41 | const IUINT32 IKCP_ACK_FAST = 3; 42 | const IUINT32 IKCP_INTERVAL = 100; 43 | const IUINT32 IKCP_OVERHEAD = 24; // kcp设计了自己的包结构 IKCPSEG,包头一共24bytes 44 | const IUINT32 IKCP_DEADLINK = 20; 45 | const IUINT32 IKCP_THRESH_INIT = 2; 46 | const IUINT32 IKCP_THRESH_MIN = 2; 47 | const IUINT32 IKCP_PROBE_INIT = 7000; // 7 secs to probe window size 48 | const IUINT32 IKCP_PROBE_LIMIT = 120000; // up to 120 secs to probe window 49 | 50 | 51 | //--------------------------------------------------------------------- 52 | // encode / decode 53 | //--------------------------------------------------------------------- 54 | 55 | /* encode 8 bits unsigned int */ 56 | static inline char *ikcp_encode8u(char *p, unsigned char c) 57 | { 58 | *(unsigned char*)p++ = c; 59 | return p; 60 | } 61 | 62 | /* decode 8 bits unsigned int */ 63 | static inline const char *ikcp_decode8u(const char *p, unsigned char *c) 64 | { 65 | *c = *(unsigned char*)p++; 66 | return p; 67 | } 68 | 69 | /* encode 16 bits unsigned int (lsb) */ 70 | static inline char *ikcp_encode16u(char *p, unsigned short w) 71 | { 72 | #if IWORDS_BIG_ENDIAN 73 | *(unsigned char*)(p + 0) = (w & 255); 74 | *(unsigned char*)(p + 1) = (w >> 8); 75 | #else 76 | *(unsigned short*)(p) = w; 77 | #endif 78 | p += 2; 79 | return p; 80 | } 81 | 82 | /* decode 16 bits unsigned int (lsb) */ 83 | static inline const char *ikcp_decode16u(const char *p, unsigned short *w) 84 | { 85 | #if IWORDS_BIG_ENDIAN 86 | *w = *(const unsigned char*)(p + 1); 87 | *w = *(const unsigned char*)(p + 0) + (*w << 8); 88 | #else 89 | *w = *(const unsigned short*)p; 90 | #endif 91 | p += 2; 92 | return p; 93 | } 94 | 95 | /* encode 32 bits unsigned int (lsb) */ 96 | static inline char *ikcp_encode32u(char *p, IUINT32 l) 97 | { 98 | #if IWORDS_BIG_ENDIAN 99 | *(unsigned char*)(p + 0) = (unsigned char)((l >> 0) & 0xff); 100 | *(unsigned char*)(p + 1) = (unsigned char)((l >> 8) & 0xff); 101 | *(unsigned char*)(p + 2) = (unsigned char)((l >> 16) & 0xff); 102 | *(unsigned char*)(p + 3) = (unsigned char)((l >> 24) & 0xff); 103 | #else 104 | *(IUINT32*)p = l; 105 | #endif 106 | p += 4; 107 | return p; 108 | } 109 | 110 | /* decode 32 bits unsigned int (lsb) */ 111 | static inline const char *ikcp_decode32u(const char *p, IUINT32 *l) 112 | { 113 | #if IWORDS_BIG_ENDIAN 114 | *l = *(const unsigned char*)(p + 3); 115 | *l = *(const unsigned char*)(p + 2) + (*l << 8); 116 | *l = *(const unsigned char*)(p + 1) + (*l << 8); 117 | *l = *(const unsigned char*)(p + 0) + (*l << 8); 118 | #else 119 | *l = *(const IUINT32*)p; 120 | #endif 121 | p += 4; 122 | return p; 123 | } 124 | 125 | static inline IUINT32 _imin_(IUINT32 a, IUINT32 b) { 126 | return a <= b ? a : b; 127 | } 128 | 129 | static inline IUINT32 _imax_(IUINT32 a, IUINT32 b) { 130 | return a >= b ? a : b; 131 | } 132 | 133 | static inline IUINT32 _ibound_(IUINT32 lower, IUINT32 middle, IUINT32 upper) 134 | { 135 | return _imin_(_imax_(lower, middle), upper); 136 | } 137 | 138 | static inline long _itimediff(IUINT32 later, IUINT32 earlier) 139 | { 140 | return ((IINT32)(later - earlier)); 141 | } 142 | 143 | //--------------------------------------------------------------------- 144 | // manage segment 145 | //--------------------------------------------------------------------- 146 | typedef struct IKCPSEG IKCPSEG; 147 | 148 | static void* (*ikcp_malloc_hook)(size_t) = NULL; 149 | static void (*ikcp_free_hook)(void *) = NULL; 150 | 151 | // internal malloc 152 | static void* ikcp_malloc(size_t size) { 153 | if (ikcp_malloc_hook) 154 | return ikcp_malloc_hook(size); 155 | return malloc(size); 156 | } 157 | 158 | // internal free 159 | static void ikcp_free(void *ptr) { 160 | if (ikcp_free_hook) { 161 | ikcp_free_hook(ptr); 162 | } else { 163 | free(ptr); 164 | } 165 | } 166 | 167 | // redefine allocator 168 | void ikcp_allocator(void* (*new_malloc)(size_t), void (*new_free)(void*)) 169 | { 170 | ikcp_malloc_hook = new_malloc; 171 | ikcp_free_hook = new_free; 172 | } 173 | 174 | // allocate a new kcp segment 175 | static IKCPSEG* ikcp_segment_new(ikcpcb *kcp, int size) 176 | { 177 | return (IKCPSEG*)ikcp_malloc(sizeof(IKCPSEG) + size); 178 | } 179 | 180 | // delete a segment 181 | static void ikcp_segment_delete(ikcpcb *kcp, IKCPSEG *seg) 182 | { 183 | ikcp_free(seg); 184 | } 185 | 186 | // write log 187 | void ikcp_log(ikcpcb *kcp, int mask, const char *fmt, ...) 188 | { 189 | char buffer[1024]; 190 | va_list argptr; 191 | if ((mask & kcp->logmask) == 0 || kcp->writelog == 0) return; 192 | va_start(argptr, fmt); 193 | vsprintf(buffer, fmt, argptr); 194 | va_end(argptr); 195 | kcp->writelog(buffer, kcp, kcp->user); 196 | } 197 | 198 | // check log mask 199 | static int ikcp_canlog(const ikcpcb *kcp, int mask) 200 | { 201 | if ((mask & kcp->logmask) == 0 || kcp->writelog == NULL) return 0; 202 | return 1; 203 | } 204 | 205 | // output segment 206 | static int ikcp_output(ikcpcb *kcp, const void *data, int size) 207 | { 208 | assert(kcp); 209 | assert(kcp->output); 210 | if (ikcp_canlog(kcp, IKCP_LOG_OUTPUT)) { 211 | ikcp_log(kcp, IKCP_LOG_OUTPUT, "[RO] %ld bytes", (long)size); 212 | } 213 | if (size == 0) return 0; 214 | return kcp->output((const char*)data, size, kcp, kcp->user); 215 | } 216 | 217 | // output queue 218 | void ikcp_qprint(const char *name, const struct IQUEUEHEAD *head) 219 | { 220 | #if 0 221 | const struct IQUEUEHEAD *p; 222 | printf("<%s>: [", name); 223 | for (p = head->next; p != head; p = p->next) { 224 | const IKCPSEG *seg = iqueue_entry(p, const IKCPSEG, node); 225 | printf("(%lu %d)", (unsigned long)seg->sn, (int)(seg->ts % 10000)); 226 | if (p->next != head) printf(","); 227 | } 228 | printf("]\n"); 229 | #endif 230 | } 231 | 232 | 233 | //--------------------------------------------------------------------- 234 | // create a new kcpcb 235 | // 首先需要创建一个kcp用于管理接下来的工作过程, 236 | // 在创建的时候,默认的发送、接收以及远端的窗口大小均为32, 237 | // mtu大小为1400bytes,mss为1400-24=1376bytes, 238 | // 超时重传时间为200毫秒,最小重传时间为100毫秒, 239 | // kcp内部间隔最小时间为100毫秒(kcp->interval = IKCP_INTERVAL;), 240 | // 最大重发次数 dead_link 为IKCP_DEADLINK即20。 241 | //--------------------------------------------------------------------- 242 | ikcpcb* ikcp_create(IUINT32 conv, void *user) 243 | { 244 | ikcpcb *kcp = (ikcpcb*)ikcp_malloc(sizeof(struct IKCPCB)); 245 | if (kcp == NULL) return NULL; 246 | 247 | kcp->rdc_check_ts = 0; 248 | kcp->rdc_check_interval = IKCP_RDC_CHK_INTERVAL; 249 | kcp->rdc_rtt_limit = IKCP_RDC_RTT_LIMIT; 250 | kcp->is_rdc_on = 0; 251 | kcp->rdc_close_try_times = 0; 252 | kcp->rdc_close_try_threshold = IKCP_RDC_CLOSE_TRY_THRESHOLD; 253 | kcp->snd_sum = 0; 254 | kcp->timeout_resnd_cnt = 0; 255 | kcp->loss_rate = 0; 256 | kcp->rdc_loss_rate_limit = IKCP_RDC_LOSS_RATE_LIMIT; 257 | 258 | kcp->conv = conv; 259 | kcp->user = user; 260 | kcp->snd_una = 0; 261 | kcp->snd_nxt = 0; 262 | kcp->rcv_nxt = 0; 263 | kcp->ts_probe = 0; 264 | kcp->probe_wait = 0; 265 | kcp->snd_wnd = IKCP_WND_SND; 266 | kcp->rcv_wnd = IKCP_WND_RCV; 267 | kcp->rmt_wnd = IKCP_WND_RCV; 268 | kcp->cwnd = 0; 269 | kcp->incr = 0; 270 | kcp->probe = 0; 271 | kcp->mtu = IKCP_MTU_DEF; 272 | kcp->mss = kcp->mtu - IKCP_OVERHEAD; 273 | kcp->stream = 0; 274 | 275 | kcp->buffer = (char*)ikcp_malloc((kcp->mtu + IKCP_OVERHEAD) * 3); 276 | if (kcp->buffer == NULL) { 277 | ikcp_free(kcp); 278 | return NULL; 279 | } 280 | 281 | iqueue_init(&kcp->snd_queue); 282 | iqueue_init(&kcp->rcv_queue); 283 | iqueue_init(&kcp->snd_buf); 284 | iqueue_init(&kcp->rcv_buf); 285 | kcp->nrcv_buf = 0; 286 | kcp->nsnd_buf = 0; 287 | kcp->nrcv_que = 0; 288 | kcp->nsnd_que = 0; 289 | kcp->state = 0; 290 | kcp->acklist = NULL; 291 | kcp->ackblock = 0; 292 | kcp->ackcount = 0; 293 | kcp->rx_srtt = 0; 294 | kcp->rx_rttval = 0; 295 | kcp->rx_rto = IKCP_RTO_DEF; 296 | kcp->rx_minrto = IKCP_RTO_MIN; 297 | kcp->current = 0; 298 | kcp->interval = IKCP_INTERVAL; 299 | kcp->ts_flush = IKCP_INTERVAL; 300 | kcp->nodelay = 0; 301 | kcp->updated = 0; 302 | kcp->logmask = 0; 303 | kcp->ssthresh = IKCP_THRESH_INIT; 304 | kcp->fastresend = 0; 305 | kcp->nocwnd = 0; 306 | kcp->dead_link = IKCP_DEADLINK; 307 | kcp->output = NULL; 308 | kcp->writelog = NULL; 309 | 310 | return kcp; 311 | } 312 | 313 | 314 | //--------------------------------------------------------------------- 315 | // release a new kcpcb 316 | //--------------------------------------------------------------------- 317 | void ikcp_release(ikcpcb *kcp) 318 | { 319 | assert(kcp); 320 | if (kcp) { 321 | IKCPSEG *seg; 322 | while (!iqueue_is_empty(&kcp->snd_buf)) { 323 | seg = iqueue_entry(kcp->snd_buf.next, IKCPSEG, node); 324 | iqueue_del(&seg->node); 325 | ikcp_segment_delete(kcp, seg); 326 | } 327 | while (!iqueue_is_empty(&kcp->rcv_buf)) { 328 | seg = iqueue_entry(kcp->rcv_buf.next, IKCPSEG, node); 329 | iqueue_del(&seg->node); 330 | ikcp_segment_delete(kcp, seg); 331 | } 332 | while (!iqueue_is_empty(&kcp->snd_queue)) { 333 | seg = iqueue_entry(kcp->snd_queue.next, IKCPSEG, node); 334 | iqueue_del(&seg->node); 335 | ikcp_segment_delete(kcp, seg); 336 | } 337 | while (!iqueue_is_empty(&kcp->rcv_queue)) { 338 | seg = iqueue_entry(kcp->rcv_queue.next, IKCPSEG, node); 339 | iqueue_del(&seg->node); 340 | ikcp_segment_delete(kcp, seg); 341 | } 342 | if (kcp->buffer) { 343 | ikcp_free(kcp->buffer); 344 | } 345 | if (kcp->acklist) { 346 | ikcp_free(kcp->acklist); 347 | } 348 | 349 | kcp->nrcv_buf = 0; 350 | kcp->nsnd_buf = 0; 351 | kcp->nrcv_que = 0; 352 | kcp->nsnd_que = 0; 353 | kcp->ackcount = 0; 354 | kcp->buffer = NULL; 355 | kcp->acklist = NULL; 356 | ikcp_free(kcp); 357 | } 358 | } 359 | 360 | 361 | //--------------------------------------------------------------------- 362 | // set output callback, which will be invoked by kcp 363 | //--------------------------------------------------------------------- 364 | void ikcp_setoutput(ikcpcb *kcp, int (*output)(const char *buf, int len, 365 | ikcpcb *kcp, void *user)) 366 | { 367 | kcp->output = output; 368 | } 369 | 370 | 371 | //--------------------------------------------------------------------- 372 | // user/upper level recv: returns size, returns below zero for EAGAIN 373 | // kcp_recv函数,用户获取接收到数据(去除kcp头的用户数据)。 374 | // 该函数根据frg,把kcp包数据进行组合返回给用户。 375 | // 376 | // 上层调用kcp的receive函数, 377 | // 会将rcv_queue中的数据分段整理好填入用户数据区(即 ikcp_recv 函数中的形参char *buffer)中, 378 | // 然后删除对应的Segment,在做数据转移前会先计算一遍本次数据包的总大小, 379 | // 只有大小合适时才会用户才会收到数据。 380 | // 381 | // 然后在接收缓冲区中寻找下一个需要接收的Segment, 382 | // 如果找到则将该Segment转移到rcv_queue中等待下次用户再调用receive接收数据 。 383 | // 384 | // 需要注意的是,Segment在从buf转到queue中时会确保转移的Segment的sn号为下次需要接收的, 385 | // 否则将不做转移,rcv_queue 的数据是连续的,rcv_buf 可能是间隔的 386 | // 387 | // 之后根据用户接收数据后的窗口变化来告诉远端进行窗口恢复。 388 | //--------------------------------------------------------------------- 389 | int ikcp_recv(ikcpcb *kcp, char *buffer, int len) 390 | { 391 | struct IQUEUEHEAD *p; 392 | int ispeek = (len < 0)? 1 : 0; 393 | int peeksize; 394 | int recover = 0; 395 | IKCPSEG *seg; 396 | assert(kcp); 397 | 398 | if (iqueue_is_empty(&kcp->rcv_queue)) 399 | return -1; 400 | 401 | if (len < 0) len = -len; 402 | 403 | peeksize = ikcp_peeksize(kcp); 404 | 405 | if (peeksize < 0) 406 | return -2; 407 | 408 | if (peeksize > len) 409 | return -3; 410 | 411 | // 首先检测一下本次接收数据之后,是否需要进行窗口恢复。 412 | // 在前面的内容中解释过,KCP 协议在远端窗口为0的时候将会停止发送数据, 413 | // 此时如果远端调用 ikcp_recv 将数据从 rcv_queue 中移动到应用层 buffer 中之后, 414 | // 表明其可以再次接受数据,为了能够恢复数据的发送, 415 | // 远端可以主动发送 IKCP_ASK_TELL 来告知窗口大小 416 | if (kcp->nrcv_que >= kcp->rcv_wnd) // 判断当前是否可用窗口为0 417 | recover = 1; // 标记可以开始窗口恢复 418 | 419 | // merge fragment 420 | // 拷贝rcv_queue到用户buffer 421 | // 先将 rcv_queue 中的数据根据分片编号 frg merge 起来, 422 | // 然后拷贝到用户的 buffer 中。循环遍历 rcv_queue, 423 | // 按序拷贝数据,当碰到某个 segment 的 frg 为 0 时跳出循环, 424 | // 表明本次数据接收结束。这点应该很好理解,经过 ikcp_send 发送的数据会进行分片, 425 | // 分片编号为倒序序号,因此 frg 为 0 的数据包标记着完整接收到了一次 send 发送过来的数据; 426 | for (len = 0, p = kcp->rcv_queue.next; p != &kcp->rcv_queue; ) { 427 | int fragment; 428 | seg = iqueue_entry(p, IKCPSEG, node); 429 | p = p->next; 430 | 431 | if (buffer) { 432 | memcpy(buffer, seg->data, seg->len); 433 | buffer += seg->len; 434 | } 435 | 436 | len += seg->len; 437 | fragment = seg->frg; 438 | 439 | if (ikcp_canlog(kcp, IKCP_LOG_RECV)) { 440 | ikcp_log(kcp, IKCP_LOG_RECV, "recv sn=%lu", seg->sn); 441 | } 442 | 443 | if (ispeek == 0) { 444 | iqueue_del(&seg->node); 445 | ikcp_segment_delete(kcp, seg); 446 | kcp->nrcv_que--; 447 | } 448 | 449 | if (fragment == 0) 450 | break; 451 | } 452 | 453 | assert(len == peeksize); 454 | 455 | // move available data from rcv_buf -> rcv_queue 456 | // 下一步将 rcv_buf 中的数据转移到 rcv_queue 中, 457 | // 这个过程根据报文的 sn 编号来确保转移到 rcv_queue 中的数据一定是按序的: 458 | while (! iqueue_is_empty(&kcp->rcv_buf)) { 459 | IKCPSEG *seg = iqueue_entry(kcp->rcv_buf.next, IKCPSEG, node); 460 | if (seg->sn == kcp->rcv_nxt && kcp->nrcv_que < kcp->rcv_wnd) { 461 | iqueue_del(&seg->node); 462 | kcp->nrcv_buf--; 463 | iqueue_add_tail(&seg->node, &kcp->rcv_queue); 464 | kcp->nrcv_que++; 465 | kcp->rcv_nxt++; 466 | } else { 467 | break; 468 | } 469 | } 470 | 471 | // fast recover 472 | // 最后进行窗口恢复。此时如果 recover 标记为1,表明在此次接收之前, 473 | // 可用接收窗口为0,如果经过本次接收之后,可用窗口大于0, 474 | // 将主动发送 IKCP_ASK_TELL 数据包来通知对方已可以接收数据: 475 | if (kcp->nrcv_que < kcp->rcv_wnd && recover) { 476 | // ready to send back IKCP_CMD_WINS in ikcp_flush 477 | // tell remote my window size 478 | kcp->probe |= IKCP_ASK_TELL; 479 | } 480 | 481 | return len; 482 | } 483 | 484 | 485 | //--------------------------------------------------------------------- 486 | // peek data size 487 | //--------------------------------------------------------------------- 488 | int ikcp_peeksize(const ikcpcb *kcp) 489 | { 490 | struct IQUEUEHEAD *p; 491 | IKCPSEG *seg; 492 | int length = 0; 493 | 494 | assert(kcp); 495 | 496 | if (iqueue_is_empty(&kcp->rcv_queue)) 497 | return -1; 498 | 499 | seg = iqueue_entry(kcp->rcv_queue.next, IKCPSEG, node); 500 | if (seg->frg == 0) return seg->len; 501 | 502 | if (kcp->nrcv_que < seg->frg + 1) 503 | return -1; 504 | 505 | for (p = kcp->rcv_queue.next; p != &kcp->rcv_queue; p = p->next) { 506 | seg = iqueue_entry(p, IKCPSEG, node); 507 | length += seg->len; 508 | if (seg->frg == 0) break; 509 | } 510 | 511 | return length; 512 | } 513 | 514 | 515 | //--------------------------------------------------------------------- 516 | // user/upper level send, returns below zero for error 517 | // 518 | // 该函数的功能非常简单,把用户发送的数据根据MSS进行分片。 519 | // 用户发送1900字节的数据,MTU为1400byte。 520 | // 因此,该函数会把1900byte的用户数据分成两个包,一个数据大小为1400,头frg设置为1, 521 | // len设置为1400;第二个包,头frg设置为0,len设置为500。 522 | // 切好KCP包之后,放入到名为snd_queue的待发送队列中。 523 | // 注: 524 | // - 流模式情况下,kcp会把两次发送的数据衔接为一个完整的kcp包。 525 | // - 非流模式下,用户数据%MSS的包,也会作为一个包发送出去。 526 | // 527 | // 当设置好输出函数之后,上层应用可以调用 ikcp_send 来发送数据。 528 | // ikcpcb 中定义了发送相关的缓冲队列和 buf,分别是 snd_queue 和 snd_buf。 529 | // 应用层调用 ikcp_send 后,数据将会进入到 snd_queue 中, 530 | // 而下层函数 ikcp_flush 将会决定将多少数据从 snd_queue 中移到 snd_buf 中, 531 | // 进行发送。 532 | // 533 | // 我们首先来看 ikcp_send 的主要功能 : 534 | // 535 | // kcp发送的数据包分为2种模式,包模式和流模式。 536 | // 537 | // - 在包模式下 : 538 | // 数据按照用户单次的send数据分界,记录Segment到send_queue中, 539 | // 单次数据量超过mss大小将进行分片处理, 540 | // 分片内的frg记录分片序号,从大到小,0代表本次数据的结束。 541 | // - 在流模式下 : 542 | // kcp会将用户的数据全部拼接在一起, 543 | // 上一次send的数据Segment后如果有空间就将新数据补充进末尾, 544 | // 剩余数据再创建新的Segment。send的过程就是将用户数据转移到Segment, 545 | // 然后添加到发送队列中。 546 | // 547 | // 以mss为依据对用户数据分segment (即分片过程fragment) : 548 | // - 消息模式,数据分片赋予独立id,依次放入snd_queue,接收方按照id解分片数据,分片大小 <= mss 549 | // - 流模式,检测上一个分片是否达到mss,如未达到则填充,利用率高一些 550 | //--------------------------------------------------------------------- 551 | int ikcp_send(ikcpcb *kcp, const char *buffer, int len) 552 | { 553 | IKCPSEG *seg; 554 | int count, i; 555 | 556 | assert(kcp->mss > 0); 557 | if (len < 0) return -1; 558 | 559 | // append to previous segment in streaming mode (if possible) 560 | // 1. 如果当前的 KCP 开启流模式,取出 `snd_queue` 中的最后一个报文(即 kcp->snd_queue.prev) 561 | // 将其填充到 mss 的长度,并设置其 frg 为 0. 562 | if (kcp->stream != 0) { 563 | if (!iqueue_is_empty(&kcp->snd_queue)) { 564 | IKCPSEG *old = iqueue_entry(kcp->snd_queue.prev, IKCPSEG, node); 565 | if (old->len < kcp->mss) { 566 | int capacity = kcp->mss - old->len; 567 | int extend = (len < capacity)? len : capacity; 568 | seg = ikcp_segment_new(kcp, old->len + extend); 569 | assert(seg); 570 | if (seg == NULL) { 571 | return -2; 572 | } 573 | iqueue_add_tail(&seg->node, &kcp->snd_queue); 574 | memcpy(seg->data, old->data, old->len); 575 | if (buffer) { 576 | memcpy(seg->data + old->len, buffer, extend); 577 | buffer += extend; 578 | } 579 | seg->len = old->len + extend; 580 | seg->frg = 0; 581 | len -= extend; 582 | iqueue_del_init(&old->node); 583 | ikcp_segment_delete(kcp, old); 584 | } 585 | } 586 | if (len <= 0) { 587 | return 0; 588 | } 589 | } 590 | 591 | // 2. 计算剩下的数据需要分成几段 592 | if (len <= (int)kcp->mss) count = 1; 593 | else count = (len + kcp->mss - 1) / kcp->mss; 594 | 595 | if ((IUINT32)count >= IKCP_WND_RCV) return -2; 596 | 597 | if (count == 0) count = 1; 598 | 599 | // fragment 600 | // 3. 为剩下的数据创建 KCP segment 601 | for (i = 0; i < count; i++) { 602 | int size = len > (int)kcp->mss ? (int)kcp->mss : len; 603 | seg = ikcp_segment_new(kcp, size); 604 | assert(seg); 605 | if (seg == NULL) { 606 | return -2; 607 | } 608 | if (buffer && len > 0) { 609 | memcpy(seg->data, buffer, size); 610 | } 611 | seg->len = size; 612 | // frg用来表示被分片的序号,从大到小递减; 流模式情况下分片编号不用填写 613 | seg->frg = (kcp->stream == 0)? (count - i - 1) : 0; 614 | iqueue_init(&seg->node); 615 | iqueue_add_tail(&seg->node, &kcp->snd_queue); // 加入到 snd_queue 中 616 | kcp->nsnd_que++; 617 | if (buffer) { 618 | buffer += size; 619 | } 620 | len -= size; 621 | } 622 | 623 | return 0; 624 | } 625 | 626 | 627 | //--------------------------------------------------------------------- 628 | // parse ack 629 | //** 更新ack 630 | //** 此处实际上是在更新rto, 631 | //** 因为此时收到远端的ack,所以我们知道远端的包到本机的时间,因此可统计当前的网速如何,进行调整 632 | //--------------------------------------------------------------------- 633 | static void ikcp_update_ack(ikcpcb *kcp, IINT32 rtt) 634 | { 635 | IINT32 rto = 0; 636 | if (kcp->rx_srtt == 0) { 637 | kcp->rx_srtt = rtt; 638 | kcp->rx_rttval = rtt / 2; 639 | } else { 640 | long delta = rtt - kcp->rx_srtt; 641 | if (delta < 0) delta = -delta; 642 | kcp->rx_rttval = (3 * kcp->rx_rttval + delta) / 4; 643 | kcp->rx_srtt = (7 * kcp->rx_srtt + rtt) / 8; 644 | if (kcp->rx_srtt < 1) kcp->rx_srtt = 1; 645 | } 646 | rto = kcp->rx_srtt + _imax_(kcp->interval, 4 * kcp->rx_rttval); 647 | kcp->rx_rto = _ibound_(kcp->rx_minrto, rto, IKCP_RTO_MAX); 648 | } 649 | 650 | //** 更新本地 snd_una 数据,如snd_buf为空,snd_una 指向 snd_nxt,否则指向 snd_buf 首端 651 | static void ikcp_shrink_buf(ikcpcb *kcp) 652 | { 653 | struct IQUEUEHEAD *p = kcp->snd_buf.next; 654 | if (p != &kcp->snd_buf) { // 若snd_buff不为空 655 | IKCPSEG *seg = iqueue_entry(p, IKCPSEG, node); 656 | kcp->snd_una = seg->sn; // snd_una指向snd_buf首端 657 | } else { // 如snd_buf为空,snd_una指向snd_nxt 658 | kcp->snd_una = kcp->snd_nxt; 659 | } 660 | } 661 | 662 | //** 分析具体是哪个segment被收到了,将其从snd_buf中移除 663 | static void ikcp_parse_ack(ikcpcb *kcp, IUINT32 sn) 664 | { 665 | struct IQUEUEHEAD *p, *next; 666 | 667 | // sn小于snd_una或大于等于snd_nxt,忽略该包,snd_una之前是完备的,snd_nxt之后未发送,不应收到ack 668 | if (_itimediff(sn, kcp->snd_una) < 0 || _itimediff(sn, kcp->snd_nxt) >= 0) 669 | return; 670 | 671 | for (p = kcp->snd_buf.next; p != &kcp->snd_buf; p = next) { 672 | IKCPSEG *seg = iqueue_entry(p, IKCPSEG, node); 673 | next = p->next; 674 | if (sn == seg->sn) { 675 | iqueue_del(p); 676 | ikcp_segment_delete(kcp, seg); 677 | kcp->nsnd_buf--; 678 | break; 679 | } 680 | if (_itimediff(sn, seg->sn) < 0) { 681 | break; 682 | } 683 | } 684 | } 685 | 686 | // 分析una,看哪些segment远端收到了,删除send_buf中小于una的segment 687 | static void ikcp_parse_una(ikcpcb *kcp, IUINT32 una) 688 | { 689 | struct IQUEUEHEAD *p, *next; 690 | for (p = kcp->snd_buf.next; p != &kcp->snd_buf; p = next) { 691 | 692 | IKCPSEG *seg = iqueue_entry(p, IKCPSEG, node); 693 | 694 | next = p->next; 695 | if (_itimediff(una, seg->sn) > 0) { 696 | iqueue_del(p); 697 | ikcp_segment_delete(kcp, seg); 698 | kcp->nsnd_buf--; 699 | } else { 700 | break; 701 | } 702 | } 703 | } 704 | 705 | // 根据遍历snd_buf队列更新各个Segment中ack跳过的次数, 706 | // 也就是说, 若Segment的sn小于接收到的ack包的sn, 则Segment的fastack ++, 707 | // 用于之后判断是否需要快速重传, 708 | // 若fastack超过指定阈值,则启动快速重传 709 | static void ikcp_parse_fastack(ikcpcb *kcp, IUINT32 sn) 710 | { 711 | struct IQUEUEHEAD *p, *next; 712 | 713 | if (_itimediff(sn, kcp->snd_una) < 0 || _itimediff(sn, kcp->snd_nxt) >= 0) 714 | return; 715 | 716 | for (p = kcp->snd_buf.next; p != &kcp->snd_buf; p = next) { 717 | IKCPSEG *seg = iqueue_entry(p, IKCPSEG, node); 718 | next = p->next; 719 | if (_itimediff(sn, seg->sn) < 0) { 720 | break; 721 | } 722 | else if (sn != seg->sn) { // 若seg的sn小于接收到的所有ack包中的最大sn 723 | seg->fastack++; 724 | } 725 | } 726 | } 727 | 728 | 729 | //--------------------------------------------------------------------- 730 | // ack append 731 | //** push当前包的ack给远端(会在flush中发送ack出去) 732 | // 调用 ikcp_ack_push 将对该报文的确认 ACK 报文放入 ACK 列表acklist中 733 | //--------------------------------------------------------------------- 734 | static void ikcp_ack_push(ikcpcb *kcp, IUINT32 sn, IUINT32 ts) 735 | { 736 | size_t newsize = kcp->ackcount + 1; 737 | IUINT32 *ptr; 738 | 739 | if (newsize > kcp->ackblock) { 740 | IUINT32 *acklist; 741 | size_t newblock; 742 | 743 | for (newblock = 8; newblock < newsize; newblock <<= 1); // newblock <<= 1 等价于 newblock *= 2; 744 | acklist = (IUINT32*)ikcp_malloc(newblock * sizeof(IUINT32) * 2); 745 | 746 | if (acklist == NULL) { 747 | assert(acklist != NULL); 748 | abort(); 749 | } 750 | 751 | if (kcp->acklist != NULL) { 752 | size_t x; 753 | for (x = 0; x < kcp->ackcount; x++) { 754 | acklist[x * 2 + 0] = kcp->acklist[x * 2 + 0]; 755 | acklist[x * 2 + 1] = kcp->acklist[x * 2 + 1]; 756 | } 757 | ikcp_free(kcp->acklist); 758 | } 759 | 760 | kcp->acklist = acklist; 761 | kcp->ackblock = newblock; 762 | } 763 | 764 | ptr = &kcp->acklist[kcp->ackcount * 2]; 765 | ptr[0] = sn; 766 | ptr[1] = ts; 767 | kcp->ackcount++; 768 | } 769 | 770 | static void ikcp_ack_get(const ikcpcb *kcp, int p, IUINT32 *sn, IUINT32 *ts) 771 | { 772 | if (sn) sn[0] = kcp->acklist[p * 2 + 0]; 773 | if (ts) ts[0] = kcp->acklist[p * 2 + 1]; 774 | } 775 | 776 | 777 | //--------------------------------------------------------------------- 778 | // parse data 779 | // 首先会在rcv_buf中遍历一次,判断是否已经接收过这个数据包, 780 | // 如果数据包不存在则添加到rcv_buf中,之后将可用的Segment再转移到rcv_queue中 781 | //--------------------------------------------------------------------- 782 | void ikcp_parse_data(ikcpcb *kcp, IKCPSEG *newseg) 783 | { 784 | struct IQUEUEHEAD *p, *prev; 785 | IUINT32 sn = newseg->sn; 786 | int repeat = 0; 787 | 788 | // 超出接收窗口大小了 或 rcv_queue已经接收过这个sn的数据包了 789 | if (_itimediff(sn, kcp->rcv_nxt + kcp->rcv_wnd) >= 0 || _itimediff(sn, kcp->rcv_nxt) < 0) { 790 | ikcp_segment_delete(kcp, newseg); 791 | return; 792 | } 793 | 794 | // rcv_buf 从后往前遍历,判断是否已经接收过这个数据包, 并且找到新数据newseg应该插入到 rcv_buf 的位置 795 | for (p = kcp->rcv_buf.prev; p != &kcp->rcv_buf; p = prev) { 796 | IKCPSEG *seg = iqueue_entry(p, IKCPSEG, node); 797 | prev = p->prev; 798 | 799 | // 检测是否为重复数据包 800 | if (seg->sn == sn) { 801 | repeat = 1; 802 | break; 803 | } 804 | if (_itimediff(sn, seg->sn) > 0) { 805 | break; 806 | } 807 | } 808 | 809 | if (repeat == 0) { 810 | iqueue_init(&newseg->node); 811 | iqueue_add(&newseg->node, p); // 新数据newseg插入到p的后面 812 | kcp->nrcv_buf++; 813 | } else { 814 | // 如果已经接收过了,则丢弃 815 | ikcp_segment_delete(kcp, newseg); 816 | } 817 | 818 | #if 0 819 | ikcp_qprint("rcvbuf", &kcp->rcv_buf); 820 | printf("rcv_nxt=%lu\n", kcp->rcv_nxt); 821 | #endif 822 | 823 | // move available data from rcv_buf to rcv_queue 824 | // 扫描rcv_buf,segment的id等于rcv_nxt,则rcv_nxt右移, 825 | // 同时segment移出rcv_buf移入rcv_queue,rcv_nxt的连续性保证rcv_queue的完备性 826 | while (! iqueue_is_empty(&kcp->rcv_buf)) { 827 | IKCPSEG *seg = iqueue_entry(kcp->rcv_buf.next, IKCPSEG, node); 828 | if (seg->sn == kcp->rcv_nxt && kcp->nrcv_que < kcp->rcv_wnd) { 829 | iqueue_del(&seg->node); 830 | kcp->nrcv_buf--; 831 | iqueue_add_tail(&seg->node, &kcp->rcv_queue); 832 | kcp->nrcv_que++; 833 | kcp->rcv_nxt++; 834 | } else { 835 | break; 836 | } 837 | } 838 | 839 | #if 0 840 | ikcp_qprint("queue", &kcp->rcv_queue); 841 | printf("rcv_nxt=%lu\n", kcp->rcv_nxt); 842 | #endif 843 | 844 | #if 1 845 | // printf("snd(buf=%d, queue=%d)\n", kcp->nsnd_buf, kcp->nsnd_que); 846 | // printf("rcv(buf=%d, queue=%d)\n", kcp->nrcv_buf, kcp->nrcv_que); 847 | #endif 848 | } 849 | 850 | 851 | //--------------------------------------------------------------------- 852 | // ikcp_input负责接收用户传入的底层网络数据(比如udp协议传过来的报文), 853 | // 然后把底层网络数据解码成kcp报文进行缓存。 854 | // kcp不负责网络端数据的接收, 855 | // 需要用户自己调用相关的网络操作函数进行数据包的接收,将接收到数据通过input传入kcp中。 856 | // 857 | // 相关联的成员变量有以下几个: 858 | // - UInt32 rcv_nxt 下一个要接收的数据包的编号。也就是说此序号之前的包都已经按顺序全部收到了, 859 | // 下面期望收到这个序号的包(已保证数据包的连续性、顺序性) 860 | // - UInt32 rcv_wnd 接收窗口的大小 861 | // - Segment[] rcv_buf 接收到的数据会先存放到rcv_buf中。 862 | // 因为数据可能是乱序到达本地的,所以接受到的数据会按sn顺序依次放入到对应的位置中。 863 | // 当sn从低到高连续的数据包都收到了,则将这批连续的数据包转移到 rcv_queue 中。 864 | // 这样就保证了数据包的顺序性。 865 | // - Segment[] rcv_queue 缓存接收到、连续的数据包 866 | // - UInt32[] acklist 收到包后要发送的回传确认。 867 | // 在收到包时先将要回传ack的sn放入此队列中,在 ikcp_flush 函数中再发出去。 868 | // acklist中,一个ack以(sn, timestampe)为一组的方式存储。 869 | // 即[{sn1, ts1}, { sn2,ts2 } …] 即[sn1, ts1, sn2, ts2 …] 870 | // 871 | // 对于用户传入的数据,kcp会先对数据头部进行解包,判断数据包的大小、会话序号等信息, 872 | // 同时更新远端窗口大小。通过调用 parse_una 来确认远端收到的数据包, 873 | // 将接收到的数据包从 snd_buf 中移除。然后调用shrink_buf来更新kcp中snd_una信息, 874 | // 用于告诉远端自己已经确认被接收的数据包信息。 875 | // 876 | // 之后根据不同的数据包cmd类型分别处理对应的数据包 : 877 | // 878 | // - IKCP_CMD_ACK : 对应ack包, 879 | // kcp通过判断当前接收到ack的时间戳和ack包内存储的发送时间戳来更新rtt和rto的时间。 880 | // - IKCP_CMD_PUSH : 对应数据包,kcp首先会判断sn号是否超出了当前窗口所能接收的范围, 881 | // 如果超出范围将直接丢弃这个数据包, 882 | // 如果是已经确认接收过的重复包也直接丢弃,然后将数据转移到新的Segment中, 883 | // 通过 parse_data 将Segment放入rcv_buf中, 884 | // 在 parse_data 中首先会在rcv_buf中遍历一次,判断是否已经接收过这个数据包, 885 | // 如果数据包不存在则添加到rcv_buf中,之后将可用的Segment再转移到rcv_queue中。 886 | // - IKCP_CMD_WASK : 对应远端的窗口探测包,设置probe标志,在之后发送本地窗口大小。 887 | // - IKCP_CMD_WINS : 对应远端的窗口更新包,无需做额外的操作。 888 | // 889 | // 然后根据接收到的ack遍历 snd_buf 队列更新各个Segment中ack跳过的次数,用于之后判断是否需要快速重传。 890 | // 最后进行窗口慢启动的恢复。 891 | //--------------------------------------------------------------------- 892 | int ikcp_input(ikcpcb *kcp, const char *data, long size) 893 | { 894 | IUINT32 una = kcp->snd_una; // 缓存一下当前的 snd_una 895 | IUINT32 maxack = 0; 896 | int flag = 0; 897 | 898 | if (ikcp_canlog(kcp, IKCP_LOG_INPUT)) { 899 | ikcp_log(kcp, IKCP_LOG_INPUT, "[RI] %d bytes", size); 900 | } 901 | 902 | if (data == NULL || (int)size < (int)IKCP_OVERHEAD) return -1; 903 | 904 | // Part 1 逐步解析data中的数据 905 | while (1) { 906 | IUINT32 ts, sn, len, una, conv; 907 | IUINT16 wnd; 908 | IUINT8 cmd, frg; 909 | IKCPSEG *seg; 910 | 911 | //** Part 1.1 912 | //** 解析出数据中的KCP头部 913 | // 914 | // KCP Header Format : 915 | // 916 | // 4 1 1 2 (Byte) 917 | // +---+---+---+---+---+---+---+---+ 918 | // | conv |cmd|frg| wnd | 919 | // +---+---+---+---+---+---+---+---+ 920 | // | ts | sn | 921 | // +---+---+---+---+---+---+---+---+ 922 | // | una | len | 923 | // +---+---+---+---+---+---+---+---+ 924 | // | | 925 | // + DATA + 926 | // | | 927 | // +---+---+---+---+---+---+---+---+ 928 | // 929 | if (size < (int)IKCP_OVERHEAD) break; 930 | 931 | data = ikcp_decode32u(data, &conv); 932 | if (conv != kcp->conv) return -1; 933 | 934 | data = ikcp_decode8u(data, &cmd); 935 | data = ikcp_decode8u(data, &frg); 936 | data = ikcp_decode16u(data, &wnd); 937 | data = ikcp_decode32u(data, &ts); 938 | data = ikcp_decode32u(data, &sn); 939 | data = ikcp_decode32u(data, &una); 940 | data = ikcp_decode32u(data, &len); 941 | 942 | // kcp包头一共24个字节, size减去IKCP_OVERHEAD即24个字节应该不小于len 943 | size -= IKCP_OVERHEAD; 944 | if ((long)size < (long)len) return -2; 945 | 946 | if (cmd != IKCP_CMD_PUSH && cmd != IKCP_CMD_ACK && 947 | cmd != IKCP_CMD_WASK && cmd != IKCP_CMD_WINS) 948 | return -3; 949 | 950 | //** Part 1.2 951 | //** 获得远端的窗口大小 952 | kcp->rmt_wnd = wnd; 953 | 954 | //** Part 1.3 955 | //** 分析una,看哪些segment远端收到了,删除send_buf中小于una的segment 956 | ikcp_parse_una(kcp, una); 957 | 958 | //** 更新本地 snd_una 数据,如snd_buff为空,snd_una指向snd_nxt,否则指向send_buff首端 959 | ikcp_shrink_buf(kcp); 960 | 961 | //** Part 1.4 962 | //** 如果收到的是远端发来的ACK包 963 | if (cmd == IKCP_CMD_ACK) { 964 | if (_itimediff(kcp->current, ts) >= 0) { 965 | //** 更新ack 966 | //** 此处实际上是在更新rto, 967 | //** 因为此时收到远端的ack,所以我们知道远端的包到本机的时间,因此可统计当前的网速如何,进行调整 968 | ikcp_update_ack(kcp, _itimediff(kcp->current, ts)); 969 | } 970 | 971 | //** 分析具体是哪个segment被收到了,将其从snd_buf中移除 972 | ikcp_parse_ack(kcp, sn); 973 | 974 | //** 因为snd_buf可能改变了,更新当前的 snd_una 975 | ikcp_shrink_buf(kcp); 976 | 977 | // 记录最大的ack包的sn值 978 | if (flag == 0) { 979 | flag = 1; 980 | maxack = sn; 981 | } else { 982 | if (_itimediff(sn, maxack) > 0) { 983 | maxack = sn; 984 | } 985 | } 986 | 987 | // 记录sn, rtt, rto 988 | if (ikcp_canlog(kcp, IKCP_LOG_IN_ACK)) { 989 | ikcp_log(kcp, IKCP_LOG_IN_DATA, 990 | "input ack: sn=%lu rtt=%ld rto=%ld", sn, 991 | (long)_itimediff(kcp->current, ts), 992 | (long)kcp->rx_rto); 993 | } 994 | } 995 | //** Part 1.5 996 | //** 如果收到的是远端发来的数据包 997 | else if (cmd == IKCP_CMD_PUSH) { 998 | if (ikcp_canlog(kcp, IKCP_LOG_IN_DATA)) { 999 | ikcp_log(kcp, IKCP_LOG_IN_DATA, 1000 | "input psh: sn=%lu ts=%lu", sn, ts); 1001 | } 1002 | 1003 | //** 如果还有足够多的接收窗口 1004 | if (_itimediff(sn, kcp->rcv_nxt + kcp->rcv_wnd) < 0) { 1005 | //** push当前包的ack给远端(会在flush中发送ack出去) 1006 | // 调用 ikcp_ack_push 将对该报文的确认 ACK 报文放入 ACK 列表acklist中 1007 | ikcp_ack_push(kcp, sn, ts); 1008 | 1009 | if (_itimediff(sn, kcp->rcv_nxt) >= 0) { 1010 | seg = ikcp_segment_new(kcp, len); 1011 | seg->conv = conv; 1012 | seg->cmd = cmd; 1013 | seg->frg = frg; 1014 | seg->wnd = wnd; 1015 | seg->ts = ts; 1016 | seg->sn = sn; 1017 | seg->una = una; 1018 | seg->len = len; 1019 | 1020 | if (len > 0) { 1021 | memcpy(seg->data, data, len); 1022 | } 1023 | 1024 | // 解析data, 1025 | // 首先会在rcv_buf中遍历一次,判断是否已经接收过这个数据包, 1026 | // 如果数据包不存在则添加到rcv_buf中,之后将可用的Segment再转移到rcv_queue中 1027 | ikcp_parse_data(kcp, seg); 1028 | } 1029 | } 1030 | } 1031 | //** Part 1.6 1032 | //** 如果收到的包是远端发过来询问窗口大小的包 1033 | else if (cmd == IKCP_CMD_WASK) { 1034 | // ready to send back IKCP_CMD_WINS in ikcp_flush 1035 | // tell remote my window size 1036 | kcp->probe |= IKCP_ASK_TELL; 1037 | if (ikcp_canlog(kcp, IKCP_LOG_IN_PROBE)) { 1038 | ikcp_log(kcp, IKCP_LOG_IN_PROBE, "input probe"); 1039 | } 1040 | } 1041 | // wins告知窗口大小 1042 | else if (cmd == IKCP_CMD_WINS) { 1043 | // do nothing 1044 | if (ikcp_canlog(kcp, IKCP_LOG_IN_WINS)) { 1045 | ikcp_log(kcp, IKCP_LOG_IN_WINS, 1046 | "input wins: %lu", (IUINT32)(wnd)); 1047 | } 1048 | } 1049 | else { 1050 | return -3; 1051 | } 1052 | 1053 | data += len; 1054 | size -= len; 1055 | } 1056 | 1057 | if (flag != 0) { 1058 | // 根据记录的最大ack的snd值,扫描 snd_buf ,小于max ack的segment的fastack ++, 1059 | // 在 ikcp_flush 函数中会判断是否超过指定快速重传次数阈值,超过了就会启动快速重传 1060 | ikcp_parse_fastack(kcp, maxack); 1061 | } 1062 | 1063 | // snd_una与之前缓存的 una 比较 见本函数第一行代码, 1064 | // 若 snd_una>una,说明收到了有效的una或ack之后已经更新了snd_una了, 1065 | // 接下来要做流量控制和拥塞控制 1066 | // 情况1 : cwnd < ssthresh, 慢启动阶段,cwnd++,可发送最大数据量+mss 1067 | // 情况2 : 拥塞控制阶段 1068 | if (_itimediff(kcp->snd_una, una) > 0) { 1069 | if (kcp->cwnd < kcp->rmt_wnd) { 1070 | IUINT32 mss = kcp->mss; 1071 | if (kcp->cwnd < kcp->ssthresh) { // 慢启动阶段 1072 | kcp->cwnd++; 1073 | kcp->incr += mss; 1074 | } else { // 拥塞控制阶段 1075 | if (kcp->incr < mss) 1076 | kcp->incr = mss; 1077 | kcp->incr += (mss * mss) / kcp->incr + (mss / 16); 1078 | if ((kcp->cwnd + 1) * mss <= kcp->incr) 1079 | kcp->cwnd++; 1080 | } 1081 | if (kcp->cwnd > kcp->rmt_wnd) { 1082 | kcp->cwnd = kcp->rmt_wnd; 1083 | kcp->incr = kcp->rmt_wnd * mss; 1084 | } 1085 | } 1086 | } 1087 | 1088 | return 0; 1089 | } 1090 | 1091 | 1092 | //--------------------------------------------------------------------- 1093 | // ikcp_encode_seg 1094 | //--------------------------------------------------------------------- 1095 | static char *ikcp_encode_seg(char *ptr, const IKCPSEG *seg) 1096 | { 1097 | ptr = ikcp_encode32u(ptr, seg->conv); 1098 | ptr = ikcp_encode8u(ptr, (IUINT8)seg->cmd); 1099 | ptr = ikcp_encode8u(ptr, (IUINT8)seg->frg); 1100 | ptr = ikcp_encode16u(ptr, (IUINT16)seg->wnd); 1101 | ptr = ikcp_encode32u(ptr, seg->ts); 1102 | ptr = ikcp_encode32u(ptr, seg->sn); 1103 | ptr = ikcp_encode32u(ptr, seg->una); 1104 | ptr = ikcp_encode32u(ptr, seg->len); 1105 | return ptr; 1106 | } 1107 | 1108 | static int ikcp_wnd_unused(const ikcpcb *kcp) 1109 | { 1110 | if (kcp->nrcv_que < kcp->rcv_wnd) { 1111 | return kcp->rcv_wnd - kcp->nrcv_que; // 剩余接收窗口大小(接收窗口大小-接收队列大小) 1112 | } 1113 | return 0; 1114 | } 1115 | 1116 | 1117 | //--------------------------------------------------------------------- 1118 | // ikcp_flush 1119 | // KCP.flush之发包 1120 | // 1121 | // KCP中,与发包相关联的成员变量有以下几个: 1122 | // - UInt32 snd_una 当前未收到确认回传的发送出去的包的最小编号。也就是此编号前的包都已经收到确认回传了。 1123 | // - UInt32 snd_nxt 下一个要发送出去的包编号 1124 | // - UInt32 snd_wnd 发送窗口大小 1125 | // - UInt32 rmt_wnd 远端的接收窗口大小 1126 | // - Segment[] snd_queue 发送队列。 1127 | // 应用层的数据(在调用KCP.Send后) 1128 | // 会进入此队列中,KCP在flush的时候根据发送窗口的大小, 1129 | // 再决定将多少个Segment放入到snd_buf中进行发送 1130 | // - Segment[] snd_buf 发送缓存池。 1131 | // 发送出去的数据将会呆在这个池子中, 1132 | // 等待远端的回传确认,等收到远端确认此包收到后再从snd_buf移出去。 1133 | // KCP在每次flush的时候都会检查这个缓存池中的每个Segment,如果超时或者判定丢包就会重发。 1134 | // 1135 | // Tips : 1136 | // - snd是send或者sender的缩写,发送端 1137 | // - rmt是remote的缩写,远端 1138 | // - nxt是next的缩写 1139 | // 1140 | // kcp在flush的时候将snd_queue中的内容移动到snd_buf中,然后才真正将数据发送出去。 1141 | // 1142 | // 首先kcp会发送所有ack信息,每个ack信息占用一个kcp数据包头的大小,用于存储ack的sn和ts, 1143 | // 这里的ts是在接收到数据包时存储进acklist中的ts,也就是远端发送数据包的ts。 1144 | // 1145 | // 发送完ack信息后,kcp还会检查当前是否需要对远端窗口进行探测。 1146 | // 因为kcp的流量控制依赖于远端通知其可接受窗口的大小,一旦远端接受窗口为0, 1147 | // 本地将不会再向远端发送数据,就无法从远端接收ack包,从而没有机会更新远端窗口大小。 1148 | // 在这种情况下,kcp需要发送窗口探测包到远端,待远端回复窗口大小后,后续传输才可以继续。 1149 | // 然后kcp分别根据之前的判断,选择是否发送窗口探测包和窗口更新包。 1150 | // 1151 | // 接着kcp将设置当前的发送窗口大小,如果未开启非退让流控, 1152 | // 窗口大小将有发送缓存大小、远端窗口大小以及慢启动所计算出的窗口大小决定, 1153 | // 如果开启非退让流控,则不受慢启动窗口大小的限制。 1154 | // 按照发送窗口所能容纳的大小,kcp将需要发送的Segment从snd_queue移动到snd_buf中。 1155 | // 1156 | // 然后更新快速重传的次数和重传时间延迟,为之后的数据发送做准备。 1157 | // 1158 | // kcp将遍历snd_buf队列,将发送缓冲区中需要发送的Segment逐一发送出去,有3种情况数据包需要发送: 1159 | // 1160 | // - 第一次发送:设置重传时间信息。 1161 | // - 超过重传时间:更新重传时间信息,根据kcp的设置选择rto * 2或rto*1.5,并记录lost标志。 1162 | // - ack跳过指定次数:立即重传,重置跳过次数并更新重传时间,记录change标志。 1163 | // 1164 | // 然后将这3种情况下的数据包进行发送。当一个数据包重传超过dead_link次数时, 1165 | // kcp的state将设置为 - 1。这里的state在其他函数中并没有使用到, 1166 | // 猜测可能是当kcp发送缓冲区内的数据丢失无法得到ack时,kcp将不断重传, 1167 | // 如果重传多次仍然失败,这时可以通过判断state来清理snd_buf中这些僵死的数据包, 1168 | // 放在永远占用在snd_buf中限制正常的发送窗口大小。 1169 | // 1170 | // 最后,kcp将更新慢启动的窗口大小。 1171 | //--------------------------------------------------------------------- 1172 | void ikcp_flush(ikcpcb *kcp) 1173 | { 1174 | IUINT32 current = kcp->current; 1175 | char *buffer = kcp->buffer; 1176 | char *ptr = buffer; 1177 | int count, size, i; 1178 | IUINT32 resent, cwnd; 1179 | IUINT32 rtomin; 1180 | struct IQUEUEHEAD *p; 1181 | int change = 0; // 标识快重传发生 1182 | int lost = 0; // 记录出现了报文丢失 1183 | IKCPSEG seg; 1184 | 1185 | // 'ikcp_update' haven't been called. 1186 | // 检查 kcp->update 是否更新,未更新直接返回。 1187 | // kcp->update 由 ikcp_update 更新, 1188 | // 上层应用需要每隔一段时间(10-100ms)调用 ikcp_update 来驱动 KCP 发送数据; 1189 | if (kcp->updated == 0) return; 1190 | 1191 | seg.conv = kcp->conv; 1192 | seg.cmd = IKCP_CMD_ACK; 1193 | seg.frg = 0; 1194 | seg.wnd = ikcp_wnd_unused(kcp); 1195 | seg.una = kcp->rcv_nxt; 1196 | seg.len = 0; 1197 | seg.sn = 0; 1198 | seg.ts = 0; 1199 | 1200 | // flush acknowledges 1201 | // 我们先看一下 KCP 对于 ack 报文的管理。KCP 控制块 ikcpcb 中有如下几个成员: 1202 | // - acklist: 当收到一个数据报文时,将其对应的 ACK 报文的 sn 号以及 1203 | // 时间戳 ts 同时加入到acklist 中,即形成如[sn1, ts1, sn2, ts2 …] 的列表; 1204 | // - ackcount:记录 acklist 中存放的 ACK 报文的数量; 1205 | // - ackblock:acklist 数组的可用长度,当 acklist 的容量不足时,需要进行扩容; 1206 | // 以下代码表示 : 1207 | // 准备将 acklist 中记录的 ACK 报文发送出去,即从 acklist 中填充 ACK 报文的 sn 和 ts 字段; 1208 | count = kcp->ackcount; 1209 | for (i = 0; i < count; i++) { 1210 | size = (int)(ptr - buffer); 1211 | if (size + (int)IKCP_OVERHEAD > (int)kcp->mtu) { 1212 | ikcp_output(kcp, buffer, size); 1213 | ptr = buffer; 1214 | } 1215 | ikcp_ack_get(kcp, i, &seg.sn, &seg.ts); 1216 | ptr = ikcp_encode_seg(ptr, &seg); 1217 | } 1218 | 1219 | kcp->ackcount = 0; 1220 | 1221 | // probe window size (if remote window size equals zero) 1222 | // 检查当前是否需要对远端窗口进行探测。 1223 | // 由于 KCP 流量控制依赖于远端通知其可接受窗口的大小, 1224 | // 一旦远端接受窗口 kcp->rmt_wnd 为0,那么本地将不会再向远端发送数据, 1225 | // 因此就没有机会从远端接受 ACK 报文,从而没有机会更新远端窗口大小。 1226 | // 在这种情况下,KCP 需要发送窗口探测报文到远端,待远端回复窗口大小后,后续传输才可以继续 1227 | if (kcp->rmt_wnd == 0) { 1228 | if (kcp->probe_wait == 0) { 1229 | kcp->probe_wait = IKCP_PROBE_INIT; 1230 | kcp->ts_probe = kcp->current + kcp->probe_wait; // 初始化探测间隔和下一次探测时间 1231 | } 1232 | else { 1233 | if (_itimediff(kcp->current, kcp->ts_probe) >= 0) { //当前时间 > 下一次探查窗口的时间 1234 | if (kcp->probe_wait < IKCP_PROBE_INIT) 1235 | kcp->probe_wait = IKCP_PROBE_INIT; 1236 | kcp->probe_wait += kcp->probe_wait / 2; //等待时间变为之前的1.5倍 1237 | if (kcp->probe_wait > IKCP_PROBE_LIMIT) 1238 | kcp->probe_wait = IKCP_PROBE_LIMIT; //若超过上限,设置为上限值 1239 | kcp->ts_probe = kcp->current + kcp->probe_wait; //计算下次探查窗口的时间戳 1240 | kcp->probe |= IKCP_ASK_SEND; //设置探查变量。IKCP_ASK_TELL表示告知远端窗口大小。IKCP_ASK_SEND表示请求远端告知窗口大小 1241 | } 1242 | } 1243 | } else { 1244 | kcp->ts_probe = 0; 1245 | kcp->probe_wait = 0; 1246 | } 1247 | 1248 | // flush window probing commands 1249 | // 将窗口探测报文发送出去 1250 | if (kcp->probe & IKCP_ASK_SEND) { 1251 | seg.cmd = IKCP_CMD_WASK; 1252 | size = (int)(ptr - buffer); 1253 | if (size + (int)IKCP_OVERHEAD > (int)kcp->mtu) { 1254 | ikcp_output(kcp, buffer, size); 1255 | ptr = buffer; 1256 | } 1257 | ptr = ikcp_encode_seg(ptr, &seg); 1258 | } 1259 | 1260 | // flush window probing commands 1261 | // 将窗口回复报文发送出去 1262 | if (kcp->probe & IKCP_ASK_TELL) 1263 | { 1264 | seg.cmd = IKCP_CMD_WINS; 1265 | size = (int)(ptr - buffer); 1266 | if (size + (int)IKCP_OVERHEAD > (int)kcp->mtu) { 1267 | ikcp_output(kcp, buffer, size); 1268 | ptr = buffer; 1269 | } 1270 | ptr = ikcp_encode_seg(ptr, &seg); 1271 | } 1272 | 1273 | kcp->probe = 0; 1274 | 1275 | // calculate window size 1276 | // 计算本次发送可用的窗口大小,这里 KCP 采用了可以配置的策略, 1277 | // 正常情况下,KCP 的窗口大小由 1278 | // 发送窗口 snd_wnd 和 远端接收窗口 rmt_wnd 以及 根据拥塞控制计算得到的 kcp->cwnd 三者共同决定; 1279 | // 但是当开启了 nocwnd 模式时,窗口大小仅由前两者决定 1280 | cwnd = _imin_(kcp->snd_wnd, kcp->rmt_wnd); 1281 | if (kcp->nocwnd == 0) cwnd = _imin_(kcp->cwnd, cwnd); 1282 | 1283 | // move data from snd_queue to snd_buf 1284 | // 将缓存在 snd_queue 中的数据移到 snd_buf 中等待发送 1285 | // 移动的包的数量不会超过snd_una+cwnd-snd_nxt,确保发送的数据不会让接收方的接收队列溢出。 1286 | // 该功能类似于TCP协议中的滑动窗口。 1287 | while (_itimediff(kcp->snd_nxt, kcp->snd_una + cwnd) < 0) { 1288 | IKCPSEG *newseg; 1289 | if (iqueue_is_empty(&kcp->snd_queue)) 1290 | break; 1291 | 1292 | newseg = iqueue_entry(kcp->snd_queue.next, IKCPSEG, node); //snd_queue:发送消息的队列 1293 | 1294 | iqueue_del(&newseg->node); //从发送消息队列中,删除节点 1295 | iqueue_add_tail(&newseg->node, &kcp->snd_buf); //然后把删除的节点,加入到kcp的发送缓存队列中 1296 | kcp->nsnd_que--; 1297 | kcp->nsnd_buf++; 1298 | 1299 | newseg->conv = kcp->conv; //会话id 1300 | newseg->cmd = IKCP_CMD_PUSH; 1301 | newseg->wnd = seg.wnd; 1302 | newseg->ts = current; 1303 | newseg->sn = kcp->snd_nxt++; //下一个待发报的序号 1304 | newseg->una = kcp->rcv_nxt; //待接收的下一个消息序号 1305 | newseg->resendts = current; //下次超时重传的时间戳 1306 | newseg->rto = kcp->rx_rto; //由ack接收延迟计算出来的重传超时时间 1307 | newseg->fastack = 0; //收到ack时计算的该分片被跳过的累计次数 1308 | newseg->xmit = 0; //发送分片的次数,每发送一次加一 1309 | } 1310 | 1311 | // calculate resent 1312 | // 在发送数据之前,先设置快重传的次数和重传间隔; 1313 | // KCP 允许设置快重传的次数,即 fastresend 参数。 1314 | // 例如设置 fastresend 为2,并且发送端发送了1,2,3,4,5几个包, 1315 | // 收到远端的ACK: 1, 3, 4, 5,当收到ACK3时,KCP知道2被跳过1次, 1316 | // 收到ACK4时,知道2被“跳过”了2次,此时可以认为2号丢失,不用等超时,直接重传2号包; 1317 | // 每个报文的 fastack 记录了该报文被跳过了几次, 1318 | // 由函数 ikcp_parse_fastack 更新。于此同时,KCP 也允许设置 nodelay 参数, 1319 | // 当激活该参数时,每个报文的超时重传时间将由 x2 变为 x1.5,即加快报文重传: 1320 | resent = (kcp->fastresend > 0)? (IUINT32)kcp->fastresend : 0xffffffff; // 是否设置了快重传次数 1321 | rtomin = (kcp->nodelay == 0)? (kcp->rx_rto >> 3) : 0; // 是否开启了 nodelay 1322 | 1323 | // flush data segments 1324 | for (p = kcp->snd_buf.next; p != &kcp->snd_buf; p = p->next) { 1325 | IKCPSEG *segment = iqueue_entry(p, IKCPSEG, node); 1326 | int needsend = 0; 1327 | 1328 | // 1. xmit为0,第一次发送,赋值rto及resendts 1329 | if (segment->xmit == 0) { 1330 | needsend = 1; 1331 | segment->xmit++; 1332 | segment->rto = kcp->rx_rto; 1333 | segment->resendts = current + segment->rto + rtomin; 1334 | } 1335 | // 2. 超过segment重发时间,却仍在send_buf中,说明长时间未收到ack,认为丢失,重发 1336 | else if (_itimediff(current, segment->resendts) >= 0) { 1337 | needsend = 1; 1338 | segment->xmit++; 1339 | ++kcp->timeout_resnd_cnt; 1340 | // 更新重传时间信息,根据kcp的设置选择rto*2或rto*1.5,并记录lost标志。 1341 | if (kcp->nodelay == 0) { 1342 | segment->rto += kcp->rx_rto; // 以2倍的方式来增长(TCP的RTO默认也是2倍增长) 1343 | } else { 1344 | segment->rto += kcp->rx_rto / 2; // 可以以1.5倍的速度增长 1345 | } 1346 | segment->resendts = current + segment->rto; 1347 | lost = 1; // 记录出现了报文丢失 1348 | } 1349 | // 3. 达到快速重传阈值,重新发送 1350 | else if (segment->fastack >= resent) { 1351 | needsend = 1; 1352 | segment->xmit++; 1353 | segment->fastack = 0; 1354 | segment->resendts = current + segment->rto; 1355 | change++; // 标识快重传发生 1356 | } 1357 | 1358 | if (needsend) { 1359 | int size, need; 1360 | segment->ts = current; 1361 | segment->wnd = seg.wnd; 1362 | segment->una = kcp->rcv_nxt; 1363 | 1364 | size = (int)(ptr - buffer); 1365 | need = IKCP_OVERHEAD + segment->len; //segment报文默认大小 + segment的长度 1366 | 1367 | if (size + need > (int)kcp->mtu) { 1368 | ikcp_output(kcp, buffer, size); 1369 | ++kcp->snd_sum; 1370 | ptr = buffer; 1371 | } 1372 | 1373 | ptr = ikcp_encode_seg(ptr, segment); 1374 | 1375 | if (segment->len > 0) { 1376 | // 因为ptr初始值是指向buffer的, 而buffer是指向kcp->buffer的, 1377 | // 所以这里实际上是把segment->data拷贝到kcp->buffer中, 1378 | // 之后再求ptr与buffer的差值是否大于mtu决定是否要ikcp_output 1379 | memcpy(ptr, segment->data, segment->len); 1380 | ptr += segment->len; 1381 | } 1382 | 1383 | if (segment->xmit >= kcp->dead_link) { 1384 | kcp->state = -1; 1385 | } 1386 | } 1387 | } 1388 | 1389 | // flush remain segments 1390 | size = (int)(ptr - buffer); 1391 | if (size > 0) { 1392 | ikcp_output(kcp, buffer, size); 1393 | ++kcp->snd_sum; 1394 | } 1395 | 1396 | // update ssthresh 1397 | // 如发生快速重传,将拥塞窗口阈值ssthresh调整为当前发送窗口的一半, 1398 | // 将拥塞窗口调整为 ssthresh + resent,resent是触发快速重传的丢包的次数, 1399 | // resent的值代表的意思在被弄丢的包后面收到了resent个数的包的ack。 1400 | // 这样调整后kcp就进入了拥塞控制状态。 1401 | if (change) { 1402 | IUINT32 inflight = kcp->snd_nxt - kcp->snd_una; 1403 | kcp->ssthresh = inflight / 2; // 将拥塞窗口阈值ssthresh调整为当前发送窗口的一半 1404 | if (kcp->ssthresh < IKCP_THRESH_MIN) 1405 | kcp->ssthresh = IKCP_THRESH_MIN; 1406 | kcp->cwnd = kcp->ssthresh + resent; 1407 | kcp->incr = kcp->cwnd * kcp->mss; 1408 | } 1409 | 1410 | // update ssthresh 1411 | // 当出现超时重传的时候,说明网络很可能死掉了,因为超时重传会出现, 1412 | // 原因是有包丢失了,并且该包之后的包也没有收到,这很有可能是网络死了, 1413 | // 这时候,拥塞窗口直接变为1。 1414 | if (lost) { 1415 | kcp->ssthresh = cwnd / 2; 1416 | if (kcp->ssthresh < IKCP_THRESH_MIN) 1417 | kcp->ssthresh = IKCP_THRESH_MIN; 1418 | kcp->cwnd = 1; 1419 | kcp->incr = kcp->mss; 1420 | } 1421 | 1422 | if (kcp->cwnd < 1) { 1423 | kcp->cwnd = 1; 1424 | kcp->incr = kcp->mss; 1425 | } 1426 | } 1427 | 1428 | // return rdc state; 0 for close, 1 for open 1429 | int ikcp_rdc_check(ikcpcb *kcp) 1430 | { 1431 | IINT32 slap = _itimediff(kcp->current, kcp->rdc_check_ts); 1432 | if (slap < 0 && slap > -10000) 1433 | return kcp->is_rdc_on; 1434 | kcp->rdc_check_ts= kcp->current + kcp->rdc_check_interval; 1435 | if (kcp->snd_sum > 0) 1436 | kcp->loss_rate = (int)(1.0 * kcp->timeout_resnd_cnt / kcp->snd_sum * 100); 1437 | kcp->timeout_resnd_cnt = 0; 1438 | kcp->snd_sum = 0; 1439 | if (!kcp->is_rdc_on && kcp->loss_rate >= kcp->rdc_loss_rate_limit && kcp->rx_srtt >= kcp->rdc_rtt_limit) 1440 | kcp->is_rdc_on = 1; 1441 | else if (kcp->is_rdc_on && (kcp->loss_rate < kcp->rdc_loss_rate_limit || kcp->rx_srtt < kcp->rdc_rtt_limit) 1442 | && (++kcp->rdc_close_try_times >= kcp->rdc_close_try_threshold)) 1443 | kcp->is_rdc_on = 0; 1444 | 1445 | return kcp->is_rdc_on; 1446 | } 1447 | 1448 | //--------------------------------------------------------------------- 1449 | // update state (call it repeatedly, every 10ms-100ms), or you can ask 1450 | // ikcp_check when to call it again (without ikcp_input/_send calling). 1451 | // 'current' - current timestamp in millisec. 1452 | // 1453 | // ikcp_update函数的作用是 : 1454 | // 设置下一次flush刷新时间戳, 并调用 ikcp_flush 函数 1455 | // 1456 | // kcp需要上层通过update来驱动kcp数据包的发送,每次驱动的时间间隔由interval来决定, 1457 | // interval可以通过函数ikcp_interval来设置,间隔时间在10毫秒到5秒之间, 1458 | // 初始默认值为100毫秒。 1459 | // 1460 | // 另外注意到一点是,updated参数只有在第一次调用ikcp_update函数时设置为1, 1461 | // 源码中没有找到重置为0的地方,目测就是一个标志参数, 1462 | // 用于区别第一次驱动和之后的驱动所需要选择的时间。 1463 | //--------------------------------------------------------------------- 1464 | void ikcp_update(ikcpcb *kcp, IUINT32 current) 1465 | { 1466 | IINT32 slap; 1467 | 1468 | kcp->current = current; 1469 | 1470 | if (kcp->updated == 0) { 1471 | kcp->updated = 1; 1472 | kcp->ts_flush = kcp->current; // 设置下一次flush刷新时间戳 1473 | } 1474 | 1475 | slap = _itimediff(kcp->current, kcp->ts_flush); 1476 | 1477 | if (slap >= 10000 || slap < -10000) { 1478 | kcp->ts_flush = kcp->current; 1479 | slap = 0; 1480 | } 1481 | 1482 | if (slap >= 0) { 1483 | kcp->ts_flush += kcp->interval; // 设置下一次flush刷新时间戳 1484 | if (_itimediff(kcp->current, kcp->ts_flush) >= 0) { 1485 | kcp->ts_flush = kcp->current + kcp->interval; 1486 | } 1487 | ikcp_flush(kcp); 1488 | } 1489 | } 1490 | 1491 | 1492 | //--------------------------------------------------------------------- 1493 | // Determine when should you invoke ikcp_update: 1494 | // returns when you should invoke ikcp_update in millisec, if there 1495 | // is no ikcp_input/_send calling. you can call ikcp_update in that 1496 | // time, instead of call update repeatly. 1497 | // Important to reduce unnacessary ikcp_update invoking. use it to 1498 | // schedule ikcp_update (eg. implementing an epoll-like mechanism, 1499 | // or optimize ikcp_update when handling massive kcp connections) 1500 | // 1501 | // check函数用于获取下次update的时间。 1502 | // 具体的时间由上次update后更新的下次时间和snd_buf中的超时重传时间决定。 1503 | // check过程会寻找snd_buf中是否有超时重传的数据,如果有需要重传的Segment, 1504 | // 将返回当前时间,立即进行一次update来进行重传,如果全都不需要重传, 1505 | // 则会根据最小的重传时间来判断下次update的时间。 1506 | //--------------------------------------------------------------------- 1507 | IUINT32 ikcp_check(const ikcpcb *kcp, IUINT32 current) 1508 | { 1509 | IUINT32 ts_flush = kcp->ts_flush; 1510 | IINT32 tm_flush = 0x7fffffff; 1511 | IINT32 tm_packet = 0x7fffffff; 1512 | IUINT32 minimal = 0; 1513 | struct IQUEUEHEAD *p; 1514 | 1515 | if (kcp->updated == 0) { 1516 | return current; 1517 | } 1518 | 1519 | if (_itimediff(current, ts_flush) >= 10000 || 1520 | _itimediff(current, ts_flush) < -10000) { 1521 | ts_flush = current; 1522 | } 1523 | 1524 | if (_itimediff(current, ts_flush) >= 0) { 1525 | return current; 1526 | } 1527 | 1528 | tm_flush = _itimediff(ts_flush, current); 1529 | 1530 | for (p = kcp->snd_buf.next; p != &kcp->snd_buf; p = p->next) { 1531 | const IKCPSEG *seg = iqueue_entry(p, const IKCPSEG, node); 1532 | IINT32 diff = _itimediff(seg->resendts, current); 1533 | if (diff <= 0) { 1534 | return current; 1535 | } 1536 | if (diff < tm_packet) tm_packet = diff; 1537 | } 1538 | 1539 | minimal = (IUINT32)(tm_packet < tm_flush ? tm_packet : tm_flush); 1540 | if (minimal >= kcp->interval) minimal = kcp->interval; 1541 | 1542 | return current + minimal; 1543 | } 1544 | 1545 | 1546 | 1547 | int ikcp_setmtu(ikcpcb *kcp, int mtu) 1548 | { 1549 | char *buffer; 1550 | if (mtu < 50 || mtu < (int)IKCP_OVERHEAD) 1551 | return -1; 1552 | buffer = (char*)ikcp_malloc((mtu + IKCP_OVERHEAD) * 3); 1553 | if (buffer == NULL) 1554 | return -2; 1555 | kcp->mtu = mtu; 1556 | kcp->mss = kcp->mtu - IKCP_OVERHEAD; 1557 | ikcp_free(kcp->buffer); 1558 | kcp->buffer = buffer; 1559 | return 0; 1560 | } 1561 | 1562 | int ikcp_interval(ikcpcb *kcp, int interval) 1563 | { 1564 | if (interval > 5000) interval = 5000; 1565 | else if (interval < 10) interval = 10; 1566 | kcp->interval = interval; 1567 | return 0; 1568 | } 1569 | 1570 | //nodelay: 0 不启用,1启用nodelay模式(即使用更小的 rx_minrto, 以更快检测到丢包) 1571 | //interval: 内部flush刷新时间 1572 | //resend: 0(默认)表示关闭。可以自己设置值,若设置为2(则2次ACK跨越将会直接重传) 1573 | //nc: 即 no congest 的缩写, 是否关闭拥塞控制,0(默认)代表不关闭,1代表关闭 1574 | int ikcp_nodelay(ikcpcb *kcp, int nodelay, int interval, int resend, int nc) 1575 | { 1576 | if (nodelay >= 0) 1577 | { 1578 | kcp->nodelay = nodelay; 1579 | if (nodelay) 1580 | { 1581 | kcp->rx_minrto = IKCP_RTO_NDL; //最小重传超时时间(如果需要可以设置更小) 1582 | } 1583 | else 1584 | { 1585 | kcp->rx_minrto = IKCP_RTO_MIN; 1586 | } 1587 | } 1588 | if (interval >= 0) 1589 | { 1590 | if (interval > 5000) 1591 | interval = 5000; 1592 | else if (interval < 10) 1593 | interval = 10; 1594 | kcp->interval = interval; //内部flush刷新时间 1595 | } 1596 | if (resend >= 0) // ACK被跳过resend次数后直接重传该包, 而不等待超时 1597 | { 1598 | kcp->fastresend = resend; // fastresend : 触发快速重传的重复ack个数 1599 | } 1600 | if (nc >= 0) 1601 | { 1602 | kcp->nocwnd = nc; 1603 | } 1604 | return 0; 1605 | } 1606 | 1607 | 1608 | int ikcp_wndsize(ikcpcb *kcp, int sndwnd, int rcvwnd) 1609 | { 1610 | if (kcp) { 1611 | if (sndwnd > 0) { 1612 | kcp->snd_wnd = sndwnd; 1613 | } 1614 | if (rcvwnd > 0) { // must >= max fragment size 1615 | kcp->rcv_wnd = _imax_(rcvwnd, IKCP_WND_RCV); 1616 | } 1617 | } 1618 | return 0; 1619 | } 1620 | 1621 | int ikcp_waitsnd(const ikcpcb *kcp) 1622 | { 1623 | return kcp->nsnd_buf + kcp->nsnd_que; 1624 | } 1625 | 1626 | 1627 | // read conv 1628 | IUINT32 ikcp_getconv(const void *ptr) 1629 | { 1630 | IUINT32 conv; 1631 | ikcp_decode32u((const char*)ptr, &conv); 1632 | return conv; 1633 | } 1634 | 1635 | 1636 | -------------------------------------------------------------------------------- /ikcp.h: -------------------------------------------------------------------------------- 1 | //===================================================================== 2 | // 3 | // KCP - A Better ARQ Protocol Implementation 4 | // skywind3000 (at) gmail.com, 2010-2011 5 | // 6 | // Features: 7 | // + Average RTT reduce 30% - 40% vs traditional ARQ like tcp. 8 | // + Maximum RTT reduce three times vs tcp. 9 | // + Lightweight, distributed as a single source file. 10 | // 11 | //===================================================================== 12 | #ifndef __IKCP_H__ 13 | #define __IKCP_H__ 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | 20 | //===================================================================== 21 | // 32BIT INTEGER DEFINITION 22 | //===================================================================== 23 | #ifndef __INTEGER_32_BITS__ 24 | #define __INTEGER_32_BITS__ 25 | #if defined(_WIN64) || defined(WIN64) || defined(__amd64__) || \ 26 | defined(__x86_64) || defined(__x86_64__) || defined(_M_IA64) || \ 27 | defined(_M_AMD64) 28 | typedef unsigned int ISTDUINT32; 29 | typedef int ISTDINT32; 30 | #elif defined(_WIN32) || defined(WIN32) || defined(__i386__) || \ 31 | defined(__i386) || defined(_M_X86) 32 | typedef unsigned long ISTDUINT32; 33 | typedef long ISTDINT32; 34 | #elif defined(__MACOS__) 35 | typedef UInt32 ISTDUINT32; 36 | typedef SInt32 ISTDINT32; 37 | #elif defined(__APPLE__) && defined(__MACH__) 38 | #include 39 | typedef u_int32_t ISTDUINT32; 40 | typedef int32_t ISTDINT32; 41 | #elif defined(__BEOS__) 42 | #include 43 | typedef u_int32_t ISTDUINT32; 44 | typedef int32_t ISTDINT32; 45 | #elif (defined(_MSC_VER) || defined(__BORLANDC__)) && (!defined(__MSDOS__)) 46 | typedef unsigned __int32 ISTDUINT32; 47 | typedef __int32 ISTDINT32; 48 | #elif defined(__GNUC__) 49 | #include 50 | typedef uint32_t ISTDUINT32; 51 | typedef int32_t ISTDINT32; 52 | #else 53 | typedef unsigned long ISTDUINT32; 54 | typedef long ISTDINT32; 55 | #endif 56 | #endif 57 | 58 | 59 | //===================================================================== 60 | // Integer Definition 61 | //===================================================================== 62 | #ifndef __IINT8_DEFINED 63 | #define __IINT8_DEFINED 64 | typedef char IINT8; 65 | #endif 66 | 67 | #ifndef __IUINT8_DEFINED 68 | #define __IUINT8_DEFINED 69 | typedef unsigned char IUINT8; 70 | #endif 71 | 72 | #ifndef __IUINT16_DEFINED 73 | #define __IUINT16_DEFINED 74 | typedef unsigned short IUINT16; 75 | #endif 76 | 77 | #ifndef __IINT16_DEFINED 78 | #define __IINT16_DEFINED 79 | typedef short IINT16; 80 | #endif 81 | 82 | #ifndef __IINT32_DEFINED 83 | #define __IINT32_DEFINED 84 | typedef ISTDINT32 IINT32; 85 | #endif 86 | 87 | #ifndef __IUINT32_DEFINED 88 | #define __IUINT32_DEFINED 89 | typedef ISTDUINT32 IUINT32; 90 | #endif 91 | 92 | #ifndef __IINT64_DEFINED 93 | #define __IINT64_DEFINED 94 | #if defined(_MSC_VER) || defined(__BORLANDC__) 95 | typedef __int64 IINT64; 96 | #else 97 | typedef long long IINT64; 98 | #endif 99 | #endif 100 | 101 | #ifndef __IUINT64_DEFINED 102 | #define __IUINT64_DEFINED 103 | #if defined(_MSC_VER) || defined(__BORLANDC__) 104 | typedef unsigned __int64 IUINT64; 105 | #else 106 | typedef unsigned long long IUINT64; 107 | #endif 108 | #endif 109 | 110 | #ifndef INLINE 111 | #if defined(__GNUC__) 112 | 113 | #if (__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1)) 114 | #define INLINE __inline__ __attribute__((always_inline)) 115 | #else 116 | #define INLINE __inline__ 117 | #endif 118 | 119 | #elif (defined(_MSC_VER) || defined(__BORLANDC__) || defined(__WATCOMC__)) 120 | #define INLINE __inline 121 | #else 122 | #define INLINE 123 | #endif 124 | #endif 125 | 126 | #if (!defined(__cplusplus)) && (!defined(inline)) 127 | #define inline INLINE 128 | #endif 129 | 130 | 131 | //===================================================================== 132 | // QUEUE DEFINITION 133 | //===================================================================== 134 | #ifndef __IQUEUE_DEF__ 135 | #define __IQUEUE_DEF__ 136 | 137 | struct IQUEUEHEAD { 138 | struct IQUEUEHEAD *next, *prev; 139 | }; 140 | 141 | typedef struct IQUEUEHEAD iqueue_head; 142 | 143 | 144 | //--------------------------------------------------------------------- 145 | // queue init 146 | //--------------------------------------------------------------------- 147 | #define IQUEUE_HEAD_INIT(name) { &(name), &(name) } 148 | #define IQUEUE_HEAD(name) \ 149 | struct IQUEUEHEAD name = IQUEUE_HEAD_INIT(name) 150 | 151 | #define IQUEUE_INIT(ptr) ( \ 152 | (ptr)->next = (ptr), (ptr)->prev = (ptr)) 153 | 154 | #define IOFFSETOF(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) 155 | 156 | #define ICONTAINEROF(ptr, type, member) ( \ 157 | (type*)( ((char*)((type*)ptr)) - IOFFSETOF(type, member)) ) 158 | 159 | 160 | // 关于 IQUEUE_ENTRY 宏 : 161 | // 162 | // #1. 先看&((type *)0)->member: 163 | // 把“0”强制转化为指针类型,则该指针一定指向“0”(数据段基址)。 164 | // 因为指针是“type *”型的,所以可取到以“0”为基地址的一个type型变量member域的地址。 165 | // 那么这个地址也就等于member域到结构体基地址的偏移字节数。 166 | // 167 | // #2. 再来看((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))): 168 | // (char *)(ptr)使得指针的加减操作步长为一字节, 169 | // (unsigned long)(&((type *)0)->member)等于ptr指向的member到该member所在结构体基地址的偏移字节数。 170 | // 二者一减便得出该结构体的地址。转换为(type *)型的指针,大功告成。 171 | // 172 | // 比如 ikcp_parse_una 函数中的以下代码 173 | // ``` 174 | // struct IQUEUEHEAD *p, *next; 175 | // for (p = kcp->snd_buf.next; p != &kcp->snd_buf; p = next) 176 | // { 177 | // IKCPSEG *seg = iqueue_entry(p, IKCPSEG, node); 178 | // ``` 179 | // 其中的 ` IKCPSEG *seg = iqueue_entry(p, IKCPSEG, node); ` 展开则为 : 180 | // IKCPSEG *seg = ( (IKCPSEG*)( ( (char*)((IKCPSEG*)p) ) - ((size_t) &((IKCPSEG *)0)->node) ) ); 181 | // 182 | // 则可达到以下效果 : 183 | // 通过一个 IQUEUEHEAD 指针 p 得到 一个 指向该链表节点所在的数据块的 IKCPSEG 指针 seg 184 | // 185 | // 注 : 186 | // 要把源代码中的宏展开,其实只要使用gcc进行预处理即可。 187 | // gcc -E source.c > out.txt 188 | // -E 表示只进行预处理,不进行编译。 189 | // 预处理时会把注释当成空格处理掉,如果想保留其中的注释,可以加上 -C选项,即: 190 | // gcc -E -C source.c > out.txt 191 | #define IQUEUE_ENTRY(ptr, type, member) ICONTAINEROF(ptr, type, member) 192 | 193 | 194 | //--------------------------------------------------------------------- 195 | // queue operation 196 | //--------------------------------------------------------------------- 197 | 198 | // 插到队列某一元素的后面 199 | // 如 head = rcv_queue, node = A 则变为 rcv_queue <-> A <-> rcv_queue 200 | // 若然后在A后面加个B之后(即head = A, node = B)则变为 rcv_queue <-> A <-> B <-> rcv_queue 201 | #define IQUEUE_ADD(node, head) (\ 202 | (node)->prev = (head), (node)->next = (head)->next, \ 203 | (head)->next->prev = (node), (head)->next = (node)) 204 | 205 | // 插到队列尾部 206 | // 如 rcv_queue 变为 rcv_queue <-> A <-> rcv_queue 207 | // 然后加个B之后变为 rcv_queue <-> A <-> B <-> rcv_queue 208 | // 然后加个node之后变为 rcv_queue <-> A <-> B <-> node <-> rcv_queue 209 | #define IQUEUE_ADD_TAIL(node, head) (\ 210 | (node)->prev = (head)->prev, (node)->next = (head), \ 211 | (head)->prev->next = (node), (head)->prev = (node)) 212 | 213 | #define IQUEUE_DEL_BETWEEN(p, n) ((n)->prev = (p), (p)->next = (n)) 214 | 215 | // 如 A <-> entry <-> C 变为 A <-> C 216 | #define IQUEUE_DEL(entry) (\ 217 | (entry)->next->prev = (entry)->prev, \ 218 | (entry)->prev->next = (entry)->next, \ 219 | (entry)->next = 0, (entry)->prev = 0) 220 | 221 | #define IQUEUE_DEL_INIT(entry) do { \ 222 | IQUEUE_DEL(entry); IQUEUE_INIT(entry); } while (0) 223 | 224 | #define IQUEUE_IS_EMPTY(entry) ((entry) == (entry)->next) 225 | 226 | #define iqueue_init IQUEUE_INIT 227 | #define iqueue_entry IQUEUE_ENTRY 228 | #define iqueue_add IQUEUE_ADD 229 | #define iqueue_add_tail IQUEUE_ADD_TAIL 230 | #define iqueue_del IQUEUE_DEL 231 | #define iqueue_del_init IQUEUE_DEL_INIT 232 | #define iqueue_is_empty IQUEUE_IS_EMPTY 233 | 234 | #define IQUEUE_FOREACH(iterator, head, TYPE, MEMBER) \ 235 | for ((iterator) = iqueue_entry((head)->next, TYPE, MEMBER); \ 236 | &((iterator)->MEMBER) != (head); \ 237 | (iterator) = iqueue_entry((iterator)->MEMBER.next, TYPE, MEMBER)) 238 | 239 | #define iqueue_foreach(iterator, head, TYPE, MEMBER) \ 240 | IQUEUE_FOREACH(iterator, head, TYPE, MEMBER) 241 | 242 | #define iqueue_foreach_entry(pos, head) \ 243 | for( (pos) = (head)->next; (pos) != (head) ; (pos) = (pos)->next ) 244 | 245 | 246 | #define __iqueue_splice(list, head) do { \ 247 | iqueue_head *first = (list)->next, *last = (list)->prev; \ 248 | iqueue_head *at = (head)->next; \ 249 | (first)->prev = (head), (head)->next = (first); \ 250 | (last)->next = (at), (at)->prev = (last); } while (0) 251 | 252 | #define iqueue_splice(list, head) do { \ 253 | if (!iqueue_is_empty(list)) __iqueue_splice(list, head); } while (0) 254 | 255 | #define iqueue_splice_init(list, head) do { \ 256 | iqueue_splice(list, head); iqueue_init(list); } while (0) 257 | 258 | 259 | #ifdef _MSC_VER 260 | #pragma warning(disable:4311) 261 | #pragma warning(disable:4312) 262 | #pragma warning(disable:4996) 263 | #endif 264 | 265 | #endif 266 | 267 | 268 | //--------------------------------------------------------------------- 269 | // WORD ORDER 270 | //--------------------------------------------------------------------- 271 | #ifndef IWORDS_BIG_ENDIAN 272 | #ifdef _BIG_ENDIAN_ 273 | #if _BIG_ENDIAN_ 274 | #define IWORDS_BIG_ENDIAN 1 275 | #endif 276 | #endif 277 | #ifndef IWORDS_BIG_ENDIAN 278 | #if defined(__hppa__) || \ 279 | defined(__m68k__) || defined(mc68000) || defined(_M_M68K) || \ 280 | (defined(__MIPS__) && defined(__MIPSEB__)) || \ 281 | defined(__ppc__) || defined(__POWERPC__) || defined(_M_PPC) || \ 282 | defined(__sparc__) || defined(__powerpc__) || \ 283 | defined(__mc68000__) || defined(__s390x__) || defined(__s390__) 284 | #define IWORDS_BIG_ENDIAN 1 285 | #endif 286 | #endif 287 | #ifndef IWORDS_BIG_ENDIAN 288 | #define IWORDS_BIG_ENDIAN 0 289 | #endif 290 | #endif 291 | 292 | 293 | 294 | //===================================================================== 295 | // SEGMENT 296 | // KCP数据包 297 | // 298 | // # 1. KCP Segment定义 299 | // 300 | // - KCP.Segment.conv 发送端与接收端通信时的匹配数字,发送端发送的数据包中此值与接收端的conv值匹配一致时,接收端才会接受此包。 301 | // - KCP.Segment.cmd cmd是command的缩写, 指明Segment类型。 302 | // KCP中会有四种Segment数据包类型,分别是 303 | // - 1. 数据包(IKCP_CMD_PUSH): 304 | // 最基础的Segment,用于发送应用层数据给远端。 305 | // 每个数据包会有自己的sn, 发送出去后不会立即从缓存池中删除, 306 | // 而是会等收到远端返回回来的ack包时才会从缓存中移除(两端通过sn确认哪些包已收到) 307 | // - 2. ACK包(IKCP_CMD_ACK): 308 | // 告诉远端自己已收到了远端发送的哪个编号的数据 309 | // - 3. 窗口大小探测包(IKCP_CMD_WASK): 310 | // 询问远端的接收窗口大小。 311 | // 本地发送数据时,会根据远端的窗口大小来控制发送的数据量。 312 | // 每个数据包的包头中都会带有远端当前的接收窗口大小。 313 | // 但是当远端的接收窗口大小为0时,本机将不会再向远端发送数据, 314 | // 此时也就不会有远端的回传数据从而导致无法更新远端窗口大小。 315 | // 因此需要单独的一类远端窗口大小探测包,在远端接收窗口大小为0时, 316 | // 隔一段时间询问一次,从而让本地有机会再开始重新传数据。 317 | // - 4. 窗口大小回应包(IKCP_CMD_WINS): 318 | // 回应远端自己的数据接收窗口大小window size 319 | // - KCP.Segment.frg frg是fragment的缩小,是一个Segment在一次Send的data中的倒序序号。 320 | // 在让KCP发送数据时,KCP会加入snd_queue的Segment分配序号,标记Segment是这次发送数据中的倒数第几个Segment。 321 | // 数据在发送出去时,由于mss的限制,数据可能被分成若干个Segment发送出去。在分segment的过程中,相应的序号就会被记录到frg中。 322 | // 接收端在接收到这些segment时,就会根据frg将若干个segment合并成一个,再返回给应用层。 323 | // - KCP.Segment.wnd wnd是window的缩写; 滑动窗口大小,用于流控(Flow Control) 324 | // - 当Segment做为发送数据时,此wnd为本机滑动窗口大小,用于告诉远端自己窗口剩余多少 325 | // - 当Segment做为接收到数据时,此wnd为远端滑动窗口大小,本机知道了远端窗口剩余多少后,可以控制自己接下来发送数据的大小 326 | // - KCP.Segment.ts 即timestamp, 当前Segment发送时的时间戳 327 | // - KCP.Segment.resendts 即resend timestamp, 指定重发的时间戳,当当前时间超过这个时间时,则再重发一次这个包。 328 | // - KCP.Segment.sn 即Sequence Number, Segment的编号 329 | // - KCP.Segment.una una即unacknowledged, 表示此编号前的所有包都已收到了。 330 | // - KCP.Segment.fastack 用于以数据驱动的快速重传机制; 331 | // - KCP.Segment.rto rto即Retransmission TimeOut,即超时重传时间,在发送出去时根据之前的网络情况进行设置 332 | // - KCP.Segment.xmit 基本类似于Segment发送的次数,每发送一次会自加一。用于统计该Segment被重传了几次,用于参考,进行调节 333 | // - KCP.Segment.length 数据的长度 334 | // - KCP.Segment.data 数据段,应用层要发送出去的数据。 335 | // 336 | // 337 | // # 2. kcp包头结构分析 338 | // 339 | // kcp发送的数据包设计了自己的包结构,包头一共24bytes,包含了一些必要的信息,具体内容和大小如下: 340 | // 341 | // |<------------ 4 bytes ------------>| 342 | // +--------+--------+--------+--------+ 343 | // | conv | conv:Conversation, 会话序号,用于标识收发数据包是否一致 344 | // +--------+--------+--------+--------+ cmd: Command, 指令类型,代表这个Segment的类型 345 | // | cmd | frg | wnd | frg: Fragment, 分段序号,分段从大到小,0代表数据包接收完毕 346 | // +--------+--------+--------+--------+ wnd: Window, 窗口大小 347 | // | ts | ts: Timestamp, 发送的时间戳 348 | // +--------+--------+--------+--------+ 349 | // | sn | sn: Sequence Number, Segment序号 350 | // +--------+--------+--------+--------+ 351 | // | una | una: Unacknowledged, 当前未收到的序号, 352 | // +--------+--------+--------+--------+ 即代表这个序号之前的包均收到 353 | // | len | len: Length, 后续数据的长度 354 | // +--------+--------+--------+--------+ 355 | // 356 | // 包的结构可以在函数ikcp_encode_seg函数的编码过程中看出来 357 | //===================================================================== 358 | struct IKCPSEG 359 | { 360 | struct IQUEUEHEAD node; // 节点用来串接多个 KCP segment,也就是前向后向指针; 361 | // 通用链表实现的队列. 362 | // node是一个通用链表,用于管理Segment队列, 363 | // 通用链表可以支持在不同类型的链表中做转移, 364 | // 通用链表实际上管理的就是一个最小的链表节点, 365 | // 具体该链表节点所在的数据块可以通过该数据块在链表中的位置反向解析出来。见 iqueue_entry 宏 366 | 367 | IUINT32 conv; // Conversation, 会话序号: 接收到的数据包与发送的一致才接收此数据包 368 | IUINT32 cmd; // Command, 指令类型: 代表这个Segment的类型 369 | IUINT32 frg; // Fragment 记录了分片时的倒序序号, 当输出数据大于 MSS 时,需要将数据进行分片; 370 | IUINT32 wnd; // Window, 己方的可用窗口大小, 也就是 rcv_queue 的可用大小即 rcv_wnd - nrcv_que, 见 ikcp_wnd_unused 函数 371 | IUINT32 ts; // Timestamp, 记录了发送时的时间戳,用来估计 RTT 372 | IUINT32 sn; // Sequence Number, Segment序号 373 | IUINT32 una; // Unacknowledged, 当前未收到的序号: 即代表这个序号之前的包均收到 374 | IUINT32 len; // Length, 数据长度 375 | IUINT32 resendts; // 即 resend timestamp, 指定重发的时间戳,当当前时间超过这个时间时,则再重发一次这个包。 376 | IUINT32 rto; // 即 Retransmit Timeout, 用于记录超时重传的时间间隔 377 | IUINT32 fastack; // 记录ack跳过的次数,用于快速重传, 由函数 ikcp_parse_fastack 更新 378 | IUINT32 xmit; // 记录发送的次数 379 | char data[1]; // 应用层要发送出去的数据 380 | }; 381 | 382 | 383 | //--------------------------------------------------------------------- 384 | // IKCPCB 385 | // 386 | // conv 会话ID 387 | // mtu 最大传输单元 388 | // mss 最大分片大小 389 | // state 连接状态(0xFFFFFFFF表示断开连接) 390 | // snd_una 第一个未确认的包 391 | // snd_nxt 下一个待分配的包的序号 392 | // rcv_nxt 待接收的下一个消息序号, 当把segment移出rcv_buf移入rcv_queue时, rcv_nxt会自增 393 | // ssthresh 拥塞窗口阈值 394 | // rx_rttval ack接收rtt浮动值 395 | // rx_srtt ack接收rtt静态值 396 | // rx_rto 由ack接收延迟计算出来的重传超时时间 397 | // rx_minrto 最小重传超时时间 398 | // snd_wnd 发送窗口大小, 一旦设置之后就不会变了, 默认32 399 | // rcv_wnd 接收窗口大小, 一旦设置之后就不会变了, 默认128 400 | // rmt_wnd, 远端接收窗口大小 401 | // cwnd, 拥塞窗口大小 402 | // probe 探查变量,IKCP_ASK_TELL表示告知远端窗口大小。IKCP_ASK_SEND表示请求远端告知窗口大小 403 | // interval 内部flush刷新间隔 404 | // ts_flush 下次flush刷新时间戳 405 | // nodelay 是否启动无延迟模式 406 | // updated 是否调用过update函数的标识 407 | // ts_probe 下次探查窗口的时间戳 408 | // probe_wait 探查窗口需要等待的时间 409 | // dead_link 最大重传次数 410 | // incr 可发送的最大数据量 411 | // 412 | // fastresend 触发快速重传的重复ack个数 413 | // nocwnd 取消拥塞控制 414 | // stream 是否采用流传输模式 415 | // 416 | // nrcv_buf, nsnd_buf; // 收发缓存区中的Segment数量 417 | // 418 | // nsnd_que // 发送队列snd_queue中的Segment数量 419 | // snd_queue 发送消息的队列 420 | // 421 | // rcv_queue 接收消息的队列, rcv_queue的数据是连续的,rcv_buf可能是间隔的 422 | // nrcv_que // 接收队列rcv_queue中的Segment数量, 需要小于 rcv_wnd 423 | // rcv_queue 如下图所示 424 | // +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ 425 | // ... | 2 | 3 | 4 | ............................................... 426 | // +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ 427 | // ^ ^ ^ 428 | // | | | 429 | // rcv_nxt rcv_nxt + nrcv_que rcv_nxt + rcv_wnd 430 | // 431 | // snd_buf 发送消息的缓存 432 | // snd_buf 如下图所示 433 | // +---+---+---+---+---+---+---+---+---+---+---+---+---+ 434 | // ... | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | ........... 435 | // +---+---+---+---+---+---+---+---+---+---+---+---+---+ 436 | // ^ ^ ^ 437 | // | | | 438 | // snd_una snd_nxt snd_una + snd_wnd 439 | // 440 | // 441 | // rcv_buf 接收消息的缓存 442 | // rcv_buf 如下图所示, rcv_queue的数据是连续的,rcv_buf可能是间隔的 443 | // +---+---+---+---+---+---+---+---+---+---+---+---+---+ 444 | // ... | 2 | 4 | 6 | 7 | 8 | 9 | ........... 445 | // +---+---+---+---+---+---+---+---+---+---+---+---+---+ 446 | // 447 | // acklist 待发送的ack列表 448 | // 449 | // buffer 存储消息字节流的内存 450 | // output udp发送消息的回调函数 451 | // 452 | // IKCPCB用于管理整个kcp的工作过程, 453 | // 内部维护了4条队列分别用于管理收发的数据, 454 | // 以及一个ack数组记录ack的数据包。 455 | // 内部还有一些关于重传RTO、流控、窗口大小的信息, 456 | //--------------------------------------------------------------------- 457 | struct IKCPCB 458 | { 459 | IUINT32 rdc_check_ts, rdc_check_interval; 460 | IINT32 rdc_rtt_limit, is_rdc_on, rdc_close_try_times, rdc_close_try_threshold; 461 | IUINT32 snd_sum, timeout_resnd_cnt; 462 | IUINT32 loss_rate, rdc_loss_rate_limit; 463 | 464 | IUINT32 conv, mtu, mss, state; 465 | IUINT32 snd_una, snd_nxt, rcv_nxt; 466 | IUINT32 ssthresh; 467 | IINT32 rx_rttval, rx_srtt, rx_rto, rx_minrto; 468 | IUINT32 snd_wnd, rcv_wnd, rmt_wnd, cwnd, probe; 469 | IUINT32 current, interval, ts_flush; 470 | IUINT32 nrcv_buf, nsnd_buf; // 收发缓存区中的Segment数量 471 | IUINT32 nrcv_que, nsnd_que; // 收发队列中的Segment数量 472 | IUINT32 nodelay, updated; // 非延迟ack,是否update(kcp需要上层通过不断的ikcp_update和ikcp_check来驱动kcp的收发过程) 473 | IUINT32 ts_probe, probe_wait; 474 | IUINT32 dead_link, incr; 475 | struct IQUEUEHEAD snd_queue; // 发送队列:send时将Segment放入 476 | struct IQUEUEHEAD rcv_queue; // 接收队列:recv时将接收缓冲区rcv_buf中的Segment移入接收队列 477 | struct IQUEUEHEAD snd_buf; // 发送缓冲区:update时将Segment从发送队列放入缓冲区 478 | struct IQUEUEHEAD rcv_buf; // 接收缓冲区:存放底层接收的数据Segment 479 | IUINT32 *acklist; // ack列表,所有收到的包ack将放在这里,依次存放sn和ts 480 | IUINT32 ackcount; // ack数量 481 | IUINT32 ackblock; // acklist大小 482 | void *user; 483 | char *buffer; // 存储消息字节流的内存 484 | int fastresend; // 触发快速重传的重复ack个数 485 | int nocwnd, stream; // 非退让流控、流模式 486 | int logmask; 487 | int(*output)(const char *buf, int len, struct IKCPCB *kcp, void *user); // 底层网络传输函数 488 | void(*writelog)(const char *log, struct IKCPCB *kcp, void *user); 489 | }; 490 | 491 | 492 | typedef struct IKCPCB ikcpcb; 493 | 494 | #define IKCP_LOG_OUTPUT 1 495 | #define IKCP_LOG_INPUT 2 496 | #define IKCP_LOG_SEND 4 497 | #define IKCP_LOG_RECV 8 498 | #define IKCP_LOG_IN_DATA 16 499 | #define IKCP_LOG_IN_ACK 32 500 | #define IKCP_LOG_IN_PROBE 64 501 | #define IKCP_LOG_IN_WINS 128 502 | #define IKCP_LOG_OUT_DATA 256 503 | #define IKCP_LOG_OUT_ACK 512 504 | #define IKCP_LOG_OUT_PROBE 1024 505 | #define IKCP_LOG_OUT_WINS 2048 506 | 507 | #ifdef __cplusplus 508 | extern "C" { 509 | #endif 510 | 511 | //--------------------------------------------------------------------- 512 | // interface 513 | //--------------------------------------------------------------------- 514 | 515 | // create a new kcp control object, 'conv' must equal in two endpoint 516 | // from the same connection. 'user' will be passed to the output callback 517 | // output callback can be setup like this: 'kcp->output = my_udp_output' 518 | ikcpcb* ikcp_create(IUINT32 conv, void *user); 519 | 520 | // release kcp control object 521 | void ikcp_release(ikcpcb *kcp); 522 | 523 | // set output callback, which will be invoked by kcp 524 | void ikcp_setoutput(ikcpcb *kcp, int (*output)(const char *buf, int len, 525 | ikcpcb *kcp, void *user)); 526 | 527 | // user/upper level recv: returns size, returns below zero for EAGAIN 528 | int ikcp_recv(ikcpcb *kcp, char *buffer, int len); 529 | 530 | // user/upper level send, returns below zero for error 531 | int ikcp_send(ikcpcb *kcp, const char *buffer, int len); 532 | 533 | // update state (call it repeatedly, every 10ms-100ms), or you can ask 534 | // ikcp_check when to call it again (without ikcp_input/_send calling). 535 | // 'current' - current timestamp in millisec. 536 | void ikcp_update(ikcpcb *kcp, IUINT32 current); 537 | 538 | // Determine when should you invoke ikcp_update: 539 | // returns when you should invoke ikcp_update in millisec, if there 540 | // is no ikcp_input/_send calling. you can call ikcp_update in that 541 | // time, instead of call update repeatly. 542 | // Important to reduce unnacessary ikcp_update invoking. use it to 543 | // schedule ikcp_update (eg. implementing an epoll-like mechanism, 544 | // or optimize ikcp_update when handling massive kcp connections) 545 | IUINT32 ikcp_check(const ikcpcb *kcp, IUINT32 current); 546 | 547 | // when you received a low level packet (eg. UDP packet), call it 548 | int ikcp_input(ikcpcb *kcp, const char *data, long size); 549 | 550 | // flush pending data 551 | void ikcp_flush(ikcpcb *kcp); 552 | 553 | // check the size of next message in the recv queue 554 | int ikcp_peeksize(const ikcpcb *kcp); 555 | 556 | // change MTU size, default is 1400 557 | int ikcp_setmtu(ikcpcb *kcp, int mtu); 558 | 559 | // set maximum window size: sndwnd=32, rcvwnd=32 by default 560 | int ikcp_wndsize(ikcpcb *kcp, int sndwnd, int rcvwnd); 561 | 562 | // get how many packet is waiting to be sent 563 | int ikcp_waitsnd(const ikcpcb *kcp); 564 | 565 | // fastest: ikcp_nodelay(kcp, 1, 20, 2, 1) 566 | // nodelay: 0:disable(default), 1:enable 567 | // interval: internal update timer interval in millisec, default is 100ms 568 | // resend: 0:disable fast resend(default), 1:enable fast resend 569 | // nc: 0:normal congestion control(default), 1:disable congestion control 570 | int ikcp_nodelay(ikcpcb *kcp, int nodelay, int interval, int resend, int nc); 571 | 572 | void ikcp_log(ikcpcb *kcp, int mask, const char *fmt, ...); 573 | 574 | // setup allocator 575 | void ikcp_allocator(void* (*new_malloc)(size_t), void (*new_free)(void*)); 576 | 577 | // read conv 578 | IUINT32 ikcp_getconv(const void *ptr); 579 | 580 | // return rdc state; 0 for close, 1 for open 581 | int ikcp_rdc_check(ikcpcb *kcp); 582 | 583 | #ifdef __cplusplus 584 | } 585 | #endif 586 | 587 | #endif 588 | 589 | 590 | -------------------------------------------------------------------------------- /kcpp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "ikcp.h" 12 | 13 | 14 | // "License": Public Domain 15 | // I, Mathias Panzenbรถck, place this file hereby into the public domain. Use it at your own risk for whatever you like. 16 | // In case there are jurisdictions that don't support putting things in the public domain you can also consider it to 17 | // be "dual licensed" under the BSD, MIT and Apache licenses, if you want to. This code is trivial anyway. Consider it 18 | // an example on how to get the endian conversion functions on different platforms. 19 | 20 | 21 | #if (defined(_WIN16) || defined(_WIN32) || defined(_WIN64)) && !defined(__WINDOWS__) 22 | 23 | # define __WINDOWS__ 24 | 25 | #endif 26 | 27 | #if defined(__linux__) || defined(__CYGWIN__) 28 | 29 | # include 30 | 31 | #elif defined(__APPLE__) 32 | 33 | # include 34 | 35 | # define htobe16(x) OSSwapHostToBigInt16(x) 36 | # define htole16(x) OSSwapHostToLittleInt16(x) 37 | # define be16toh(x) OSSwapBigToHostInt16(x) 38 | # define le16toh(x) OSSwapLittleToHostInt16(x) 39 | 40 | # define htobe32(x) OSSwapHostToBigInt32(x) 41 | # define htole32(x) OSSwapHostToLittleInt32(x) 42 | # define be32toh(x) OSSwapBigToHostInt32(x) 43 | # define le32toh(x) OSSwapLittleToHostInt32(x) 44 | 45 | # define htobe64(x) OSSwapHostToBigInt64(x) 46 | # define htole64(x) OSSwapHostToLittleInt64(x) 47 | # define be64toh(x) OSSwapBigToHostInt64(x) 48 | # define le64toh(x) OSSwapLittleToHostInt64(x) 49 | 50 | # define __BYTE_ORDER BYTE_ORDER 51 | # define __BIG_ENDIAN BIG_ENDIAN 52 | # define __LITTLE_ENDIAN LITTLE_ENDIAN 53 | # define __PDP_ENDIAN PDP_ENDIAN 54 | 55 | #elif defined(__OpenBSD__) 56 | 57 | # include 58 | 59 | #elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) 60 | 61 | # include 62 | 63 | # define be16toh(x) betoh16(x) 64 | # define le16toh(x) letoh16(x) 65 | 66 | # define be32toh(x) betoh32(x) 67 | # define le32toh(x) letoh32(x) 68 | 69 | # define be64toh(x) betoh64(x) 70 | # define le64toh(x) letoh64(x) 71 | 72 | #elif defined(__WINDOWS__) 73 | 74 | # include 75 | //# include 76 | 77 | #if !defined(BYTE_ORDER) && defined(__BYTE_ORDER) 78 | #define BYTE_ORDER __BYTE_ORDER 79 | 80 | #ifndef LITTLE_ENDIAN 81 | #define LITTLE_ENDIAN __LITTLE_ENDIAN 82 | #endif /* LITTLE_ENDIAN */ 83 | 84 | #ifndef BIG_ENDIAN 85 | #define BIG_ENDIAN __LITTLE_ENDIAN 86 | #endif /* BIG_ENDIAN */ 87 | #endif /* BYTE_ORDER */ 88 | 89 | # if BYTE_ORDER == LITTLE_ENDIAN 90 | 91 | # define htobe16(x) htons(x) 92 | # define htole16(x) (x) 93 | # define be16toh(x) ntohs(x) 94 | # define le16toh(x) (x) 95 | 96 | # define htobe32(x) htonl(x) 97 | # define htole32(x) (x) 98 | # define be32toh(x) ntohl(x) 99 | # define le32toh(x) (x) 100 | 101 | #ifndef htonll 102 | #define htonll(x) ((1==htonl(1)) ? (x) : ((uint64_t)htonl((x) & 0xFFFFFFFF) << 32) | htonl((x) >> 32)) 103 | #endif 104 | 105 | #ifndef ntohll 106 | #define ntohll(x) ((1==ntohl(1)) ? (x) : ((uint64_t)ntohl((x) & 0xFFFFFFFF) << 32) | ntohl((x) >> 32)) 107 | #endif 108 | 109 | # define htobe64(x) htonll(x) 110 | # define htole64(x) (x) 111 | # define be64toh(x) ntohll(x) 112 | # define le64toh(x) (x) 113 | 114 | # elif BYTE_ORDER == BIG_ENDIAN 115 | 116 | /* that would be xbox 360 */ 117 | # define htobe16(x) (x) 118 | # define htole16(x) __builtin_bswap16(x) 119 | # define be16toh(x) (x) 120 | # define le16toh(x) __builtin_bswap16(x) 121 | 122 | # define htobe32(x) (x) 123 | # define htole32(x) __builtin_bswap32(x) 124 | # define be32toh(x) (x) 125 | # define le32toh(x) __builtin_bswap32(x) 126 | 127 | # define htobe64(x) (x) 128 | # define htole64(x) __builtin_bswap64(x) 129 | # define be64toh(x) (x) 130 | # define le64toh(x) __builtin_bswap64(x) 131 | 132 | # else 133 | 134 | # error byte order not supported 135 | 136 | # endif 137 | 138 | # define __BYTE_ORDER BYTE_ORDER 139 | # define __BIG_ENDIAN BIG_ENDIAN 140 | # define __LITTLE_ENDIAN LITTLE_ENDIAN 141 | # define __PDP_ENDIAN PDP_ENDIAN 142 | 143 | #else 144 | 145 | # error platform not supported 146 | 147 | #endif 148 | 149 | 150 | namespace kcpp 151 | { 152 | 153 | // a light weight buffer. 154 | // thx to chensuo, modify on muduo::net::Buffer and make it safe to prepend data of any length. 155 | 156 | /// A buffer class modeled after org.jboss.netty.buffer.ChannelBuffer 157 | /// 158 | /// @code 159 | /// +-------------------+------------------+------------------+ 160 | /// | prependable bytes | readable bytes | writable bytes | 161 | /// | | (CONTENT) | | 162 | /// +-------------------+------------------+------------------+ 163 | /// | | | | 164 | /// 0 <= readerIndex <= writerIndex <= size 165 | /// @endcode 166 | class Buf 167 | { 168 | public: 169 | static const size_t kCheapPrepend = 1024; 170 | static const size_t kInitialSize = 512; 171 | 172 | explicit Buf(size_t initialSize = kInitialSize) 173 | : 174 | buffer_(kCheapPrepend + initialSize), 175 | readerIndex_(kCheapPrepend), 176 | writerIndex_(kCheapPrepend) 177 | { 178 | assert(readableBytes() == 0); 179 | assert(writableBytes() == initialSize); 180 | assert(prependableBytes() == kCheapPrepend); 181 | } 182 | 183 | // implicit copy-ctor, move-ctor, dtor and assignment are fine 184 | // NOTE: implicit move-ctor is added in g++ 4.6 185 | 186 | void swap(Buf& rhs) 187 | { 188 | buffer_.swap(rhs.buffer_); 189 | std::swap(readerIndex_, rhs.readerIndex_); 190 | std::swap(writerIndex_, rhs.writerIndex_); 191 | } 192 | 193 | size_t readableBytes() const 194 | { return writerIndex_ - readerIndex_; } 195 | 196 | size_t writableBytes() const 197 | { return buffer_.size() - writerIndex_; } 198 | 199 | size_t prependableBytes() const 200 | { return readerIndex_; } 201 | 202 | const char* peek() const 203 | { return begin() + readerIndex_; } 204 | 205 | const char* findCRLF() const 206 | { 207 | // FIXME: replace with memmem()? 208 | const char* crlf = std::search(peek(), beginWrite(), kCRLF, kCRLF + 2); 209 | return crlf == beginWrite() ? NULL : crlf; 210 | } 211 | 212 | const char* findCRLF(const char* start) const 213 | { 214 | assert(peek() <= start); 215 | assert(start <= beginWrite()); 216 | // FIXME: replace with memmem()? 217 | const char* crlf = std::search(start, beginWrite(), kCRLF, kCRLF + 2); 218 | return crlf == beginWrite() ? NULL : crlf; 219 | } 220 | 221 | const char* findEOL() const 222 | { 223 | const void* eol = memchr(peek(), '\n', readableBytes()); 224 | return static_cast(eol); 225 | } 226 | 227 | const char* findEOL(const char* start) const 228 | { 229 | assert(peek() <= start); 230 | assert(start <= beginWrite()); 231 | const void* eol = memchr(start, '\n', beginWrite() - start); 232 | return static_cast(eol); 233 | } 234 | 235 | // retrieve returns void, to prevent 236 | // std::string str(retrieve(readableBytes()), readableBytes()); 237 | // the evaluation of two functions are unspecified 238 | void retrieve(size_t len) 239 | { 240 | assert(len <= readableBytes()); 241 | if (len < readableBytes()) 242 | { 243 | readerIndex_ += len; 244 | } 245 | else 246 | { 247 | retrieveAll(); 248 | } 249 | } 250 | 251 | void retrieveUntil(const char* end) 252 | { 253 | assert(peek() <= end); 254 | assert(end <= beginWrite()); 255 | retrieve(end - peek()); 256 | } 257 | 258 | void retrieveInt64() 259 | { 260 | retrieve(sizeof(int64_t)); 261 | } 262 | 263 | void retrieveInt32() 264 | { 265 | retrieve(sizeof(int32_t)); 266 | } 267 | 268 | void retrieveInt16() 269 | { 270 | retrieve(sizeof(int16_t)); 271 | } 272 | 273 | void retrieveInt8() 274 | { 275 | retrieve(sizeof(int8_t)); 276 | } 277 | 278 | void retrieveAll() 279 | { 280 | readerIndex_ = kCheapPrepend; 281 | writerIndex_ = kCheapPrepend; 282 | } 283 | 284 | std::string retrieveAllAsString() 285 | { 286 | return retrieveAsString(readableBytes()); 287 | } 288 | 289 | std::string retrieveAsString(size_t len) 290 | { 291 | assert(len <= readableBytes()); 292 | std::string result(peek(), len); 293 | retrieve(len); 294 | return result; 295 | } 296 | 297 | void append(const std::string& str) 298 | { 299 | append(str.data(), str.size()); 300 | } 301 | 302 | void append(const char* /*restrict*/ data, size_t len) 303 | { 304 | ensureWritableBytes(len); 305 | std::copy(data, data + len, beginWrite()); 306 | hasWritten(len); 307 | } 308 | 309 | void append(const void* /*restrict*/ data, size_t len) 310 | { 311 | append(static_cast(data), len); 312 | } 313 | 314 | void ensureWritableBytes(size_t len) 315 | { 316 | if (writableBytes() < len) 317 | { 318 | makeSpace(len); 319 | } 320 | assert(writableBytes() >= len); 321 | } 322 | 323 | char* beginWrite() 324 | { return begin() + writerIndex_; } 325 | 326 | const char* beginWrite() const 327 | { return begin() + writerIndex_; } 328 | 329 | void hasWritten(size_t len) 330 | { 331 | assert(len <= writableBytes()); 332 | writerIndex_ += len; 333 | } 334 | 335 | void unwrite(size_t len) 336 | { 337 | assert(len <= readableBytes()); 338 | writerIndex_ -= len; 339 | } 340 | 341 | /// 342 | /// Append int64_t using network endian 343 | /// 344 | void appendInt64(int64_t x) 345 | { 346 | int64_t be64 = htobe64(x); 347 | append(&be64, sizeof be64); 348 | } 349 | 350 | /// 351 | /// Append int32_t using network endian 352 | /// 353 | void appendInt32(int32_t x) 354 | { 355 | int32_t be32 = htobe32(x); 356 | append(&be32, sizeof be32); 357 | } 358 | 359 | void appendInt16(int16_t x) 360 | { 361 | int16_t be16 = htobe16(x); 362 | append(&be16, sizeof be16); 363 | } 364 | 365 | void appendInt8(int8_t x) 366 | { 367 | append(&x, sizeof x); 368 | } 369 | 370 | /// 371 | /// Read int64_t from network endian 372 | /// 373 | /// Require: buf->readableBytes() >= sizeof(int32_t) 374 | int64_t readInt64() 375 | { 376 | int64_t result = peekInt64(); 377 | retrieveInt64(); 378 | return result; 379 | } 380 | 381 | /// 382 | /// Read int32_t from network endian 383 | /// 384 | /// Require: buf->readableBytes() >= sizeof(int32_t) 385 | int32_t readInt32() 386 | { 387 | int32_t result = peekInt32(); 388 | retrieveInt32(); 389 | return result; 390 | } 391 | 392 | int16_t readInt16() 393 | { 394 | int16_t result = peekInt16(); 395 | retrieveInt16(); 396 | return result; 397 | } 398 | 399 | int8_t readInt8() 400 | { 401 | int8_t result = peekInt8(); 402 | retrieveInt8(); 403 | return result; 404 | } 405 | 406 | /// 407 | /// Peek int64_t from network endian 408 | /// 409 | /// Require: buf->readableBytes() >= sizeof(int64_t) 410 | int64_t peekInt64() const 411 | { 412 | assert(readableBytes() >= sizeof(int64_t)); 413 | int64_t be64 = 0; 414 | ::memcpy(&be64, peek(), sizeof be64); 415 | return be64toh(be64); 416 | } 417 | 418 | /// 419 | /// Peek int32_t from network endian 420 | /// 421 | /// Require: buf->readableBytes() >= sizeof(int32_t) 422 | int32_t peekInt32() const 423 | { 424 | assert(readableBytes() >= sizeof(int32_t)); 425 | int32_t be32 = 0; 426 | ::memcpy(&be32, peek(), sizeof be32); 427 | return be32toh(be32); 428 | } 429 | 430 | int16_t peekInt16() const 431 | { 432 | assert(readableBytes() >= sizeof(int16_t)); 433 | int16_t be16 = 0; 434 | ::memcpy(&be16, peek(), sizeof be16); 435 | return be16toh(be16); 436 | } 437 | 438 | int8_t peekInt8() const 439 | { 440 | assert(readableBytes() >= sizeof(int8_t)); 441 | int8_t x = *peek(); 442 | return x; 443 | } 444 | 445 | /// 446 | /// Prepend int64_t using network endian 447 | /// 448 | void prependInt64(int64_t x) 449 | { 450 | int64_t be64 = htobe64(x); 451 | prepend(&be64, sizeof be64); 452 | } 453 | 454 | /// 455 | /// Prepend int32_t using network endian 456 | /// 457 | void prependInt32(int32_t x) 458 | { 459 | int32_t be32 = htobe32(x); 460 | prepend(&be32, sizeof be32); 461 | } 462 | 463 | void prependInt16(int16_t x) 464 | { 465 | int16_t be16 = htobe16(x); 466 | prepend(&be16, sizeof be16); 467 | } 468 | 469 | void prependInt8(int8_t x) 470 | { 471 | prepend(&x, sizeof x); 472 | } 473 | 474 | void prepend(const std::string& str) 475 | { 476 | prepend(str.data(), str.size()); 477 | } 478 | 479 | void prepend(const void* /*restrict*/ data, size_t len) 480 | { 481 | ensurePrependableBytes(len); 482 | readerIndex_ -= len; 483 | const char* d = static_cast(data); 484 | std::copy(d, d + len, begin() + readerIndex_); 485 | } 486 | 487 | void ensurePrependableBytes(size_t len) 488 | { 489 | if (len > prependableBytes()) 490 | { 491 | makeSpaceForPrepend(len); 492 | } 493 | assert(prependableBytes() >= len); 494 | } 495 | 496 | size_t internalCapacity() const 497 | { 498 | return buffer_.capacity(); 499 | } 500 | 501 | private: 502 | 503 | char* begin() 504 | { return &*buffer_.begin(); } 505 | 506 | const char* begin() const 507 | { return &*buffer_.begin(); } 508 | 509 | void makeSpace(size_t len) 510 | { 511 | if (writableBytes() + prependableBytes() < len + kCheapPrepend) 512 | { 513 | // FIXME: move readable data 514 | buffer_.resize(writerIndex_ + len); 515 | } 516 | else 517 | { 518 | // move readable data to the front, make space inside buffer 519 | assert(kCheapPrepend < readerIndex_); 520 | size_t readable = readableBytes(); 521 | std::copy(begin() + readerIndex_, 522 | begin() + writerIndex_, 523 | begin() + kCheapPrepend); 524 | readerIndex_ = kCheapPrepend; 525 | writerIndex_ = readerIndex_ + readable; 526 | assert(readable == readableBytes()); 527 | } 528 | } 529 | 530 | void makeSpaceForPrepend(size_t len) 531 | { 532 | if (len - readerIndex_ > writableBytes()) 533 | { 534 | buffer_.resize(writerIndex_ + (len - readerIndex_)); 535 | } 536 | // move readable data to the end 537 | size_t readable = readableBytes(); 538 | std::copy(begin() + readerIndex_, 539 | begin() + writerIndex_, 540 | begin() + len); 541 | readerIndex_ = len; 542 | writerIndex_ = readerIndex_ + readable; 543 | assert(readable == readableBytes()); 544 | } 545 | 546 | private: 547 | std::vector buffer_; 548 | size_t readerIndex_; 549 | size_t writerIndex_; 550 | static const char kCRLF[]; 551 | }; 552 | 553 | 554 | 555 | struct UserInputData 556 | { 557 | UserInputData(char *data = nullptr, const int len = 0) 558 | { 559 | this->len_ = len; 560 | if (len > 0) 561 | this->data_ = data; 562 | else 563 | this->data_ = nullptr; 564 | } 565 | char* data_; 566 | int len_; 567 | }; 568 | 569 | class KcpSession; 570 | typedef std::shared_ptr KcpSessionPtr; 571 | 572 | typedef std::function UserOutputFunction; 573 | typedef std::function UserInputFunction; 574 | typedef std::function CurrentTimestampMsFunction; 575 | typedef std::function* pendingSendDataDeque)> KcpSessionConnectionCallback; 576 | 577 | enum TransmitModeE { kUnreliable = 88, kReliable }; 578 | enum RoleTypeE { kSrv, kCli }; 579 | enum ConnectionStateE { kConnecting, kConnected, kResetting, kReset }; 580 | enum PktTypeE { kSyn = 66, kAck, kPsh, kRst }; 581 | 582 | 583 | class Rdc 584 | { 585 | public: 586 | typedef std::function RecvFuncion; 587 | Rdc(const UserOutputFunction& userOutputFunc, const RecvFuncion& rcvFunc) 588 | : 589 | userOutputFunc_(userOutputFunc), rcvFunc_(rcvFunc), nextSndSn_(0), nextRcvSn_(0), 590 | isThisRoundFinished_(true), on_(false), mss_(548) 591 | {} 592 | 593 | int Output(Buf* oBuf, PktTypeE pktType) 594 | { 595 | size_t curLen = oBuf->readableBytes(); 596 | if (pktType == static_cast(kUnreliable)) 597 | { 598 | size_t frgCnt = 0; 599 | if (curLen <= kUnreliableDataLenLimit + kFrgLen) 600 | frgCnt = 1; 601 | else 602 | frgCnt = (curLen + kUnreliableDataLenLimit - 1) / kUnreliableDataLenLimit; 603 | 604 | if (frgCnt >= kMaxFrgCnt) 605 | { 606 | oBuf->retrieveAll(); 607 | return -1; 608 | } 609 | 610 | size_t curDataLen = 0; 611 | size_t curHeaderLen = frgCnt > 1 ? kUnreliableHeaderLen : (kUnreliableHeaderLen - kFrgLen); 612 | size_t curDataLenLimit = kMaxMSS - curHeaderLen; 613 | for (size_t i = 0; i < frgCnt; ++i) 614 | { 615 | curDataLen = curLen > curDataLenLimit ? curDataLenLimit : curLen; 616 | oBuf->prependInt16(static_cast(curDataLen)); 617 | if (frgCnt > 1) 618 | oBuf->prependInt8(static_cast(frgCnt - i - 1)); 619 | oBuf->prependInt8(static_cast(frgCnt)); 620 | oBuf->prependInt32(nextSndSn_++); 621 | oBuf->prependInt8(static_cast(kUnreliable)); 622 | outputPktDeque_.emplace_back(std::string(oBuf->peek(), curHeaderLen + curDataLen)); 623 | oBuf->retrieve(curHeaderLen + curDataLen); 624 | curLen -= curDataLen; 625 | } 626 | assert(curLen == 0); 627 | assert(oBuf->readableBytes() == 0); 628 | 629 | HandleFlush(oBuf, frgCnt); 630 | } 631 | else /*if(pktType != kUnreliable)*/ 632 | { 633 | oBuf->prependInt16(static_cast(curLen)); 634 | oBuf->prependInt32(nextSndSn_++); 635 | oBuf->prependInt8(static_cast(pktType)); 636 | outputPktDeque_.emplace_back(std::string(oBuf->peek(), kReliableHeaderLen + curLen)); 637 | oBuf->retrieveAll(); 638 | 639 | HandleFlush(oBuf); 640 | } 641 | return 0; 642 | } 643 | 644 | bool Input(Buf* userBuf, int& len, Buf* iBuf) 645 | { 646 | PktTypeE pktType = static_cast(0); 647 | int32_t rcvSn = 0; 648 | int8_t rcvFrgCnt = 0; 649 | int8_t rcvFrg = 0; 650 | int16_t dataLen = 0; 651 | 652 | bool hasDataLeftThisRound = ParsePkt(iBuf, pktType, rcvSn, rcvFrgCnt, rcvFrg, dataLen); 653 | if (hasDataLeftThisRound) 654 | { 655 | auto discardRcvedData = [&]() { iBuf->retrieve(dataLen); len = 0; }; 656 | isThisRoundFinished_ = false; 657 | 658 | if (pktType == static_cast(kUnreliable)) 659 | { 660 | if (rcvSn >= nextRcvSn_) 661 | { 662 | nextRcvSn_ = rcvSn + 1; 663 | 664 | if (rcvFrgCnt == 1) 665 | rcvFunc_(userBuf, len, dataLen, pktType); 666 | else 667 | { 668 | if (rcvFrg != 0) 669 | { 670 | bool isHeadFrg = (rcvFrg == rcvFrgCnt - 1); 671 | if (isHeadFrg) 672 | inputFrgMap_.clear(); 673 | 674 | if (isHeadFrg || inputFrgMap_.find(rcvSn - 1) != inputFrgMap_.end()) 675 | inputFrgMap_.emplace(std::make_pair( 676 | rcvSn, std::string(iBuf->peek(), dataLen))); 677 | 678 | discardRcvedData(); 679 | } 680 | else if (rcvFrg == 0) 681 | { 682 | if (inputFrgMap_.find(rcvSn - 1) != inputFrgMap_.end()) 683 | { 684 | int sumDataLen = dataLen; 685 | for (int sn = rcvSn - 1; sn >= rcvSn - rcvFrgCnt + 1; --sn) 686 | { 687 | iBuf->prepend(inputFrgMap_[sn]); 688 | sumDataLen += static_cast(inputFrgMap_[sn].size()); 689 | } 690 | rcvFunc_(userBuf, len, sumDataLen, pktType); 691 | } 692 | else 693 | discardRcvedData(); 694 | } 695 | } /*if (rcvFrgCnt > 1)*/ 696 | } 697 | else if (rcvSn < nextRcvSn_) 698 | discardRcvedData(); 699 | } 700 | else /*if (pktType != kUnreliable)*/ 701 | { 702 | if (rcvSn >= nextRcvSn_) 703 | { 704 | nextRcvSn_ = rcvSn + 1; 705 | rcvFunc_(userBuf, len, dataLen, pktType); 706 | } 707 | else 708 | discardRcvedData(); 709 | } 710 | } 711 | else if (!hasDataLeftThisRound) 712 | { 713 | iBuf->retrieveAll(); 714 | isThisRoundFinished_ = true; 715 | len = 0; 716 | } 717 | return hasDataLeftThisRound; 718 | } 719 | 720 | bool IsThisRoundFinished() const { return isThisRoundFinished_; } 721 | 722 | void Switch(bool on) { on_ = on; } 723 | 724 | void SetMTU(size_t mtu) 725 | { assert(mtu - 28 <= kMaxMSS); mss_ = mtu - 28; } 726 | 727 | private: 728 | 729 | void FlushOutputBuffer(Buf* oBuf) 730 | { 731 | userOutputFunc_(oBuf->peek(), static_cast(oBuf->readableBytes())); 732 | oBuf->retrieveAll(); 733 | } 734 | 735 | void HandleFlush(Buf* oBuf, size_t frgCnt = 1) 736 | { 737 | if (frgCnt > 1) 738 | { 739 | for (size_t i = frgCnt; i >= 1; --i) 740 | { 741 | auto curIt = outputPktDeque_.end() - i; 742 | if (curIt->size() >= mss_) 743 | { 744 | oBuf->prepend(*curIt); 745 | FlushOutputBuffer(oBuf); 746 | outputPktDeque_.erase(curIt); 747 | } 748 | else 749 | { 750 | assert(i == 1); 751 | HandleDynamicRdc(oBuf, *curIt); 752 | } 753 | } 754 | } 755 | else if (frgCnt == 1) 756 | { 757 | HandleDynamicRdc(oBuf, outputPktDeque_.back()); 758 | } 759 | } 760 | 761 | void HandleDynamicRdc(Buf* oBuf, const std::string& pendingSndData) 762 | { 763 | // PrependPrePktAndFlush(oBuf); return; 764 | 765 | if (on_) 766 | PrependPrePktAndFlush(oBuf); 767 | else 768 | { 769 | oBuf->prepend(pendingSndData); 770 | FlushOutputBuffer(oBuf); 771 | 772 | if (pendingSndData.size() >= mss_) 773 | outputPktDeque_.pop_back(); 774 | 775 | size_t sumPktLen = 0; 776 | for (auto it = outputPktDeque_.end() - 1; it != outputPktDeque_.begin(); --it) 777 | { 778 | sumPktLen += it->size(); 779 | if (sumPktLen > mss_) 780 | { 781 | outputPktDeque_.erase(outputPktDeque_.begin(), it); 782 | break; 783 | } 784 | } 785 | } 786 | } 787 | 788 | void PrependPrePktAndFlush(Buf* oBuf) 789 | { 790 | for (size_t i = 1; i <= outputPktDeque_.size(); ++i) 791 | { 792 | auto curIt = outputPktDeque_.end() - i; 793 | bool isFront = curIt == outputPktDeque_.begin(); 794 | oBuf->prepend(*curIt); 795 | 796 | size_t prePktDataLen = 0; 797 | if (!isFront) 798 | prePktDataLen = (curIt - 1)->size(); 799 | 800 | if ((oBuf->readableBytes() + prePktDataLen >= mss_) || isFront) 801 | { 802 | if (oBuf->readableBytes() + prePktDataLen >= mss_) 803 | outputPktDeque_.erase(outputPktDeque_.begin(), curIt); 804 | FlushOutputBuffer(oBuf); 805 | break; 806 | } 807 | } 808 | } 809 | 810 | bool ParsePkt(Buf* iBuf, PktTypeE &pktType, int32_t &rcvSn, 811 | int8_t &rcvFrgCnt, int8_t &rcvFrg, int16_t &dataLen) const 812 | { 813 | bool hasDataLeftThisRound = false; 814 | if (iBuf->readableBytes() >= kPktTypeLen + kSnLen + kDataLen) 815 | { 816 | pktType = static_cast(iBuf->readInt8()); 817 | rcvSn = iBuf->readInt32(); 818 | auto checkDataLenFunc = [&](TransmitModeE tm, bool noFrg = false) { 819 | if (iBuf->readableBytes() >= kDataLen) 820 | { 821 | dataLen = iBuf->readInt16(); 822 | size_t curDataLenLimit = 0; 823 | if (tm == kReliable) 824 | curDataLenLimit = kReliableDataLenLimit; 825 | else 826 | { 827 | curDataLenLimit = kUnreliableDataLenLimit; 828 | if (noFrg) 829 | curDataLenLimit = kUnreliableDataLenLimit + kFrgLen; 830 | } 831 | if (dataLen <= static_cast(curDataLenLimit)) 832 | hasDataLeftThisRound = iBuf->readableBytes() >= static_cast(dataLen); 833 | }}; 834 | if (pktType == static_cast(kUnreliable)) 835 | { 836 | rcvFrgCnt = iBuf->readInt8(); 837 | if (rcvFrgCnt > 1 && static_cast(rcvFrgCnt) <= kMaxFrgCnt) 838 | { 839 | rcvFrg = iBuf->readInt8(); 840 | checkDataLenFunc(kUnreliable); 841 | } 842 | else if (rcvFrgCnt == 1) 843 | checkDataLenFunc(kUnreliable, true); 844 | } 845 | else 846 | checkDataLenFunc(kReliable); 847 | } 848 | return hasDataLeftThisRound; 849 | } 850 | 851 | private: 852 | static const size_t kMaxMSS = 1472; 853 | static const size_t kMaxFrgCnt = 128; 854 | 855 | static const size_t kPktTypeLen = sizeof(int8_t); 856 | static const size_t kSnLen = sizeof(int32_t); 857 | static const size_t kFrgCntLen = sizeof(int8_t); 858 | static const size_t kFrgLen = sizeof(int8_t); 859 | static const size_t kDataLen = sizeof(int16_t); 860 | 861 | static const size_t kReliableHeaderLen = kPktTypeLen + kSnLen + kDataLen; 862 | static const size_t kReliableDataLenLimit = kMaxMSS - kReliableHeaderLen; 863 | 864 | static const size_t kUnreliableHeaderLen = kPktTypeLen + kSnLen + kFrgCntLen + kFrgLen + kDataLen; 865 | static const size_t kUnreliableDataLenLimit = kMaxMSS - kUnreliableHeaderLen; 866 | 867 | RecvFuncion rcvFunc_; 868 | UserOutputFunction userOutputFunc_; 869 | std::deque outputPktDeque_; 870 | std::unordered_map inputFrgMap_; 871 | int32_t nextSndSn_; 872 | int32_t nextRcvSn_; 873 | bool isThisRoundFinished_; 874 | bool on_; 875 | size_t mss_; 876 | }; 877 | 878 | 879 | 880 | 881 | class KcpSession 882 | { 883 | public: 884 | KcpSession(const RoleTypeE role, 885 | const UserOutputFunction& userOutputFunc, 886 | const UserInputFunction& userInputFunc, 887 | const CurrentTimestampMsFunction& currentTimestampMsFunc) 888 | : 889 | role_(role), 890 | conv_(0), 891 | userInputFunc_(userInputFunc), 892 | curTsMsFunc_(currentTimestampMsFunc), 893 | kcp_(nullptr), 894 | curConnState_(kConnecting), 895 | rdc_(userOutputFunc, std::bind(&KcpSession::DoRecv, this, std::placeholders::_1, 896 | std::placeholders::_2, std::placeholders::_3, std::placeholders::_4)), 897 | nextUpdateTs_(0), 898 | hasDataLeft_(false), 899 | sndWnd_(128), 900 | rcvWnd_(128), 901 | waitSndCntLimit_(4 * sndWnd_), 902 | nodelay_(1), 903 | interval_(10), 904 | fastresend_(1), 905 | nocwnd_(1), 906 | streamMode_(0), 907 | mtu_(548), 908 | rx_minrto_(10) 909 | { 910 | if (IsClient() && !IsConnected()) 911 | for (int i = 6; i > 0; --i) 912 | SendSyn(); 913 | } 914 | 915 | /// ------ basic APIs -------- 916 | 917 | // for Application-level Congestion Control 918 | bool CheckCanSend() const 919 | { 920 | return (kcp_ ? ikcp_waitsnd(kcp_) < waitSndCntLimit_ : true) 921 | && (static_cast(pendingSndDataDeque_.size()) < waitSndCntLimit_); 922 | } 923 | 924 | // returns below zero for error 925 | int Send(const void* data, int len, TransmitModeE transmitMode = kReliable) 926 | { return SendImpl(data, len, transmitMode); } 927 | 928 | // update then returns next update timestamp in ms or returns below zero for error 929 | int64_t Update() { return UpdateImpl(); } 930 | 931 | // returns Is-Any-Data-Left, len below zero for error 932 | bool Recv(Buf* userBuf, int& len) { return RecvImpl(userBuf, len); } 933 | 934 | /// ------ advanced APIs -------- 935 | 936 | bool IsServer() const { return role_ == kSrv; } 937 | bool IsClient() const { return role_ == kCli; } 938 | 939 | ikcpcb* GetKcpInstance() const { return kcp_; } 940 | 941 | bool IsConnected() const { return curConnState_ == kConnected; } 942 | 943 | // callback on : 944 | // - client role resetting state(when server role restart, client role will switch to resetting state 945 | // and bring pending send data back to Application-level) 946 | // - cli/srv role connected state 947 | void setConnectionCallback(KcpSessionConnectionCallback cb) { connectionCallback_ = std::move(cb); } 948 | 949 | // should set before Send() 950 | void SetConfig(const int mtu = 576, const int sndWnd = 128, const int rcvWnd = 128, 951 | const int waitSndCntLimit = 512, const int nodelay = 1, const int interval = 10, const int fastresend = 1, 952 | const int nocwnd = 1, const int streamMode = 0, const int rx_minrto = 10) 953 | { 954 | assert(waitSndCntLimit > sndWnd); 955 | rdc_.SetMTU(mtu); 956 | sndWnd_ = sndWnd; rcvWnd_ = rcvWnd; waitSndCntLimit_ = waitSndCntLimit; 957 | nodelay_ = nodelay; interval_ = interval; fastresend_ = fastresend; 958 | nocwnd_ = nocwnd; streamMode_ = streamMode; rx_minrto_ = rx_minrto; 959 | } 960 | 961 | ~KcpSession() { if (kcp_) ikcp_release(kcp_); } 962 | 963 | private: 964 | 965 | int64_t UpdateImpl() 966 | { 967 | if (curConnState_ == kConnecting && IsClient()) 968 | SendSyn(); 969 | 970 | IUINT32 curTimestamp = static_cast(curTsMsFunc_()); 971 | if (kcp_ && IsConnected()) 972 | { 973 | rdc_.Switch(ikcp_rdc_check(kcp_) == 1 ? true : false); 974 | int result = FlushSndQueueBeforeConned(); 975 | if (result < 0) 976 | return result; 977 | if (curTimestamp >= nextUpdateTs_) 978 | { 979 | ikcp_update(kcp_, curTimestamp); 980 | nextUpdateTs_ = ikcp_check(kcp_, curTimestamp); 981 | } 982 | return static_cast(nextUpdateTs_); 983 | } 984 | else // not yet connected 985 | return static_cast(curTimestamp) + interval_; 986 | } 987 | 988 | int SendImpl(const void* data, int len, TransmitModeE transmitMode = kReliable) 989 | { 990 | assert(data != nullptr); 991 | assert(len > 0); 992 | assert(transmitMode == kReliable || transmitMode == kUnreliable); 993 | 994 | if (transmitMode == kUnreliable) 995 | { 996 | outputBuf_.append(data, len); 997 | int error = OutputAfterCheckingRdc(static_cast(kUnreliable)); 998 | if (error) 999 | return error; 1000 | } 1001 | else if (transmitMode == kReliable) 1002 | { 1003 | if (!IsConnected() && IsClient()) 1004 | { 1005 | pendingSndDataDeque_.emplace_back(std::string(static_cast(data), len)); 1006 | } 1007 | else if (IsConnected()) 1008 | { 1009 | int result = FlushSndQueueBeforeConned(); 1010 | if (result < 0) 1011 | return result; 1012 | result = ikcp_send(kcp_, static_cast(data), len); 1013 | if (result < 0) 1014 | return result; // ikcp_send err 1015 | else 1016 | ikcp_update(kcp_, static_cast(curTsMsFunc_())); 1017 | } 1018 | } 1019 | return 0; 1020 | } 1021 | 1022 | bool RecvImpl(Buf* userBuf, int& len) 1023 | { 1024 | if (hasDataLeft_) 1025 | { 1026 | assert(inputBuf_.readableBytes() == 0); 1027 | if (!IsConnected()) 1028 | return false; 1029 | len = KcpRecv(userBuf); // if err, -1, -2, -3 1030 | hasDataLeft_ = len > 0; 1031 | return hasDataLeft_; 1032 | } 1033 | else 1034 | { 1035 | if (rdc_.IsThisRoundFinished()) 1036 | { 1037 | const UserInputData& rawRecvdata = userInputFunc_(); 1038 | if (rawRecvdata.len_ < 0) 1039 | { 1040 | len = -10; 1041 | return false; 1042 | } 1043 | else if (rawRecvdata.len_ > 0) 1044 | inputBuf_.append(rawRecvdata.data_, rawRecvdata.len_); 1045 | } 1046 | if (!rdc_.Input(userBuf, len, &inputBuf_)) 1047 | hasDataLeft_ = true; 1048 | return true; 1049 | } 1050 | } 1051 | 1052 | int FlushSndQueueBeforeConned() 1053 | { 1054 | assert(kcp_ && IsConnected()); 1055 | if (pendingSndDataDeque_.size() > 0) 1056 | { 1057 | for (auto it = pendingSndDataDeque_.begin(); it != pendingSndDataDeque_.end(); ++it) 1058 | { 1059 | int sendRet = ikcp_send(kcp_, it->c_str(), static_cast(it->size())); 1060 | if (sendRet < 0) 1061 | return sendRet; // ikcp_send err 1062 | ikcp_update(kcp_, static_cast(curTsMsFunc_())); 1063 | } 1064 | pendingSndDataDeque_.clear(); 1065 | } 1066 | return 0; 1067 | } 1068 | 1069 | void CopyKcpDataToSndQ() 1070 | { 1071 | assert(kcp_); 1072 | IKCPSEG *seg; 1073 | struct IQUEUEHEAD *p; 1074 | for (p = kcp_->snd_buf.next; p != &kcp_->snd_buf; p = p->next) 1075 | { 1076 | seg = iqueue_entry(p, IKCPSEG, node); 1077 | pendingSndDataDeque_.emplace_back(std::string(seg->data, seg->len)); 1078 | } 1079 | for (p = kcp_->snd_queue.next; p != &kcp_->snd_queue; p = p->next) 1080 | { 1081 | seg = iqueue_entry(p, IKCPSEG, node); 1082 | pendingSndDataDeque_.emplace_back(std::string(seg->data, seg->len)); 1083 | } 1084 | } 1085 | 1086 | void DoRecv(Buf* userBuf, int& len, int readableLen, PktTypeE pktType) 1087 | { 1088 | if (pktType == static_cast(kUnreliable)) 1089 | { 1090 | userBuf->append(inputBuf_.peek(), readableLen); 1091 | len = readableLen; 1092 | } 1093 | else if (pktType == kSyn) 1094 | { 1095 | assert(IsServer()); 1096 | if (!IsConnected()) 1097 | { 1098 | SetConnState(kConnected); 1099 | InitKcp(GetNewConv()); 1100 | } 1101 | SendAckAndConv(); 1102 | len = 0; 1103 | } 1104 | else if (pktType == kAck) 1105 | { 1106 | assert(IsClient()); 1107 | int32_t rcvConv = inputBuf_.readInt32(); 1108 | readableLen -= 4; 1109 | 1110 | if (curConnState_ == kConnecting) 1111 | { 1112 | InitKcp(rcvConv); 1113 | SetConnState(kConnected); 1114 | } 1115 | len = 0; 1116 | } 1117 | else if (pktType == kRst) 1118 | { 1119 | assert(IsClient()); 1120 | if (IsConnected()) 1121 | { 1122 | CopyKcpDataToSndQ(); 1123 | SetConnState(kResetting); 1124 | } 1125 | len = 0; 1126 | } 1127 | else if (pktType == kPsh) 1128 | { 1129 | if (IsConnected()) 1130 | { 1131 | int result = ikcp_input(kcp_, inputBuf_.peek(), readableLen); 1132 | if (result == 0) 1133 | { 1134 | ikcp_update(kcp_, static_cast(curTsMsFunc_())); 1135 | len = 0; 1136 | } 1137 | else // if (result < 0) 1138 | len = result - 3; // ikcp_input err, -4, -5, -6 1139 | } 1140 | else // pktType == kPsh, but kcp not connected 1141 | { 1142 | if (IsServer()) 1143 | SendRst(); 1144 | len = 0; 1145 | } 1146 | } 1147 | else 1148 | { 1149 | len = -7; // pktType err 1150 | } 1151 | inputBuf_.retrieve(readableLen); 1152 | } 1153 | 1154 | void SendRst() 1155 | { 1156 | assert(IsServer()); 1157 | OutputAfterCheckingRdc(kRst); 1158 | } 1159 | 1160 | void SendSyn() 1161 | { 1162 | assert(IsClient()); 1163 | OutputAfterCheckingRdc(kSyn); 1164 | } 1165 | 1166 | void SendAckAndConv() 1167 | { 1168 | assert(IsServer()); 1169 | outputBuf_.appendInt32(conv_); 1170 | OutputAfterCheckingRdc(kAck); 1171 | } 1172 | 1173 | void InitKcp(const IUINT32 conv) 1174 | { 1175 | conv_ = conv; 1176 | kcp_ = ikcp_create(conv, this); 1177 | ikcp_wndsize(kcp_, sndWnd_, rcvWnd_); 1178 | ikcp_nodelay(kcp_, nodelay_, interval_, fastresend_, nocwnd_); 1179 | ikcp_setmtu(kcp_, mtu_); 1180 | kcp_->stream = streamMode_; 1181 | kcp_->rx_minrto = rx_minrto_; 1182 | kcp_->output = KcpSession::KcpPshOutputFuncRaw; 1183 | } 1184 | 1185 | IUINT32 GetNewConv() 1186 | { 1187 | assert(IsServer()); 1188 | static IUINT32 newConv = 666; 1189 | return newConv++; 1190 | } 1191 | 1192 | void SetConnState(const ConnectionStateE s) 1193 | { 1194 | ConnectionStateE lastState = curConnState_; 1195 | curConnState_ = s; 1196 | if (connectionCallback_ && lastState != s) 1197 | { 1198 | if (s == kConnected) 1199 | connectionCallback_(nullptr); 1200 | else if (s == kResetting) 1201 | connectionCallback_(&pendingSndDataDeque_); 1202 | } 1203 | } 1204 | 1205 | int KcpRecv(Buf* userBuf) 1206 | { 1207 | assert(kcp_); assert(userBuf); 1208 | int msgLen = ikcp_peeksize(kcp_); 1209 | if (msgLen <= 0) 1210 | return 0; 1211 | userBuf->ensureWritableBytes(msgLen); 1212 | ikcp_recv(kcp_, userBuf->beginWrite(), msgLen); 1213 | userBuf->hasWritten(msgLen); // cause the ret of ikcp_recv() equal to ikcp_peeksize() 1214 | return msgLen; 1215 | } 1216 | 1217 | static int KcpPshOutputFuncRaw(const char* data, int len, IKCPCB* kcp, void* user) 1218 | { 1219 | (void)kcp; 1220 | auto thisPtr = reinterpret_cast(user); 1221 | thisPtr->outputBuf_.append(data, len); 1222 | return thisPtr->OutputAfterCheckingRdc(kPsh); 1223 | } 1224 | 1225 | int OutputAfterCheckingRdc(PktTypeE pktType) { return rdc_.Output(&outputBuf_, pktType); } 1226 | 1227 | private: 1228 | ikcpcb* kcp_; 1229 | UserInputFunction userInputFunc_; 1230 | ConnectionStateE curConnState_; 1231 | Buf outputBuf_; 1232 | Buf inputBuf_; 1233 | CurrentTimestampMsFunction curTsMsFunc_; 1234 | IUINT32 conv_; 1235 | RoleTypeE role_; 1236 | std::deque pendingSndDataDeque_; 1237 | Rdc rdc_; 1238 | IUINT32 nextUpdateTs_; 1239 | KcpSessionConnectionCallback connectionCallback_; 1240 | bool hasDataLeft_; 1241 | 1242 | private: 1243 | // kcp config... 1244 | int sndWnd_; 1245 | int rcvWnd_; 1246 | int waitSndCntLimit_; 1247 | int nodelay_; 1248 | int interval_; 1249 | int fastresend_; 1250 | int nocwnd_; 1251 | int streamMode_; 1252 | int mtu_; 1253 | int rx_minrto_; 1254 | }; 1255 | 1256 | } --------------------------------------------------------------------------------