mirror of
https://github.com/xtaci/kcptun.git
synced 2024-04-21 12:32:32 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
61e69d9d5b | ||
|
|
11cdc2038c | ||
|
|
1908dc391e | ||
|
|
51e6b381bf | ||
|
|
3531726339 | ||
|
|
53f814ec9f | ||
|
|
375640d183 | ||
|
|
ae2ba18b08 | ||
|
|
717df77668 | ||
|
|
b61a2c240c | ||
|
|
bfe3524d74 | ||
|
|
8b3b38eeef | ||
|
|
754b4a7186 | ||
|
|
229a4a8783 | ||
|
|
052f0a5397 | ||
|
|
8e74cf410c | ||
|
|
206df4b69f | ||
|
|
4ccc922059 | ||
|
|
1e88951c54 | ||
|
|
6540e3e90a | ||
|
|
9ac03a973b | ||
|
|
f911127426 |
+5
-2
@@ -30,8 +30,8 @@ A tool for converting tcp stream into kcp+udp stream, :zap: ***[download address
|
||||
### *QuickStart* :lollipop:
|
||||
Client, server, respectively, download the corresponding platform binary compression package, and extract, through the following command to start port forwarding.
|
||||
```
|
||||
Server: ./server_linux_amd64 -t "SERVER_IP:8388" -l ":4000"
|
||||
Client: ./client_darwin_amd64 -r "SERVER_IP:4000" -l ":8388"
|
||||
Server: ./server_linux_amd64 -t "SERVER_IP:8388" -l ":4000" -mode fast2
|
||||
Client: ./client_darwin_amd64 -r "SERVER_IP:4000" -l ":8388" -mode fast2
|
||||
```
|
||||
The above command can establish 8388/tcp port forwarding (through 4000/udp port).
|
||||
|
||||
@@ -109,6 +109,9 @@ GLOBAL OPTIONS:
|
||||
--help, -h show help
|
||||
--version, -v print the version
|
||||
```
|
||||
#### *Parameters by Layers* :lollipop:
|
||||
|
||||
<p align="left"><img src="layeredparams.png" alt="params" height="450px"/></p>
|
||||
|
||||
### *Applications* :lollipop:
|
||||
1. Real-time gaming.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<p align="center"><img src="logo.png" alt="kcptun" height="60px" /></p>
|
||||
<p align="center"><em>也许是世界上最快的UDP传输工具</em></p>
|
||||
<p align="center"><em>A Simple UDP Tunnel Based On KCP</em></p>
|
||||
|
||||
-
|
||||
|
||||
@@ -34,8 +34,8 @@
|
||||
|
||||
客户端、服务器分别**下载**对应平台的二进制压缩包,并**解压**,通过下面的命令**启动**端口转发。
|
||||
```
|
||||
服务器: ./server_linux_amd64 -t "服务器IP地址:8388" -l ":4000"
|
||||
客户端: ./client_darwin_amd64 -r "服务器IP地址:4000" -l ":8388"
|
||||
服务器: ./server_linux_amd64 -t "服务器IP地址:8388" -l ":4000" -mode fast2
|
||||
客户端: ./client_darwin_amd64 -r "服务器IP地址:4000" -l ":8388" -mode fast2
|
||||
```
|
||||
以上命令可以实现8388/tcp端口的转发(通过4000/udp端口)。
|
||||
|
||||
@@ -114,6 +114,9 @@ GLOBAL OPTIONS:
|
||||
--help, -h show help
|
||||
--version, -v print the version
|
||||
```
|
||||
#### 分层参数图
|
||||
|
||||
<p align="left"><img src="layeredparams.png" alt="params" height="450px"/></p>
|
||||
|
||||
### 内置模式
|
||||
|
||||
@@ -131,6 +134,8 @@ GLOBAL OPTIONS:
|
||||
* 搭配2. fast2 + FEC(10,3)
|
||||
* 搭配3. fast2 + FEC(0,0)
|
||||
|
||||
默认profile参考: https://github.com/xtaci/kcptun/blob/master/client/main.go#L248
|
||||
|
||||
### 前向纠错
|
||||
|
||||
前向纠错采用Reed Solomon纠删码, 它的基本原理如下: 给定n个数据块d1, d2,…, dn,n和一个正整数m, RS根据n个数据块生成m个校验块, c1, c2,…, cm。 对于任意的n和m, 从n个原始数据块和m 个校验块中任取n块就能解码出原始数据, 即RS最多**容忍m个数据块或者校验块同时丢失**。
|
||||
@@ -316,7 +321,8 @@ type Snmp struct {
|
||||
|
||||
> 郑H立, 南东风, Li, 七七, 凌君, 昶,LesMiserables, KyOn, 噼里啪啦, 继斌, 小苍辛苦, **Ken**,
|
||||
> 乔槁, 佳晨, 猪肉佬, lcx, 昊文, 冰峰, 凡, alex, **海豹叔叔**, 奥姐, 张冰, 司成,
|
||||
> 武子, **慎**,Alex43211,**Coxxs**,荣,NeroNg,吴骁,定一
|
||||
> 武子, **慎**,Alex43211,**Coxxs**,荣,NeroNg,吴骁,定一,我不是林J,Patrick, 超, 陈,windfarer, 宇,
|
||||
> 今晶,斌,晓东,最后一缕阳光。
|
||||
|
||||
好人一生平安!
|
||||
|
||||
@@ -326,6 +332,7 @@ type Snmp struct {
|
||||
2. https://github.com/EasyPi/openwrt-kcptun
|
||||
3. https://github.com/kuoruan/luci-app-kcptun
|
||||
4. https://github.com/dfdragon/kcptun_gclient
|
||||
5. https://github.com/dfdragon/kcptun_xclient
|
||||
|
||||
### 参考资料
|
||||
|
||||
|
||||
+13
-1
@@ -12,7 +12,7 @@ fi
|
||||
|
||||
VERSION=`date -u +%Y%m%d`
|
||||
LDFLAGS="-X main.VERSION=$VERSION -s -w"
|
||||
GCFLAGS="-B"
|
||||
GCFLAGS=""
|
||||
|
||||
OSES=(linux darwin windows freebsd)
|
||||
ARCHS=(amd64 386)
|
||||
@@ -40,3 +40,15 @@ done
|
||||
if $UPX; then upx -9 client_linux_arm* server_linux_arm*;fi
|
||||
tar -zcf kcptun-linux-arm-$VERSION.tar.gz client_linux_arm* server_linux_arm*
|
||||
$MD5 kcptun-linux-arm-$VERSION.tar.gz
|
||||
|
||||
#MIPS32LE
|
||||
env CGO_ENABLED=0 GOOS=linux GOARCH=mipsle go build -ldflags "$LDFLAGS" -gcflags "$GCFLAGS" -o client_linux_mipsle github.com/xtaci/kcptun/client
|
||||
env CGO_ENABLED=0 GOOS=linux GOARCH=mipsle go build -ldflags "$LDFLAGS" -gcflags "$GCFLAGS" -o server_linux_mipsle github.com/xtaci/kcptun/server
|
||||
env CGO_ENABLED=0 GOOS=linux GOARCH=mips go build -ldflags "$LDFLAGS" -gcflags "$GCFLAGS" -o client_linux_mips github.com/xtaci/kcptun/client
|
||||
env CGO_ENABLED=0 GOOS=linux GOARCH=mips go build -ldflags "$LDFLAGS" -gcflags "$GCFLAGS" -o server_linux_mips github.com/xtaci/kcptun/server
|
||||
|
||||
if $UPX; then upx -9 client_linux_mips* server_linux_mips*;fi
|
||||
tar -zcf kcptun-linux-mipsle-$VERSION.tar.gz client_linux_mipsle server_linux_mipsle
|
||||
tar -zcf kcptun-linux-mips-$VERSION.tar.gz client_linux_mips server_linux_mips
|
||||
$MD5 kcptun-linux-mipsle-$VERSION.tar.gz
|
||||
$MD5 kcptun-linux-mips-$VERSION.tar.gz
|
||||
|
||||
@@ -29,6 +29,8 @@ type Config struct {
|
||||
SockBuf int `json:"sockbuf"`
|
||||
KeepAlive int `json:"keepalive"`
|
||||
Log string `json:"log"`
|
||||
SnmpLog string `json:"snmplog"`
|
||||
SnmpPeriod int `json:"snmpperiod"`
|
||||
}
|
||||
|
||||
func parseJSONConfig(config *Config, path string) error {
|
||||
|
||||
+60
-13
@@ -2,6 +2,8 @@ package main
|
||||
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"encoding/csv"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"math/rand"
|
||||
@@ -53,7 +55,12 @@ func newCompStream(conn net.Conn) *compStream {
|
||||
return c
|
||||
}
|
||||
|
||||
func handleClient(p1, p2 io.ReadWriteCloser) {
|
||||
func handleClient(sess *smux.Session, p1 io.ReadWriteCloser) {
|
||||
p2, err := sess.OpenStream()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
log.Println("stream opened")
|
||||
defer log.Println("stream closed")
|
||||
defer p1.Close()
|
||||
@@ -196,6 +203,16 @@ func main() {
|
||||
Value: 10, // nat keepalive interval in seconds
|
||||
Hidden: true,
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "snmplog",
|
||||
Value: "",
|
||||
Usage: "collect snmp to file, aware of timeformat in golang, like: ./snmp-20060102.log",
|
||||
},
|
||||
cli.IntFlag{
|
||||
Name: "snmpperiod",
|
||||
Value: 60,
|
||||
Usage: "snmp collect period, in seconds",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "log",
|
||||
Value: "",
|
||||
@@ -231,6 +248,8 @@ func main() {
|
||||
config.SockBuf = c.Int("sockbuf")
|
||||
config.KeepAlive = c.Int("keepalive")
|
||||
config.Log = c.String("log")
|
||||
config.SnmpLog = c.String("snmplog")
|
||||
config.SnmpPeriod = c.Int("snmpperiod")
|
||||
|
||||
if c.String("c") != "" {
|
||||
err := parseJSONConfig(&config, c.String("c"))
|
||||
@@ -306,6 +325,8 @@ func main() {
|
||||
log.Println("keepalive:", config.KeepAlive)
|
||||
log.Println("conn:", config.Conn)
|
||||
log.Println("autoexpire:", config.AutoExpire)
|
||||
log.Println("snmplog:", config.SnmpLog)
|
||||
log.Println("snmpperiod:", config.SnmpPeriod)
|
||||
|
||||
smuxConfig := smux.DefaultConfig()
|
||||
smuxConfig.MaxReceiveBuffer = config.SockBuf
|
||||
@@ -371,9 +392,13 @@ func main() {
|
||||
|
||||
chScavenger := make(chan *smux.Session, 128)
|
||||
go scavenger(chScavenger)
|
||||
go snmpLogger(config.SnmpLog, config.SnmpPeriod)
|
||||
rr := uint16(0)
|
||||
for {
|
||||
p1, err := listener.AcceptTCP()
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
if err := p1.SetReadBuffer(config.SockBuf); err != nil {
|
||||
log.Println("TCP SetReadBuffer:", err)
|
||||
}
|
||||
@@ -383,23 +408,14 @@ func main() {
|
||||
checkError(err)
|
||||
idx := rr % numconn
|
||||
|
||||
OPEN_P2:
|
||||
// do auto expiration
|
||||
if config.AutoExpire > 0 && time.Now().After(muxes[idx].ttl) {
|
||||
// do auto expiration && reconnection
|
||||
if muxes[idx].session.IsClosed() || (config.AutoExpire > 0 && time.Now().After(muxes[idx].ttl)) {
|
||||
chScavenger <- muxes[idx].session
|
||||
muxes[idx].session = waitConn()
|
||||
muxes[idx].ttl = time.Now().Add(time.Duration(config.AutoExpire) * time.Second)
|
||||
}
|
||||
|
||||
// do session open
|
||||
p2, err := muxes[idx].session.OpenStream()
|
||||
if err != nil { // mux failure
|
||||
chScavenger <- muxes[idx].session
|
||||
muxes[idx].session = waitConn()
|
||||
muxes[idx].ttl = time.Now().Add(time.Duration(config.AutoExpire) * time.Second)
|
||||
goto OPEN_P2
|
||||
}
|
||||
go handleClient(p1, p2)
|
||||
go handleClient(muxes[idx].session, p1)
|
||||
rr++
|
||||
}
|
||||
}
|
||||
@@ -438,3 +454,34 @@ func scavenger(ch chan *smux.Session) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func snmpLogger(path string, interval int) {
|
||||
if path == "" || interval == 0 {
|
||||
return
|
||||
}
|
||||
ticker := time.NewTicker(time.Duration(interval) * time.Second)
|
||||
defer ticker.Stop()
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
f, err := os.OpenFile(time.Now().Format(path), os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
w := csv.NewWriter(f)
|
||||
// write header in empty file
|
||||
if stat, err := f.Stat(); err == nil && stat.Size() == 0 {
|
||||
if err := w.Write(append([]string{"Unix"}, kcp.DefaultSnmp.Header()...)); err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
if err := w.Write(append([]string{fmt.Sprint(time.Now().Unix())}, kcp.DefaultSnmp.ToSlice()...)); err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
kcp.DefaultSnmp.Reset()
|
||||
w.Flush()
|
||||
f.Close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 59 KiB |
@@ -27,6 +27,8 @@ type Config struct {
|
||||
SockBuf int `json:"sockbuf"`
|
||||
KeepAlive int `json:"keepalive"`
|
||||
Log string `json:"log"`
|
||||
SnmpLog string `json:"snmplog"`
|
||||
SnmpPeriod int `json:"snmpperiod"`
|
||||
}
|
||||
|
||||
func parseJSONConfig(config *Config, path string) error {
|
||||
|
||||
@@ -2,6 +2,8 @@ package main
|
||||
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"encoding/csv"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"math/rand"
|
||||
@@ -218,6 +220,16 @@ func main() {
|
||||
Value: 10, // nat keepalive interval in seconds
|
||||
Hidden: true,
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "snmplog",
|
||||
Value: "",
|
||||
Usage: "collect snmp to file, aware of timeformat in golang, like: ./snmp-20060102.log",
|
||||
},
|
||||
cli.IntFlag{
|
||||
Name: "snmpperiod",
|
||||
Value: 60,
|
||||
Usage: "snmp collect period, in seconds",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "log",
|
||||
Value: "",
|
||||
@@ -251,6 +263,8 @@ func main() {
|
||||
config.SockBuf = c.Int("sockbuf")
|
||||
config.KeepAlive = c.Int("keepalive")
|
||||
config.Log = c.String("log")
|
||||
config.SnmpLog = c.String("snmplog")
|
||||
config.SnmpPeriod = c.Int("snmpperiod")
|
||||
|
||||
if c.String("c") != "" {
|
||||
//Now only support json config file
|
||||
@@ -322,6 +336,8 @@ func main() {
|
||||
log.Println("dscp:", config.DSCP)
|
||||
log.Println("sockbuf:", config.SockBuf)
|
||||
log.Println("keepalive:", config.KeepAlive)
|
||||
log.Println("snmplog:", config.SnmpLog)
|
||||
log.Println("snmpperiod:", config.SnmpPeriod)
|
||||
|
||||
if err := lis.SetDSCP(config.DSCP); err != nil {
|
||||
log.Println("SetDSCP:", err)
|
||||
@@ -332,6 +348,8 @@ func main() {
|
||||
if err := lis.SetWriteBuffer(config.SockBuf); err != nil {
|
||||
log.Println("SetWriteBuffer:", err)
|
||||
}
|
||||
|
||||
go snmpLogger(config.SnmpLog, config.SnmpPeriod)
|
||||
for {
|
||||
if conn, err := lis.AcceptKCP(); err == nil {
|
||||
log.Println("remote address:", conn.RemoteAddr())
|
||||
@@ -354,3 +372,34 @@ func main() {
|
||||
}
|
||||
myApp.Run(os.Args)
|
||||
}
|
||||
|
||||
func snmpLogger(path string, interval int) {
|
||||
if path == "" || interval == 0 {
|
||||
return
|
||||
}
|
||||
ticker := time.NewTicker(time.Duration(interval) * time.Second)
|
||||
defer ticker.Stop()
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
f, err := os.OpenFile(time.Now().Format(path), os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
w := csv.NewWriter(f)
|
||||
// write header in empty file
|
||||
if stat, err := f.Stat(); err == nil && stat.Size() == 0 {
|
||||
if err := w.Write(append([]string{"Unix"}, kcp.DefaultSnmp.Header()...)); err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
if err := w.Write(append([]string{fmt.Sprint(time.Now().Unix())}, kcp.DefaultSnmp.ToSlice()...)); err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
kcp.DefaultSnmp.Reset()
|
||||
w.Flush()
|
||||
f.Close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user