-
Notifications
You must be signed in to change notification settings - Fork 760
Description
Hello, I am experimenting with kcp-go and I guess I am doing something wrong.
I want to send a bigger amount of data through kcp connection... but it's weirdly slow?
Let's have this - a bit contrived, but minimal example - almost-echo server, that reads a number as a string, and sends back that many bytes of data.
package main
import (
"crypto/rand"
"fmt"
"io"
"log"
"strconv"
"strings"
"time"
"github.com/xtaci/kcp-go/v5"
)
const dataAmount = 1024 * 1024
func main() {
block, _ := kcp.NewNoneBlockCrypt(nil)
if listener, err := kcp.ListenWithOptions("127.0.0.1:12345", block, 10, 3); err == nil {
// spin-up the client
go client()
for {
s, err := listener.AcceptKCP()
if err != nil {
log.Fatal(err)
}
go handleRandData(s)
}
} else {
log.Fatal(err)
}
}
func readNumber(conn *kcp.UDPSession) (int, error) {
bl := &strings.Builder{}
bs := make([]byte, 1)
for {
_, err := io.ReadFull(conn, bs)
if err != nil {
return 0, err
}
if bs[0] == '\n' {
break
}
bl.WriteByte(bs[0])
}
return strconv.Atoi(bl.String())
}
// handleRandData reads a number and returns that many random bytes
func handleRandData(conn *kcp.UDPSession) {
for {
n, err := readNumber(conn)
if err != nil {
log.Println(err)
return
}
fmt.Println("server read")
bs := make([]byte, n)
_, err = rand.Read(bs)
if err != nil {
log.Println(err)
return
}
_, err = conn.Write(bs)
if err != nil {
log.Println(err)
return
}
fmt.Println("server sent")
}
}
func client() {
block, _ := kcp.NewNoneBlockCrypt(nil)
// wait for server to become ready
time.Sleep(time.Second)
// dial to the echo server
if sess, err := kcp.DialWithOptions("127.0.0.1:12345", block, 10, 3); err == nil {
f := time.Now()
_, err := fmt.Fprintln(sess, dataAmount)
if err != nil {
log.Fatal(err)
}
fmt.Println("client sent")
buf := make([]byte, dataAmount)
_, err = io.ReadFull(sess, buf)
if err != nil {
log.Fatal(err)
}
fmt.Println("client read", time.Since(f))
} else {
log.Fatal(err)
}
}
You can see that it works with lesser numbers; and with bigger numbers it also, sort of, works, but really really slow.
When I send 1024*1024 bytes - 1 MB - it takes 10 seconds. That is weird...? That is a lot on localhost-to-localhost! Am I sending it in a wrong way?
In comparison, when I use just TCP, it is 9 ms. See when I just convert the listeners/servers to net.Dial/net.Listen and "tcp"
package main
import (
"crypto/rand"
"fmt"
"io"
"log"
"net"
"strconv"
"strings"
"time"
)
const dataAmount = 1024 * 1024
func main() {
if listener, err := net.Listen("tcp", ":12345"); err == nil {
// spin-up the client
go client()
for {
s, err := listener.Accept()
if err != nil {
log.Fatal(err)
}
go handleRandData(s)
}
} else {
log.Fatal(err)
}
}
func readNumber(conn net.Conn) (int, error) {
bl := &strings.Builder{}
bs := make([]byte, 1)
for {
_, err := io.ReadFull(conn, bs)
if err != nil {
return 0, err
}
if bs[0] == '\n' {
break
}
bl.WriteByte(bs[0])
}
return strconv.Atoi(bl.String())
}
// handleRandData reads a number and returns that many random bytes
func handleRandData(conn net.Conn) {
for {
n, err := readNumber(conn)
if err != nil {
log.Println(err)
return
}
fmt.Println("server read")
bs := make([]byte, n)
_, err = rand.Read(bs)
if err != nil {
log.Println(err)
return
}
_, err = conn.Write(bs)
if err != nil {
log.Println(err)
return
}
fmt.Println("server sent")
}
}
func client() {
// wait for server to become ready
time.Sleep(time.Second)
// dial to the echo server
if sess, err := net.Dial("tcp", "127.0.0.1:12345"); err == nil {
f := time.Now()
_, err := fmt.Fprintln(sess, dataAmount)
if err != nil {
log.Fatal(err)
}
fmt.Println("client sent")
buf := make([]byte, dataAmount)
_, err = io.ReadFull(sess, buf)
if err != nil {
log.Fatal(err)
}
fmt.Println("client read", time.Since(f))
} else {
log.Fatal(err)
}
}
I probably do something wrong, but I miss what