void connection::init_kcp(const kcp_conv_t& conv) { conv_ = conv; p_kcp_ = ikcp_create(conv, (void*)this); p_kcp_->output = &connection::udp_output; // 启动快速模式 // 第二个参数 nodelay-启用以后若干常规加速将启动 // 第三个参数 interval为内部处理时钟,默认设置为 10ms // 第四个参数 resend为快速重传指标,设置为2 // 第五个参数 为是否禁用常规流控,这里禁止 //ikcp_nodelay(p_kcp_, 1, 10, 2, 1); ikcp_nodelay(p_kcp_, 1, 5, 1, 1); // 设置成1次ACK跨越直接重传, 这样反应速度会更快. 内部时钟5毫秒. }
static int lnodelay(lua_State *l) { struct kcpctx *ctx = (struct kcpctx *)luaL_checkudata(l, 1, LKCP_MT); if (!ctx) return luaL_argerror(l, 1, "parameter self invalid."); assert(ctx->kcp); int nodelay = (int)luaL_optinteger(l, 2, 0); int interval = (int)luaL_optinteger(l, 3, 40); int resend = (int)luaL_optinteger(l, 4, 0); int nc = (int)luaL_optinteger(l, 5, 0); ikcp_nodelay(ctx->kcp, nodelay, interval, resend, nc); return 0; }
int main() { client_sock = make_sock("127.0.0.1"); ikcpcb *kcp = ikcp_create(0x11223344, (void*)0); kcp->output = udp_output; ikcp_wndsize(kcp, 128, 128); ikcp_nodelay(kcp, 0, 10, 0, 0); char buf[ECHO_LEN]; char *buf_in; char *msg = "hello"; int i=0; int current; int ret; for(;;) { ++i; isleep(1); current = iclock(); ikcp_update(kcp, current); if (i % 1000 == 0) { sprintf(buf, "%s:%d, %u", msg, i, current); ret = ikcp_send(kcp, buf, strlen(buf)); check(ret >= 0, "send"); printf("send [%s]\n", buf); } ret = recv(client_sock, buf, ECHO_LEN-1, 0); check_silently(ret > 0); ikcp_input(kcp, buf, ret); printf("\nrecv from server raw: %s\n", buf); ret = ikcp_recv(kcp, buf, ECHO_LEN-1); check_silently(ret > 0); buf[ret] = '\0'; printf("\nrecv from server: %s\n", buf); error: continue; } }
int Conn::init(kcpuv_conv_t conv, const sockaddr* addr, uv_udp_t* handle) { _conv = conv; _addr = *addr; _udp = handle; int r = -1; _kcp = ikcp_create(conv, (void*)this); CHK_COND(_kcp); _kcp->output = on_kcp_output; r = ikcp_nodelay(_kcp, 1, 10, 2, 1); PROC_ERR(r); return 0; Exit0: return -1; }
/*@ckcpuv*/ int conn_init(conn_t * thiz, kcpuv_conv_t conv, const struct sockaddr* addr, uv_udp_t* handle) { thiz->_conv = conv; thiz->_addr = *addr; thiz->_udp = handle; int r = -1; thiz->_kcp = ikcp_create(conv, (void*)thiz); CHK_COND(thiz->_kcp); thiz->_kcp->output = on_kcp_output; r = ikcp_nodelay(thiz->_kcp, 1, 10, 2, 1); PROC_ERR(r); return 0; Exit0: return -1; }
static int lcreate(lua_State *l) { lua_Integer conv = luaL_checkinteger(l, 1); int32_t ref = luaL_ref(l, LUA_REGISTRYINDEX); struct kcpctx *ctx = (struct kcpctx *)lua_newuserdata(l, sizeof(*ctx)); assert(ctx); ctx->ud = (void *)l; ctx->conv = (int32_t)conv; ctx->ref = ref; ctx->timeout = 0; ctx->kcp = ikcp_create(conv, ctx); assert(ctx->kcp); ikcp_nodelay(ctx->kcp, 0, 40, 0, 0); // normal mode ikcp_setoutput(ctx->kcp, udp_output); luaL_getmetatable(l, LKCP_MT); lua_setmetatable(l, -2); return 1; }
int sg_etp_session_start(sg_etp_session_t * session, int interval_ms, uv_udp_t * udp) { int ret = ERROR; SG_ASSERT_RET(NULL != session, "session pointer is NULL", ret); session->interval = interval_ms; if (NULL == udp) /* self-contained udp, for client */ { /* init udp */ session->udp = &(session->udp_hdl); ret = uv_udp_init(session->loop, session->udp); SG_ASSERT_RET(ret >= 0, "init udp failed", ERROR); session->udp->data = session; ret = uv_udp_recv_start(session->udp, on_uv_alloc_buffer, on_client_recv_udp); SG_ASSERT_RET(ret >= 0, "start udp recv failed", ERROR); } else { session->udp = udp; } ret = ikcp_nodelay(session->kcp, 1, interval_ms, 2, 0); SG_ASSERT_RET(ret >= 0, "ikcp nodelay failed", ERROR); /* start a timer for kcp update and receiving */ ret = uv_timer_init(session->loop, &(session->timer)); SG_ASSERT_RET(ret >= 0, "init timer failed", ERROR); session->timer.data = session; /* link client pointer to timer */ ret = uv_timer_start(&(session->timer), on_uv_timer_cb, session->interval, session->interval); SG_ASSERT_RET(ret >= 0, "start timer failed", ERROR); uv_idle_init(session->loop, &(session->idle)); session->idle.data = session; SG_CALLBACK(session->on_open, session); return OK; }
// 测试用例 void test(int mode) { // 创建模拟网络:丢包率10%,Rtt 60ms~125ms vnet = new LatencySimulator(10, 60, 125); // 创建两个端点的 kcp对象,第一个参数 conv是会话编号,同一个会话需要相同 // 最后一个是 user参数,用来传递标识 ikcpcb *kcp1 = ikcp_create(0x11223344, (void*)0); ikcpcb *kcp2 = ikcp_create(0x11223344, (void*)1); // 设置kcp的下层输出,这里为 udp_output,模拟udp网络输出函数 kcp1->output = udp_output; kcp2->output = udp_output; IUINT32 current = iclock(); IUINT32 slap = current + 20; IUINT32 index = 0; IUINT32 next = 0; IINT64 sumrtt = 0; int count = 0; int maxrtt = 0; // 配置窗口大小:平均延迟200ms,每20ms发送一个包, // 而考虑到丢包重发,设置最大收发窗口为128 ikcp_wndsize(kcp1, 128, 128); ikcp_wndsize(kcp2, 128, 128); // 判断测试用例的模式 if (mode == 0) { // 默认模式 ikcp_nodelay(kcp1, 0, 10, 0, 0); ikcp_nodelay(kcp2, 0, 10, 0, 0); } else if (mode == 1) { // 普通模式,关闭流控等 ikcp_nodelay(kcp1, 0, 10, 0, 1); ikcp_nodelay(kcp2, 0, 10, 0, 1); } else { // 启动快速模式 // 第二个参数 nodelay-启用以后若干常规加速将启动 // 第三个参数 interval为内部处理时钟,默认设置为 10ms // 第四个参数 resend为快速重传指标,设置为2 // 第五个参数 为是否禁用常规流控,这里禁止 ikcp_nodelay(kcp1, 1, 10, 2, 1); ikcp_nodelay(kcp2, 1, 10, 2, 1); kcp1->rx_minrto = 10; kcp1->fastresend = 1; } char buffer[2000]; int hr; IUINT32 ts1 = iclock(); while (1) { isleep(1); current = iclock(); ikcp_update(kcp1, iclock()); ikcp_update(kcp2, iclock()); // 每隔 20ms,kcp1发送数据 for (; current >= slap; slap += 20) { ((IUINT32*)buffer)[0] = index++; ((IUINT32*)buffer)[1] = current; // 发送上层协议包 ikcp_send(kcp1, buffer, 8); } // 处理虚拟网络:检测是否有udp包从p1->p2 while (1) { hr = vnet->recv(1, buffer, 2000); if (hr < 0) break; // 如果 p2收到udp,则作为下层协议输入到kcp2 ikcp_input(kcp2, buffer, hr); } // 处理虚拟网络:检测是否有udp包从p2->p1 while (1) { hr = vnet->recv(0, buffer, 2000); if (hr < 0) break; // 如果 p1收到udp,则作为下层协议输入到kcp1 ikcp_input(kcp1, buffer, hr); } // kcp2接收到任何包都返回回去 while (1) { hr = ikcp_recv(kcp2, buffer, 10); // 没有收到包就退出 if (hr < 0) break; // 如果收到包就回射 ikcp_send(kcp2, buffer, hr); } // kcp1收到kcp2的回射数据 while (1) { hr = ikcp_recv(kcp1, buffer, 10); // 没有收到包就退出 if (hr < 0) break; IUINT32 sn = *(IUINT32*)(buffer + 0); IUINT32 ts = *(IUINT32*)(buffer + 4); IUINT32 rtt = current - ts; if (sn != next) { // 如果收到的包不连续 printf("ERROR sn %d<->%d\n", (int)count, (int)next); return; } next++; sumrtt += rtt; count++; if (rtt > (IUINT32)maxrtt) maxrtt = rtt; printf("[RECV] mode=%d sn=%d rtt=%d\n", mode, (int)sn, (int)rtt); } if (next > 1000) break; } ts1 = iclock() - ts1; ikcp_release(kcp1); ikcp_release(kcp2); const char *names[3] = { "default", "normal", "fast" }; printf("%s mode result (%dms):\n", names[mode], (int)ts1); printf("avgrtt=%d maxrtt=%d tx=%d\n", (int)(sumrtt / count), (int)maxrtt, (int)vnet->tx1); printf("press enter to next ...\n"); char ch; scanf("%c", &ch); }