From 37f653c74ec9f9e839d7b51b5e999ce32504cbaf Mon Sep 17 00:00:00 2001 From: "sijie.sun" Date: Mon, 27 Jan 2025 23:04:55 +0800 Subject: [PATCH] add examples and readme --- README.md | 66 ++++++++++++++++++++++++++++++++++++++++++ examples/udp_client.rs | 58 +++++++++++++++++++++++++++++++++++++ examples/udp_server.rs | 49 +++++++++++++++++++++++++++++++ src/packet_def.rs | 10 +++++-- 4 files changed, 181 insertions(+), 2 deletions(-) create mode 100644 examples/udp_client.rs create mode 100644 examples/udp_server.rs diff --git a/README.md b/README.md index 8289177..622a8ad 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,69 @@ # kcp-sys Safe bindings to the [kcp](https://github.com/skywind3000/kcp) transport protocol library. + +Also including a high level API for connection state management and data stream handling. + +## Usage + +1. Create the endpoint and run it. + + ```rust + let mut endpoint = KcpEndpoint::new(); + endpoint.run().await; + ``` + +2. forward the input and output to your transport layer, udp for example. + + ```rust + let (input, mut output) = (endpoint.input_sender(), endpoint.output_receiver().unwrap()); + + let udp_socket = Arc::new(UdpSocket::bind("0.0.0.0:54320").await.unwrap()); + udp_socket.connect("127.0.0.1:54321").await.unwrap(); + + let udp = udp_socket.clone(); + tokio::spawn(async move { + while let Some(data) = output.recv().await { + udp.send(&data.inner()).await.unwrap(); + } + }); + + let udp = udp_socket.clone(); + tokio::spawn(async move { + loop { + let mut buf = vec![0; 1024]; + let (size, _) = udp.recv_from(&mut buf).await.unwrap(); + input + .send(BytesMut::from(&buf[..size]).into()) + .await + .unwrap(); + } + }); + ``` +4. Create a connection and send / recv data. + + ```rust + let conn_id = endpoint + .connect(Duration::from_secs(1), 0, 0, Bytes::new()) + .await + .unwrap(); + + let mut kcp_stream = KcpStream::new(&endpoint, conn_id).unwrap(); + kcp_stream.write_all(b"hello world").await.unwrap(); + + let mut buf = vec![0; 64 * 1024]; + let size = kcp_stream.read(&mut buf).await.unwrap(); + + println!("{}", String::from_utf8_lossy(&buf[..size])); + ``` + +## Tune the kcp parameters + +You can tune the kcp parameters by set a config factory to the endpoint. + +```rust +let mut endpoint = KcpEndpoint::new(); +endpoint.set_kcp_config_factory(|conv| { + KcpConfig::new_turbo(conv) +}); +``` diff --git a/examples/udp_client.rs b/examples/udp_client.rs new file mode 100644 index 0000000..a4efe5a --- /dev/null +++ b/examples/udp_client.rs @@ -0,0 +1,58 @@ +use std::{sync::Arc, time::Duration}; + +use kcp_sys::{ + endpoint::*, + packet_def::{Bytes, BytesMut}, + stream::KcpStream, +}; +use tokio::{ + io::{AsyncReadExt, AsyncWriteExt}, + net::UdpSocket, +}; + +#[tokio::main] +async fn main() { + let mut endpoint = KcpEndpoint::new(); + endpoint.run().await; + + let (input, mut output) = (endpoint.input_sender(), endpoint.output_receiver().unwrap()); + + let udp_socket = Arc::new(UdpSocket::bind("0.0.0.0:54320").await.unwrap()); + udp_socket.connect("127.0.0.1:54321").await.unwrap(); + + let udp = udp_socket.clone(); + tokio::spawn(async move { + while let Some(data) = output.recv().await { + udp.send(&data.inner()).await.unwrap(); + } + }); + + let udp = udp_socket.clone(); + tokio::spawn(async move { + loop { + let mut buf = vec![0; 1024]; + let (size, _) = udp.recv_from(&mut buf).await.unwrap(); + input + .send(BytesMut::from(&buf[..size]).into()) + .await + .unwrap(); + } + }); + + loop { + let conn_id = endpoint + .connect(Duration::from_secs(1), 0, 0, Bytes::new()) + .await + .unwrap(); + + let mut kcp_stream = KcpStream::new(&endpoint, conn_id).unwrap(); + kcp_stream.write_all(b"hello world").await.unwrap(); + kcp_stream.flush().await.unwrap(); + + let mut buf = vec![0; 64 * 1024]; + let size = kcp_stream.read(&mut buf).await.unwrap(); + + println!("{}", String::from_utf8_lossy(&buf[..size])); + tokio::time::sleep(Duration::from_secs(1)).await; + } +} diff --git a/examples/udp_server.rs b/examples/udp_server.rs new file mode 100644 index 0000000..3c37196 --- /dev/null +++ b/examples/udp_server.rs @@ -0,0 +1,49 @@ +use std::sync::Arc; + +use kcp_sys::{endpoint::*, packet_def::BytesMut, stream::KcpStream}; +use tokio::{ + io::{AsyncReadExt, AsyncWriteExt}, + net::UdpSocket, +}; + +#[tokio::main] +async fn main() { + let mut endpoint = KcpEndpoint::new(); + endpoint.run().await; + + let (input, mut output) = (endpoint.input_sender(), endpoint.output_receiver().unwrap()); + + let udp_socket = Arc::new(UdpSocket::bind("0.0.0.0:54321").await.unwrap()); + udp_socket.connect("127.0.0.1:54320").await.unwrap(); + + let udp = udp_socket.clone(); + tokio::spawn(async move { + while let Some(data) = output.recv().await { + udp.send(&data.inner()).await.unwrap(); + } + }); + + let udp = udp_socket.clone(); + tokio::spawn(async move { + loop { + let mut buf = vec![0; 1024]; + let (size, _) = udp.recv_from(&mut buf).await.unwrap(); + input + .send(BytesMut::from(&buf[..size]).into()) + .await + .unwrap(); + } + }); + + loop { + let conn_id = endpoint.accept().await.unwrap(); + let mut kcp_stream = KcpStream::new(&endpoint, conn_id).unwrap(); + + let mut buf = vec![0; 64 * 1024]; + let size = kcp_stream.read(&mut buf).await.unwrap(); + println!("server recv {}", String::from_utf8_lossy(&buf[..size])); + + kcp_stream.write_all(&buf[..size]).await.unwrap(); + kcp_stream.flush().await.unwrap(); + } +} diff --git a/src/packet_def.rs b/src/packet_def.rs index 731bb0e..c77c258 100644 --- a/src/packet_def.rs +++ b/src/packet_def.rs @@ -1,8 +1,9 @@ use std::fmt::Formatter; - -use bytes::{Bytes, BytesMut}; use zerocopy::{AsBytes, FromBytes, FromZeroes, LittleEndian, U32}; +pub type BytesMut = bytes::BytesMut; +pub type Bytes = bytes::Bytes; + bitflags::bitflags! { #[derive(Debug)] struct KcpPacketHeaderFlags: u8 { @@ -188,6 +189,7 @@ impl std::fmt::Debug for KcpPacketHeader { } } + #[derive(Clone)] pub struct KcpPacket { inner: BytesMut, @@ -256,4 +258,8 @@ impl KcpPacket { pub fn inner(self) -> BytesMut { self.inner } + + pub fn len(&self) -> usize { + self.inner.len() + } }