Пример #1
0
UDPSession *
UDPSession::createSession(int sockfd) {
    int flags = fcntl(sockfd, F_GETFL, 0);
    if (flags < 0) {
        return nullptr;
    }

    if (fcntl(sockfd, F_SETFL, flags | O_NONBLOCK) < 0) {
        return nullptr;
    }

    UDPSession *sess = new(UDPSession);
    sess->m_sockfd = sockfd;
    sess->m_kcp = ikcp_create(IUINT32(rand()), sess);
    sess->m_buf = (char *) malloc(UDPSession::mtuLimit);
    sess->m_streambuf = (char *) malloc(UDPSession::streamBufferLimit);
    sess->m_kcp->output = sess->out_wrapper;

    if (sess->m_kcp == nullptr || sess->m_buf == nullptr || sess->m_streambuf == nullptr) {
        if (nullptr != sess->m_kcp) { ikcp_release(sess->m_kcp); }
        if (nullptr != sess->m_buf) { free(sess->m_buf); }
        if (nullptr != sess->m_streambuf) { free(sess->m_streambuf); }
        return nullptr;
    }
    return sess;
}
Пример #2
0
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毫秒.
}
Пример #3
0
sg_etp_session_t * sg_etp_session_open(IUINT32 conv, const struct sockaddr * addr, uv_loop_t * loop, void * data)
{
    sg_etp_session_t * session = NULL;

    do
    {
        session = (sg_etp_session_t *)malloc(sizeof(sg_etp_session_t));
        SG_ASSERT_BRK(NULL != session, "create client failed");

        memset(session, 0, sizeof(sg_etp_session_t));

        session->data = data;
        session->conv = conv;

        memcpy(&(session->addr), addr, sizeof(struct sockaddr));

        if (NULL == loop) /* self-contained loop, for client */
        {
            session->loop = &(session->loop_hdl);
            uv_loop_init(session->loop);
        }
        else
        {
            session->loop = loop;
        }

        /* create the kcp object */
        session->kcp = ikcp_create(session->conv, (void*)session);
        SG_ASSERT_BRK(NULL != session->kcp, "create ikcp failed");

        session->kcp->output = on_kcp_output;

        session->timeout        = SG_ETP_SESSION_TIMEOUT;
        session->recv_data_time = uv_now(session->loop) + session->timeout;

        return session;
    } while (0);

    if (NULL != session)
    {
        free(session);
        session = NULL;
    }

    return session;
}
Пример #4
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;
	}
}
Пример #5
0
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;
}
Пример #6
0
/*@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;
}
Пример #7
0
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;
}
Пример #8
0
// 测试用例
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);
}