skywind3000/kcp: an ARQ protocol in two C files that trades bandwidth for latency
:zap: KCP - A Fast and Reliable ARQ Protocol
At a glance
- What is it?
- KCP is a pure-algorithm reliable transport that runs over whatever datagram layer you already have. It costs 10 to 20 percent more bandwidth than TCP to cut average latency by 30 to 40 percent, and it never makes a system call of its own.
- Who is it for?
- Adopt KCP when you already own a UDP path and the thing you are optimizing is per-packet delivery time, not throughput.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 99 days ago.
- What is it written in?
- Mainly C, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The problem KCP solves: TCP optimizes for volume, not for arrival time
TCP is designed around how many kilobytes per second a link can carry. The README makes the distinction explicit: TCP is a wide, slow canal, while KCP is a narrow stream with fast water. Every mechanism in TCP that improves bandwidth utilization, delayed ACKs, retransmitting everything after a lost segment, doubling RTO on each consecutive loss, works against a small packet that needs to arrive now.
KCP is for the case where you already have a datagram channel (usually UDP) and you need reliability on top of it without inheriting TCP's timing behavior. The README names the audience directly: someone who has written a P2P layer or a UDP-based protocol and lacks a complete ARQ implementation. The pitch is that copying ikcp.h and ikcp.c into an existing project and writing a couple of lines gets you there.
This is not a general replacement for TCP. It is a component. It has no opinion about how packets reach the other side, and it is not a socket library.
How the ARQ loop actually works: callbacks in, callbacks out, an external clock
The repository is two source files, ikcp.h and ikcp.c, plus test.cpp, test.h, protocol.txt and a CMakeLists.txt. There is no networking code in the library itself. The README states plainly that KCP does not handle the underlying protocol's send and receive, that the user defines how lower-layer packets are sent and supplies that as a callback, and that even the clock is passed in from outside. It makes no system call internally.
The data flow has four entry points. ikcp_create(conv, user) allocates a session, where conv is a session number that both ends must agree on, the same idea as a TCP connection identifier. You assign kcp->output, a function KCP calls whenever it has bytes to put on the wire. You call ikcp_update(kcp, millisec) on a timer to advance protocol state. Incoming datagrams go to ikcp_input(kcp, received_udp_packet, received_udp_size). Application data goes out through ikcp_send and comes back through ikcp_recv.
The acceleration comes from four specific choices described in the README. On timeout, TCP doubles RTO (three losses means RTO times eight); KCP's fast mode multiplies by 1.5 instead. On loss, TCP retransmits everything from the lost segment forward; KCP retransmits selectively. KCP infers loss from skipped ACKs: if the sender transmits 1 through 5 and receives ACKs for 1, 3, 4 and 5, the ACK for 3 means packet 2 was skipped once, the ACK for 4 means twice, and at that point 2 is treated as lost and retransmitted without waiting for a timeout. Finally, KCP lets you turn off delayed ACKs, which TCP sends to fill bandwidth and which inflate the measured RTT.
The fifth choice is in the wire format. ARQ responses come in two flavors: UNA, meaning everything below this number has arrived, and ACK, meaning this specific packet arrived. UNA alone forces full retransmission; ACK alone makes loss accounting expensive. KCP carries UNA information in every packet except standalone ACK packets, so both signals travel together.
Installing kcp and getting a first session running
There is no package to install for the library itself. You take the two files. The README does document one managed route, through Microsoft's vcpkg, which keeps a kcp port that Microsoft team members and community contributors maintain:
git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.sh
./vcpkg integrate install
./vcpkg install kcpThe README notes that if the vcpkg port falls behind, the fix is an issue or a pull request on the vcpkg repository, not here. For everything else, copy ikcp.c and ikcp.h into your tree. The repository also ships a CMakeLists.txt, so a CMake-based project has a build path without vcpkg.
Once the files are in place, four steps wire up a session. The README gives each one as a snippet. First create the object:
ikcpcb *kcp = ikcp_create(conv, user);Then hand KCP the function it should call to emit bytes:
int udp_output(const char *buf, int len, ikcpcb *kcp, void *user)
{
....
}
kcp->output = udp_output;Drive the state machine from a timer. The README suggests calling ikcp_update every 10ms, or using ikcp_check to find out when the next update is due instead of calling it constantly:
ikcp_update(kcp, millisec);Feed received datagrams in from your socket loop:
ikcp_input(kcp, received_udp_packet, received_udp_size);After that, ikcp_send writes to the peer and ikcp_recv reads what arrived. What you should see is your own UDP socket carrying KCP-formatted packets, and no new sockets opened by the library. If nothing is transmitted, the usual cause is that ikcp_update is not being called or the output callback is not set.
Out of the box the protocol is a plain ARQ. The acceleration switches are off until you set them:
ikcp_nodelay(kcp, 1, 10, 2, 1);The four arguments are nodelay (1 enables it), interval in milliseconds (10 or 20 are the README's examples), resend (2 means a packet skipped by two ACK crossings is retransmitted immediately), and nc (1 disables flow control). The README lists ikcp_nodelay(kcp, 0, 40, 0, 0) as normal mode and ikcp_nodelay(kcp, 1, 10, 2, 1) as the fast mode. Window size defaults to 32 and is set with ikcp_wndsize(kcp, sndwnd, rcvwnd), counted in packets rather than bytes, unlike TCP's SND_BUF and RCV_BUF. MTU defaults to 1400 bytes and is changed with ikcp_setmtu; the README points out that a pure-algorithm protocol does not probe MTU, so discovery is your problem. Minimum RTO defaults to 100ms, or 30ms in fast mode, and is changed by assigning kcp->rx_minrto = 10 directly.
Where KCP is the wrong tool
The bandwidth cost is real and stated up front: 10 to 20 percent more than TCP. On a metered or congested link that is a genuine trade, not a rounding error. If your workload is bulk transfer where total time matters more than per-packet latency, TCP already does that job and does it without you writing a session layer.
The non-retreat flow control option is the sharpest edge. Normally KCP uses the same fair-backoff rule as TCP, with the send window determined by send buffer size, the receiver's remaining buffer, loss backoff, and slow start. Setting nc to 1 skips the last two and uses only the first two. The README is candid about the price: reduced fairness and reduced bandwidth utilization, bought in exchange for smooth transmission even while a BitTorrent client is saturating the link. That is a deliberate choice to be a bad network citizen in exchange for latency, and it will not endear you to anyone sharing the pipe.
Two operational gaps follow from the design. Because the library makes no system calls, there is no thread of its own: you must call ikcp_update on a schedule, and if your output callback blocks, you are blocking whatever thread is driving the protocol. And because KCP does not probe MTU, a path with a smaller MTU than your configured value will fragment or drop, and the library will not discover it.
The README also flags a version split. KCP is now at V2, which adds a pluggable flow control mechanism so the algorithm can be swapped without changing the protocol. V1 is described as sufficiently stable and lives on the v1 branch. If you are pinning a dependency, that is the branch decision you have to make before anything else.
Alternatives, and how they differ in approach
The most direct comparison is kcptun, which the README lists first among open source cases. kcptun is a remote port forwarder built on kcp-go, the Go implementation of KCP. The difference is one of scope: KCP is a library you embed and drive yourself, while kcptun is a finished tunnel binary that pairs with ssh -D. If you want a tunnel, kcptun is the shorter path. If you need reliability inside your own protocol, kcptun is the wrong layer.
The language ports matter for the same reason. kcp-go, kcp-java, kcp-netty, java-Kcp, kcp.kt, kcp-rs, kcp-rust, tokio-kcp, kcp-cpp, kcp-perl and the several C# ports listed in the README all reimplement the same protocol in a runtime that manages memory and concurrency for you. Choosing one of those over the C original usually means you want the session management and threading that the C library deliberately omits. The README points to asio-kcp as a complete UDP network library with connection state management, session control and KCP scheduling, which is exactly the layer the two C files leave out.
Against QUIC, the split is architectural. QUIC is a full transport with its own handshake, encryption and multiplexing. KCP is an ARQ algorithm with no handshake and no encryption; the README's documentation index lists network encryption as a separate wiki topic, which tells you it is not in the library. If you need TLS-grade security as a baseline rather than an add-on, KCP is the wrong starting point.
Maintenance, licence, and what upgrading costs
The repository is not archived and the last push was on 2026-06-23. Three releases landed in the months before that: 2.1.1 on 2026-05-15, 2.0.0 on 2026-05-14, and 1.7.1 on 2026-05-01. The 2.0.0 release is the one that introduced the pluggable flow control mechanism described in the README, so anyone on 1.x is looking at a protocol-level change, not a patch, when they move to V2.
The upgrade path is unusual in a good way: because the library is two files, upgrading means replacing ikcp.c and ikcp.h. There is no build system to reconcile beyond the CMakeLists.txt, no transitive dependency tree, and no ABI surface beyond the functions you call. The cost is that you own the diff. The README does not document a migration guide from v1 to v2, and it does not document rollback. The only stated guidance is that v1 remains on the v1 branch for projects that do not want the flow control change.
The licence is MIT, per the repository's LICENSE file and the badge in the README. MIT permits use in closed-source products and requires preserving the copyright notice and licence text. That is the extent of what the README and LICENSE support; whether MIT fits a given product's compliance process is a question for your own legal review, not something this repository answers.
Editorial conclusion
Adopt KCP when you already own a UDP path and the thing you are optimizing is per-packet delivery time, not throughput. Do not adopt it if you want a socket API, congestion fairness against TCP, or encryption out of the box: the README points at wiki pages for those, and none of them are in ikcp.c. Before committing, verify two things in your own build: that your output callback never blocks the thread calling ikcp_update, and that you have decided who owns the clock, because KCP will not read one for you.
Frequently asked questions
What is the KCP protocol?
KCP is a fast, reliable ARQ protocol implemented purely as an algorithm. It does not handle the underlying transport such as UDP, does not make any system calls, and takes its clock from the caller. The README describes it as trading 10 to 20 percent more bandwidth than TCP for 30 to 40 percent lower average latency.
How do I install KCP?
There is no package for the library itself; you copy ikcp.c and ikcp.h into your project. The README also documents installing it through the vcpkg library manager with ./vcpkg install kcp, and the repository ships a CMakeLists.txt for CMake-based builds.
Why does KCP need me to provide a clock and an output callback?
KCP is a pure algorithm that does not perform any system call internally, so it cannot send packets or read time on its own. You assign kcp->output to the function that transmits bytes, call ikcp_update with a millisecond value on a timer, and pass received datagrams to ikcp_input.
Does KCP provide encryption or MTU discovery?
Neither is in the library. The README states that a pure-algorithm protocol does not probe MTU and that the default is 1400 bytes, settable with ikcp_setmtu. Encryption is listed as a separate topic in the wiki documentation index rather than as a feature of ikcp.c.
What is the difference between KCP v1 and v2?
V2 adds a pluggable flow control mechanism so the flow control algorithm can be replaced without changing the protocol. The README says v1 is sufficiently stable and keeps it on the v1 branch.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/skywind3000-kcp)