diff --git a/README.en.md b/README.en.md index 1e22c10..cb32787 100644 --- a/README.en.md +++ b/README.en.md @@ -147,6 +147,7 @@ Both the use and configuration of the protocol is very simple, in most cases, af - [asio-kcp](https://github.com/libinzhangyuan/asio_kcp): Use the complete UDP network library of KCP, complete implementation of UDP-based link state management, session control and KCP protocol scheduling, etc. - [kcp-java](https://github.com/hkspirt/kcp-java):Implementation of Java version of KCP protocol. - [kcp-netty](https://github.com/szhnet/kcp-netty):Java implementation of KCP based on Netty. +- [java-kcp](https://github.com/l42111996/java-Kcp): JAVA version KCP, based on netty implementation (including fec function) - [kcp-go](https://github.com/xtaci/kcp-go): High-security GO language implementation of kcp, including simple implementation of UDP session management, as a base library for subsequent development. - [kcp-csharp](https://github.com/limpo1989/kcp-csharp): The csharp migration of kcp, containing the session management, which can access the above kcp-go server. - [kcp-rs](https://github.com/en/kcp-rs): The rust migration of KCP @@ -176,13 +177,21 @@ Thanks to [zhangyuan](https://github.com/libinzhangyuan) the author of [asio-kcp For specifics please refer to: [Reliable Udp Benchmark](https://github.com/libinzhangyuan/reliable_udp_bench_mark) and [KCP-Benchmark](https://github.com/skywind3000/kcp/wiki/KCP-Benchmark), for more guidance to the hesitant users. +MMO Engine [SpatialOS](https://improbable.io/spatialOS) has a benchmark report on KCP/TCP/RakNet: + +![](https://raw.githubusercontent.com/skywind3000/kcp/master/images/spatialos-50.png) + +for more details, please see the report itself: + +- [Kcp a new low latency secure network stack](https://improbable.io/blog/kcp-a-new-low-latency-secure-network-stack) + # KCP is used by See [Success Stories](https://github.com/skywind3000/kcp/wiki/Success-Stories). # Donation -![欢迎使用支付宝对该项目进行捐赠](https://raw.githubusercontent.com/skywind3000/kcp/master/donation.png) +![欢迎使用支付宝对该项目进行捐赠](https://raw.githubusercontent.com/skywind3000/kcp/master/images/donation.png) Donation is welcome by using alipay, the money will be used to improve the protocol and documentation. diff --git a/README.md b/README.md index 10ecbb0..0e742c2 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ KCP - A Fast and Reliable ARQ Protocol ====================================== -[![Powered][2]][1] [![Build Status][4]][5] -[![Backers on Open Collective](https://opencollective.com/kcp/backers/badge.svg)](#backers) +[![Powered][2]][1] [![Build Status][4]][5] +[![Backers on Open Collective](https://opencollective.com/kcp/backers/badge.svg)](#backers) [![Sponsors on Open Collective](https://opencollective.com/kcp/sponsors/badge.svg)](#sponsors) [1]: https://github.com/skywind3000/kcp @@ -146,6 +146,7 @@ TCP是为流量设计的(每秒内可以传输多少KB的数据),讲究的 - [asio-kcp](https://github.com/libinzhangyuan/asio_kcp): 使用 KCP的完整 UDP网络库,完整实现了基于 UDP的链接状态管理,会话控制,KCP协议调度等 - [kcp-java](https://github.com/hkspirt/kcp-java):Java版本 KCP协议实现。 - [kcp-netty](https://github.com/szhnet/kcp-netty):kcp的Java语言实现,基于netty。 +- [java-kcp](https://github.com/l42111996/java-Kcp): JAVA版本KCP,基于netty实现(包含fec功能) - [kcp-go](https://github.com/xtaci/kcp-go): 高安全性的kcp的 GO语言实现,包含 UDP会话管理的简单实现,可以作为后续开发的基础库。 - [kcp-csharp](https://github.com/limpo1989/kcp-csharp): kcp的 csharp移植,同时包含一份回话管理,可以连接上面kcp-go的服务端。 - [kcp-csharp](https://github.com/KumoKyaku/KCP): 新版本 Kcp的 csharp移植。线程安全,运行时无alloc,对gc无压力。 @@ -169,6 +170,7 @@ TCP是为流量设计的(每秒内可以传输多少KB的数据),讲究的 - [CC](http://cc.163.com/):网易 CC 使用 kcp 加速视频推流,有效提高流畅性 - [BOBO](http://bobo.163.com/):网易 BOBO 使用 kcp 加速主播推流 - [云帆加速](http://www.yfcloud.com/):使用 KCP 加速文件传输和视频推流,优化了台湾主播推流的流畅度 +- [SpatialOS](https://improbable.io/spatialOS): 大型多人分布式游戏服务端引擎,BigWorld 的后继者,使用 KCP 加速数据传输。 欢迎告知更多案例 @@ -190,12 +192,21 @@ TCP是为流量设计的(每秒内可以传输多少KB的数据),讲究的 具体见:[横向比较](https://github.com/libinzhangyuan/reliable_udp_bench_mark) 和 [评测数据](https://github.com/skywind3000/kcp/wiki/KCP-Benchmark),为犹豫选择的人提供了更多指引。 +大型多人游戏服务端引擎 [SpatialOS](https://improbable.io/spatialOS) 在集成 KCP 协议后做了同 TCP/RakNet 的评测: +![](https://raw.githubusercontent.com/skywind3000/kcp/master/images/spatialos-50.png) +对比了在服务端刷新率为 60 Hz 同时维护 50 个角色时的响应时间,详细对比报告见: + +- [Kcp a new low latency secure network stack](https://improbable.io/blog/kcp-a-new-low-latency-secure-network-stack) + +# 项目历史 + +See [Success Stories](https://github.com/skywind3000/kcp/wiki/Success-Stories). # 欢迎捐赠 -![欢迎使用支付宝对该项目进行捐赠](https://raw.githubusercontent.com/skywind3000/kcp/master/donation.png) +![欢迎使用支付宝对该项目进行捐赠](https://raw.githubusercontent.com/skywind3000/kcp/master/images/donation.png) 欢迎使用支付宝手扫描上面的二维码,对该项目进行捐赠。捐赠款项将用于持续优化 KCP协议以及完善文档。 diff --git a/ikcp.c b/ikcp.c index bb1a0c6..2334fd6 100644 --- a/ikcp.c +++ b/ikcp.c @@ -43,6 +43,7 @@ const IUINT32 IKCP_THRESH_INIT = 2; const IUINT32 IKCP_THRESH_MIN = 2; const IUINT32 IKCP_PROBE_INIT = 7000; // 7 secs to probe window size const IUINT32 IKCP_PROBE_LIMIT = 120000; // up to 120 secs to probe window +const IUINT32 IKCP_FASTACK_LIMIT = 5; // max times to trigger fastack //--------------------------------------------------------------------- @@ -66,7 +67,7 @@ static inline const char *ikcp_decode8u(const char *p, unsigned char *c) /* encode 16 bits unsigned int (lsb) */ static inline char *ikcp_encode16u(char *p, unsigned short w) { -#if IWORDS_BIG_ENDIAN +#if IWORDS_BIG_ENDIAN || IWORDS_MUST_ALIGN *(unsigned char*)(p + 0) = (w & 255); *(unsigned char*)(p + 1) = (w >> 8); #else @@ -79,7 +80,7 @@ static inline char *ikcp_encode16u(char *p, unsigned short w) /* decode 16 bits unsigned int (lsb) */ static inline const char *ikcp_decode16u(const char *p, unsigned short *w) { -#if IWORDS_BIG_ENDIAN +#if IWORDS_BIG_ENDIAN || IWORDS_MUST_ALIGN *w = *(const unsigned char*)(p + 1); *w = *(const unsigned char*)(p + 0) + (*w << 8); #else @@ -92,7 +93,7 @@ static inline const char *ikcp_decode16u(const char *p, unsigned short *w) /* encode 32 bits unsigned int (lsb) */ static inline char *ikcp_encode32u(char *p, IUINT32 l) { -#if IWORDS_BIG_ENDIAN +#if IWORDS_BIG_ENDIAN || IWORDS_MUST_ALIGN *(unsigned char*)(p + 0) = (unsigned char)((l >> 0) & 0xff); *(unsigned char*)(p + 1) = (unsigned char)((l >> 8) & 0xff); *(unsigned char*)(p + 2) = (unsigned char)((l >> 16) & 0xff); @@ -107,7 +108,7 @@ static inline char *ikcp_encode32u(char *p, IUINT32 l) /* decode 32 bits unsigned int (lsb) */ static inline const char *ikcp_decode32u(const char *p, IUINT32 *l) { -#if IWORDS_BIG_ENDIAN +#if IWORDS_BIG_ENDIAN || IWORDS_MUST_ALIGN *l = *(const unsigned char*)(p + 3); *l = *(const unsigned char*)(p + 2) + (*l << 8); *l = *(const unsigned char*)(p + 1) + (*l << 8); @@ -283,6 +284,7 @@ ikcpcb* ikcp_create(IUINT32 conv, void *user) kcp->logmask = 0; kcp->ssthresh = IKCP_THRESH_INIT; kcp->fastresend = 0; + kcp->fastlimit = IKCP_FASTACK_LIMIT; kcp->nocwnd = 0; kcp->xmit = 0; kcp->dead_link = IKCP_DEADLINK; @@ -604,7 +606,7 @@ static void ikcp_parse_una(ikcpcb *kcp, IUINT32 una) } } -static void ikcp_parse_fastack(ikcpcb *kcp, IUINT32 sn) +static void ikcp_parse_fastack(ikcpcb *kcp, IUINT32 sn, IUINT32 ts) { struct IQUEUEHEAD *p, *next; @@ -618,7 +620,12 @@ static void ikcp_parse_fastack(ikcpcb *kcp, IUINT32 sn) break; } else if (sn != seg->sn) { + #ifndef IKCP_FASTACK_CONSERVE seg->fastack++; + #else + if (_itimediff(ts, seg->ts) >= 0) + seg->fastack++; + #endif } } } @@ -741,8 +748,8 @@ void ikcp_parse_data(ikcpcb *kcp, IKCPSEG *newseg) //--------------------------------------------------------------------- int ikcp_input(ikcpcb *kcp, const char *data, long size) { - IUINT32 una = kcp->snd_una; - IUINT32 maxack = 0; + IUINT32 prev_una = kcp->snd_una; + IUINT32 maxack = 0, latest_ts = 0; int flag = 0; if (ikcp_canlog(kcp, IKCP_LOG_INPUT)) { @@ -791,9 +798,18 @@ int ikcp_input(ikcpcb *kcp, const char *data, long size) if (flag == 0) { flag = 1; maxack = sn; + latest_ts = ts; } else { if (_itimediff(sn, maxack) > 0) { + #ifndef IKCP_FASTACK_CONSERVE maxack = sn; + latest_ts = ts; + #else + if (_itimediff(ts, latest_ts) > 0) { + maxack = sn; + latest_ts = ts; + } + #endif } } if (ikcp_canlog(kcp, IKCP_LOG_IN_ACK)) { @@ -853,10 +869,10 @@ int ikcp_input(ikcpcb *kcp, const char *data, long size) } if (flag != 0) { - ikcp_parse_fastack(kcp, maxack); + ikcp_parse_fastack(kcp, maxack, latest_ts); } - if (_itimediff(kcp->snd_una, una) > 0) { + if (_itimediff(kcp->snd_una, prev_una) > 0) { if (kcp->cwnd < kcp->rmt_wnd) { IUINT32 mss = kcp->mss; if (kcp->cwnd < kcp->ssthresh) { @@ -1048,11 +1064,14 @@ void ikcp_flush(ikcpcb *kcp) lost = 1; } else if (segment->fastack >= resent) { - needsend = 1; - segment->xmit++; - segment->fastack = 0; - segment->resendts = current + segment->rto; - change++; + if ((int)segment->xmit <= kcp->fastlimit || + kcp->fastlimit <= 0) { + needsend = 1; + segment->xmit++; + segment->fastack = 0; + segment->resendts = current + segment->rto; + change++; + } } if (needsend) { diff --git a/ikcp.h b/ikcp.h index 866d188..e525105 100644 --- a/ikcp.h +++ b/ikcp.h @@ -225,7 +225,7 @@ typedef struct IQUEUEHEAD iqueue_head; //--------------------------------------------------------------------- -// WORD ORDER +// BYTE ORDER & ALIGNMENT //--------------------------------------------------------------------- #ifndef IWORDS_BIG_ENDIAN #ifdef _BIG_ENDIAN_ @@ -248,6 +248,17 @@ typedef struct IQUEUEHEAD iqueue_head; #endif #endif +#ifndef IWORDS_MUST_ALIGN + #if defined(__i386__) || defined(__i386) || defined(_i386_) + #define IWORDS_MUST_ALIGN 0 + #elif defined(_M_IX86) || defined(_X86_) || defined(__x86_64__) + #define IWORDS_MUST_ALIGN 0 + #elif defined(__amd64) || defined(__amd64__) + #define IWORDS_MUST_ALIGN 0 + #else + #define IWORDS_MUST_ALIGN 1 + #endif +#endif //===================================================================== @@ -298,6 +309,7 @@ struct IKCPCB void *user; char *buffer; int fastresend; + int fastlimit; int nocwnd, stream; int logmask; int (*output)(const char *buf, int len, struct IKCPCB *kcp, void *user); diff --git a/donation.png b/images/donation.png similarity index 100% rename from donation.png rename to images/donation.png diff --git a/images/spatialos-25.png b/images/spatialos-25.png new file mode 100644 index 0000000..eab42ed Binary files /dev/null and b/images/spatialos-25.png differ diff --git a/images/spatialos-50.png b/images/spatialos-50.png new file mode 100644 index 0000000..3f63732 Binary files /dev/null and b/images/spatialos-50.png differ