Compare commits

...
Author SHA1 Message Date
xtaci 0afdefb26b print nocomp 2016-06-27 10:31:45 +08:00
xtaci d15bede44c Merge branch 'master' of https://github.com/xtaci/kcptun 2016-06-27 10:28:49 +08:00
xtaci d97ba4c499 add snappy compression to connection 2016-06-27 10:28:24 +08:00
Daniel FuandGitHub 8ee35e13e3 Update README.md 2016-06-26 13:48:42 +08:00
Daniel FuandGitHub b60f359079 Update README.md 2016-06-26 13:43:28 +08:00
xtaci 230d1f4924 update png 2016-06-25 14:00:46 +08:00
xtaci 2178e1ec5c update 2016-06-25 12:55:07 +08:00
Daniel FuandGitHub cc5ba0ed97 Update README.md 2016-06-25 10:14:36 +08:00
Daniel FuandGitHub 74ddf68026 Add files via upload 2016-06-24 13:01:22 +08:00
Daniel FuandGitHub e4eea23681 Update README.md 2016-06-24 12:59:01 +08:00
Daniel FuandGitHub a12b0ec4f5 Add files via upload 2016-06-24 12:57:19 +08:00
Daniel FuandGitHub fb9fcf27b4 Add files via upload 2016-06-24 12:48:22 +08:00
Daniel FuandGitHub 96e91bdfa1 Update README.md 2016-06-24 12:43:37 +08:00
Daniel FuandGitHub 0d42b4d33a Update README.md 2016-06-23 17:13:48 +08:00
Daniel FuandGitHub 2d70c7f2a7 Update README.md 2016-06-22 18:14:01 +08:00
Daniel FuandGitHub aaa3ac9aaa Update README.md 2016-06-22 18:13:01 +08:00
xtaci 160bfd068d golint 2016-06-22 17:41:40 +08:00
xtaci afec250d4c fix print 2016-06-22 17:08:13 +08:00
xtaci 65c6c049fa Forward Error Correction methods Upgraded to Reed-Solomon Code 2016-06-22 16:54:08 +08:00
xtaci 694ebe22d5 update travis.yml 2016-06-21 19:58:16 +08:00
xtaci 90b24143ba update travis.yml 2016-06-21 19:55:37 +08:00
xtaci f9f408d641 update 2016-06-21 19:52:08 +08:00
xtaci 02598db6a0 update 2016-06-21 19:50:13 +08:00
xtaci 96d816c6c4 update 2016-06-21 19:25:24 +08:00
xtaci 05ea181b9f update travis.yml 2016-06-21 19:23:30 +08:00
Daniel FuandGitHub f3b6d66ba9 Update README.md 2016-06-21 17:20:37 +08:00
Daniel FuandGitHub 42c89c85d4 Add files via upload 2016-06-21 17:19:45 +08:00
Daniel FuandGitHub 5922f3a101 Add files via upload 2016-06-21 16:22:54 +08:00
Daniel FuandGitHub 4409fc3ce4 Update README.md 2016-06-21 16:18:47 +08:00
Daniel FuandGitHub e1e0bf98c3 Update README.md 2016-06-21 16:08:09 +08:00
Daniel FuandGitHub faa093858e Add files via upload 2016-06-21 16:04:10 +08:00
xtaci b398657ffe Merge branch 'master' of https://github.com/xtaci/kcptun 2016-06-21 14:40:32 +08:00
xtaci 7dc5376427 add coveralls 2016-06-21 14:40:07 +08:00
Daniel FuandGitHub 576088c625 Update README.md 2016-06-21 14:28:50 +08:00
Daniel FuandGitHub 2655e30025 Update README.md 2016-06-21 13:26:09 +08:00
xtaci 30e82f95ee add .travis.yml 2016-06-21 13:24:57 +08:00
Daniel FuandGitHub 702c6a10cc Update README.md 2016-06-20 12:48:09 +08:00
Daniel FuandGitHub eb5d2ebd83 Update README.md 2016-06-20 12:39:17 +08:00
Daniel FuandGitHub b173fc328d Update README.md 2016-06-20 12:35:08 +08:00
xtaci b4f8dc05aa fix a race condition on mulitple connections 2016-06-16 16:24:44 +08:00
xtaci 0abdcf1672 adjust type 2016-06-15 12:42:05 +08:00
xtaci 61252eeeae fix overflow 2016-06-15 12:40:21 +08:00
xtaci 2065a3eb42 fix 2016-06-15 10:02:12 +08:00
xtaci 9f6bbce901 change default value 2016-06-14 23:00:53 +08:00
xtaci be37419c81 add support for establishing multiplex physical connections 2016-06-14 22:47:26 +08:00
xtaci b6c057acf6 add none encryption 2016-06-13 17:43:56 +08:00
xtaci b3c1b29362 add simple xor 2016-06-13 11:36:09 +08:00
xtaci b83fc9f2cb support BlockCrypt interface 2016-06-13 10:43:17 +08:00
xtaci e21c3ef047 fix 2016-06-13 10:41:01 +08:00
xtaci 64e17a1e1a support BlockCrypt interface 2016-06-13 10:25:26 +08:00
Daniel FuandGitHub 2606affaa1 Update README.md 2016-06-12 22:45:49 +08:00
Daniel FuandGitHub c71c1dabaa Update README.md 2016-06-12 22:33:13 +08:00
Daniel FuandGitHub 013557c785 Update README.md 2016-06-12 22:08:45 +08:00
Daniel FuandGitHub 91d31f0700 Update README.md 2016-06-11 23:09:17 +08:00
xtaci 2f0657c417 Merge branch 'master' of https://github.com/xtaci/kcptun 2016-06-10 21:43:09 +08:00
xtaci 1b24c8b887 optional cipher method 2016-06-10 21:41:55 +08:00
Daniel Fu b398980f6b Update README.md 2016-06-08 15:31:51 +08:00
Daniel Fu fb4f969580 Update README.md 2016-06-08 10:12:30 +08:00
Daniel Fu 779ebaace9 Add files via upload 2016-06-07 13:34:48 +08:00
Daniel Fu 2f326580f0 Add files via upload 2016-06-07 13:31:08 +08:00
Daniel Fu 3477196a67 Update README.md 2016-06-06 20:18:45 +08:00
Daniel Fu e1aa9eecc6 Update README.md 2016-06-06 20:15:24 +08:00
Daniel Fu e0a2a413c9 Update README.md 2016-06-06 20:14:05 +08:00
11 changed files with 271 additions and 68 deletions
+16
View File
@@ -0,0 +1,16 @@
language: go
go:
- 1.6
before_install:
- go get github.com/mattn/goveralls
- go get golang.org/x/tools/cmd/cover
install:
- go get github.com/xtaci/kcptun/client
- go get github.com/xtaci/kcptun/server
before_script:
script:
- cd $HOME/gopath/src/github.com/xtaci/kcptun/client
- $HOME/gopath/bin/goveralls -service=travis-ci
- cd $HOME/gopath/src/github.com/xtaci/kcptun/server
- $HOME/gopath/bin/goveralls -service=travis-ci
- exit 0
+59 -21
View File
@@ -1,9 +1,26 @@
# *kcptun*
# <img src="logo.png" alt="kcptun" height="60px" />
[![GoDoc][1]][2] [![Build Status][3]][4] [![Go Report Card][5]][6] [![Coverage Statusd][7]][8]
[1]: https://godoc.org/github.com/xtaci/kcptun?status.svg
[2]: https://godoc.org/github.com/xtaci/kcptun
[3]: https://travis-ci.org/xtaci/kcptun.svg?branch=master
[4]: https://travis-ci.org/xtaci/kcptun
[5]: https://goreportcard.com/badge/xtaci/kcptun
[6]: https://goreportcard.com/report/xtaci/kcptun
[7]: https://coveralls.io/repos/github/xtaci/kcptun/badge.svg?branch=master
[8]: https://coveralls.io/github/xtaci/kcptun?branch=master
TCP流转换为KCP+UDP流,:zap:***[下载地址](https://github.com/xtaci/kcptun/releases/latest)***:zap:工作示意图:
![kcptun](kcptun.png)
***kcptun是[kcp](https://github.com/xtaci/kcp-go)协议的一个简单应用,可以用于任意tcp网络程序的传输承载,以提高网络流畅度,降低掉线情况。***
***kcptun是[kcp](https://github.com/xtaci/kcp-go)协议的一个简单应用,可以用于任意tcp网络程序的传输承载,以提高在丢包环境下的网络流畅度。***
_采用极简设计,客户端+服务器源码总共400行,方便用户自己扩展_
### *快速设定* :lollipop:
```
服务器: ./server_linux_amd64 -t "127.0.0.1:1080" -l ":554" -mode fast2 // 转发到本地1080端口
客户端: ./client_darwin_amd64 -r "IP地址:554" -l ":1080" -mode fast2 // 监听本地1080端口
```
### *使用の方法* :lollipop:
![client](client.png)
@@ -14,6 +31,19 @@ TCP流转换为KCP+UDP流,:zap:***[下载地址](https://github.com/xtaci/kcpt
2. 跨运营商的流量传输
3. 其他高丢包通信链路的TCP承载
### *推荐参数* :lollipop:
```
适用大部分ADSL接入(非对称上下行)的参数(实验环境电信100M ADSL)
SERVER: -mtu 1400 -sndwnd 2048 -rcvwnd 2048 -mode fast2
CLIENT: -mtu 1400 -sndwnd 256 -rcvwnd 2048 -mode fast2 -dscp 46
其它带宽请按比例降低窗口,比如50M ADSL,把CLIENT的 -sndwnd -rcvwnd减掉一半,SERVER不变
```
*巭孬嫑乱动*
### *DSCP* :lollipop:
DSCP差分服务代码点(Differentiated Services Code Point),IETF于1998年12月发布了Diff-ServDifferentiated Service)的QoS分类标准。它在每个数据包IP头部的服务类别TOS标识字节中,利用已使用的6比特和未使用的2比特,通过编码值来区分优先级。
常用DSCP值可以参考[Wikipedia DSCP](https://en.wikipedia.org/wiki/Differentiated_services#Commonly_used_DSCP_values),至于有没有用,完全取决于数据包经过的设备。
### *内置模式* :lollipop:
响应速度:
*fast3 >* ***[fast2]*** *> fast > normal > default*
@@ -22,31 +52,39 @@ TCP流转换为KCP+UDP流,:zap:***[下载地址](https://github.com/xtaci/kcpt
中间mode参数比较均衡,总之就是越快越浪费带宽,推荐模式 ***fast2***
更高级的 ***手动档*** 需要理解KCP协议,并通过 ***隐藏参数*** 调整,例如:
```
-mode manual -nodelay 1 -resend 4 -nc 1 -interval 20 -fec 4
-mode manual -nodelay 1 -resend 2 -nc 1 -interval 20
```
### *前向纠错* :lollipop:
前向纠错采用Reed Solomon纠删码, 它的基本原理如下: 给定n个数据块d1, d2,…, dn,n和一个正整数m, RS根据n个数据块生成m个校验块, c1, c2,…, cm。 对于任意的n和m, 从n个原始数据块和m 个校验块中任取n块就能解码出原始数据, 即RS最多容忍m个数据块或者校验块同时丢失。
![reed-solomon](rs.png)
通过```-datashard 10 -parityshard 3``` 可以调整Reed Solomon参数。
### *SNMP* :lollipop:
```go
// Snmp defines network statistics indicator
type Snmp struct {
BytesSent uint64 // payload bytes sent
BytesReceived uint64
MaxConn uint64
ActiveOpens uint64
PassiveOpens uint64
CurrEstab uint64
InErrs uint64
InCsumErrors uint64 // checksum errors
InSegs uint64
OutSegs uint64
OutBytes uint64 // udp bytes sent
RetransSegs uint64
FastRetransSegs uint64
LostSegs uint64
RepeatSegs uint64
FECRecovered uint64
FECErrs uint64
FECSegs uint64 // fec segments received
BytesSent uint64 // payload bytes sent
BytesReceived uint64
MaxConn uint64
ActiveOpens uint64
PassiveOpens uint64
CurrEstab uint64
InErrs uint64
InCsumErrors uint64 // checksum errors
InSegs uint64
OutSegs uint64
OutBytes uint64 // udp bytes sent
RetransSegs uint64
FastRetransSegs uint64
EarlyRetransSegs uint64
LostSegs uint64
RepeatSegs uint64
FECRecovered uint64
FECErrs uint64
FECSegs uint64 // fec segments received
}
```
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 66 KiB

+114 -34
View File
@@ -1,6 +1,7 @@
package main
import (
"crypto/sha1"
"io"
"log"
"math/rand"
@@ -8,14 +9,48 @@ import (
"os"
"time"
"golang.org/x/crypto/pbkdf2"
"github.com/golang/snappy"
"github.com/hashicorp/yamux"
"github.com/urfave/cli"
"github.com/xtaci/kcp-go"
)
var VERSION = "SELFBUILD"
var (
VERSION = "SELFBUILD"
SALT = "kcp-go"
)
func handleClient(p1, p2 net.Conn) {
type compStream struct {
conn net.Conn
w *snappy.Writer
r *snappy.Reader
}
func (c *compStream) Read(p []byte) (n int, err error) {
return c.r.Read(p)
}
func (c *compStream) Write(p []byte) (n int, err error) {
n, err = c.w.Write(p)
err = c.w.Flush()
return n, err
}
func (c *compStream) Close() error {
return c.conn.Close()
}
func newCompStream(conn net.Conn) *compStream {
c := new(compStream)
c.conn = conn
c.w = snappy.NewBufferedWriter(conn)
c.r = snappy.NewReader(conn)
return c
}
func handleClient(p1, p2 io.ReadWriteCloser) {
log.Println("stream opened")
defer log.Println("stream closed")
defer p1.Close()
@@ -71,11 +106,21 @@ func main() {
Usage: "key for communcation, must be the same as kcptun server",
EnvVar: "KCPTUN_KEY",
},
cli.StringFlag{
Name: "crypt",
Value: "aes",
Usage: "methods for encryption: aes, tea, xor, none",
},
cli.StringFlag{
Name: "mode",
Value: "fast",
Usage: "mode for communication: fast3, fast2, fast, normal",
},
cli.IntFlag{
Name: "conn",
Value: 1,
Usage: "establish N physical connections as specified by 'conn' to server",
},
cli.IntFlag{
Name: "mtu",
Value: 1350,
@@ -91,10 +136,19 @@ func main() {
Value: 1024,
Usage: "set receive window size(num of packets)",
},
cli.BoolFlag{
Name: "nocomp",
Usage: "disable compression",
},
cli.IntFlag{
Name: "fec",
Value: 4,
Usage: "set FEC group size, must be the same as server",
Name: "datashard",
Value: 10,
Usage: "set reed-solomon erasure coding - datashard",
},
cli.IntFlag{
Name: "parityshard",
Value: 3,
Usage: "set reed-solomon erasure coding - parityshard",
},
cli.BoolFlag{
Name: "acknodelay",
@@ -132,13 +186,9 @@ func main() {
checkError(err)
listener, err := net.ListenTCP("tcp", addr)
checkError(err)
log.Println("listening on:", listener.Addr())
START_KCP:
pass := pbkdf2.Key([]byte(c.String("key")), []byte(SALT), 4096, 32, sha1.New)
// kcp server
kcpconn, err := kcp.DialWithOptions(c.Int("fec"), c.String("remoteaddr"), []byte(c.String("key")))
checkError(err)
nodelay, interval, resend, nc := c.Int("nodelay"), c.Int("interval"), c.Int("resend"), c.Int("nc")
switch c.String("mode") {
@@ -152,48 +202,78 @@ func main() {
nodelay, interval, resend, nc = 1, 10, 2, 1
}
log.Println("listening on:", listener.Addr())
log.Println("encryption:", c.String("crypt"))
log.Println("nodelay parameters:", nodelay, interval, resend, nc)
log.Println("remote address:", c.String("remoteaddr"))
log.Println("sndwnd:", c.Int("sndwnd"), "rcvwnd:", c.Int("rcvwnd"))
log.Println("compression:", !c.Bool("nocomp"))
log.Println("mtu:", c.Int("mtu"))
log.Println("fec:", c.Int("fec"))
log.Println("datashard:", c.Int("datashard"), "parityshard:", c.Int("parityshard"))
log.Println("acknodelay:", c.Bool("acknodelay"))
log.Println("dscp:", c.Int("dscp"))
log.Println("conn:", c.Int("conn"))
kcpconn.SetNoDelay(nodelay, interval, resend, nc)
kcpconn.SetWindowSize(c.Int("sndwnd"), c.Int("rcvwnd"))
kcpconn.SetMtu(c.Int("mtu"))
kcpconn.SetACKNoDelay(c.Bool("acknodelay"))
kcpconn.SetDSCP(c.Int("dscp"))
createConn := func() *yamux.Session {
var block kcp.BlockCrypt
switch c.String("crypt") {
case "tea":
block, _ = kcp.NewTEABlockCrypt(pass[:16])
case "xor":
block, _ = kcp.NewSimpleXORBlockCrypt(pass)
case "none":
block, _ = kcp.NewNoneBlockCrypt(pass)
default:
block, _ = kcp.NewAESBlockCrypt(pass)
}
kcpconn, err := kcp.DialWithOptions(c.String("remoteaddr"), block, c.Int("datashard"), c.Int("parityshard"))
checkError(err)
kcpconn.SetNoDelay(nodelay, interval, resend, nc)
kcpconn.SetWindowSize(c.Int("sndwnd"), c.Int("rcvwnd"))
kcpconn.SetMtu(c.Int("mtu"))
kcpconn.SetACKNoDelay(c.Bool("acknodelay"))
kcpconn.SetDSCP(c.Int("dscp"))
// stream multiplex
var mux *yamux.Session
config := &yamux.Config{
AcceptBacklog: 256,
EnableKeepAlive: true,
KeepAliveInterval: 30 * time.Second,
ConnectionWriteTimeout: 30 * time.Second,
MaxStreamWindowSize: 16777216,
LogOutput: os.Stderr,
// stream multiplex
config := &yamux.Config{
AcceptBacklog: 256,
EnableKeepAlive: true,
KeepAliveInterval: 30 * time.Second,
ConnectionWriteTimeout: 30 * time.Second,
MaxStreamWindowSize: 16777216,
LogOutput: os.Stderr,
}
var session *yamux.Session
if c.Bool("nocomp") {
session, err = yamux.Client(kcpconn, config)
} else {
session, err = yamux.Client(newCompStream(kcpconn), config)
}
checkError(err)
return session
}
session, err := yamux.Client(kcpconn, config)
checkError(err)
mux = session
numconn := uint16(c.Int("conn"))
var muxes []*yamux.Session
for i := uint16(0); i < numconn; i++ {
muxes = append(muxes, createConn())
}
rr := uint16(0)
for {
p1, err := listener.AcceptTCP()
if err != nil {
log.Println(err)
continue
}
checkError(err)
mux := muxes[rr%numconn]
p2, err := mux.Open()
if err != nil { // yamux failure
log.Println(err)
kcpconn.Close()
p1.Close()
goto START_KCP
mux.Close()
muxes[rr%numconn] = createConn()
continue
}
go handleClient(p1, p2)
rr++
}
}
myApp.Run(os.Args)
+2 -2
View File
@@ -12,10 +12,10 @@ import (
)
func init() {
go sig_handler()
go sigHandler()
}
func sig_handler() {
func sigHandler() {
ch := make(chan os.Signal, 1)
signal.Notify(ch, syscall.SIGUSR1)
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 20 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 63 KiB

+78 -9
View File
@@ -1,6 +1,7 @@
package main
import (
"crypto/sha1"
"io"
"log"
"math/rand"
@@ -8,15 +9,49 @@ import (
"os"
"time"
"golang.org/x/crypto/pbkdf2"
"github.com/golang/snappy"
"github.com/hashicorp/yamux"
"github.com/urfave/cli"
"github.com/xtaci/kcp-go"
)
var VERSION = "SELFBUILD"
var (
VERSION = "SELFBUILD"
SALT = "kcp-go"
)
type compStream struct {
conn net.Conn
w *snappy.Writer
r *snappy.Reader
}
func (c *compStream) Read(p []byte) (n int, err error) {
return c.r.Read(p)
}
func (c *compStream) Write(p []byte) (n int, err error) {
n, err = c.w.Write(p)
err = c.w.Flush()
return n, err
}
func (c *compStream) Close() error {
return c.conn.Close()
}
func newCompStream(conn net.Conn) *compStream {
c := new(compStream)
c.conn = conn
c.w = snappy.NewBufferedWriter(conn)
c.r = snappy.NewReader(conn)
return c
}
// handle multiplex-ed connection
func handleMux(conn *kcp.UDPSession, target string) {
func handleMux(conn io.ReadWriteCloser, target string) {
// stream multiplex
var mux *yamux.Session
config := &yamux.Config{
@@ -50,7 +85,7 @@ func handleMux(conn *kcp.UDPSession, target string) {
}
}
func handleClient(p1, p2 net.Conn) {
func handleClient(p1, p2 io.ReadWriteCloser) {
log.Println("stream opened")
defer log.Println("stream closed")
defer p1.Close()
@@ -99,6 +134,11 @@ func main() {
Usage: "key for communcation, must be the same as kcptun client",
EnvVar: "KCPTUN_KEY",
},
cli.StringFlag{
Name: "crypt",
Value: "aes",
Usage: "methods for encryption: aes, tea, xor, none",
},
cli.StringFlag{
Name: "mode",
Value: "fast",
@@ -119,10 +159,19 @@ func main() {
Value: 1024,
Usage: "set receive window size(num of packets)",
},
cli.BoolFlag{
Name: "nocomp",
Usage: "disable compression",
},
cli.IntFlag{
Name: "fec",
Value: 4,
Usage: "set FEC group size, must be the same as client",
Name: "datashard",
Value: 10,
Usage: "set reed-solomon erasure coding - datashard",
},
cli.IntFlag{
Name: "parityshard",
Value: 3,
Usage: "set reed-solomon erasure coding - parityshard",
},
cli.BoolFlag{
Name: "acknodelay",
@@ -168,15 +217,30 @@ func main() {
nodelay, interval, resend, nc = 1, 10, 2, 1
}
lis, err := kcp.ListenWithOptions(c.Int("fec"), c.String("listen"), []byte(c.String("key")))
pass := pbkdf2.Key([]byte(c.String("key")), []byte(SALT), 4096, 32, sha1.New)
var block kcp.BlockCrypt
switch c.String("crypt") {
case "tea":
block, _ = kcp.NewTEABlockCrypt(pass[:16])
case "xor":
block, _ = kcp.NewSimpleXORBlockCrypt(pass)
case "none":
block, _ = kcp.NewNoneBlockCrypt(pass)
default:
block, _ = kcp.NewAESBlockCrypt(pass)
}
lis, err := kcp.ListenWithOptions(c.String("listen"), block, c.Int("datashard"), c.Int("parityshard"))
if err != nil {
log.Fatal(err)
}
log.Println("listening on ", lis.Addr())
log.Println("encryption:", c.String("crypt"))
log.Println("nodelay parameters:", nodelay, interval, resend, nc)
log.Println("sndwnd:", c.Int("sndwnd"), "rcvwnd:", c.Int("rcvwnd"))
log.Println("compression:", !c.Bool("nocomp"))
log.Println("mtu:", c.Int("mtu"))
log.Println("fec:", c.Int("fec"))
log.Println("datashard:", c.Int("datashard"), "parityshard:", c.Int("parityshard"))
log.Println("acknodelay:", c.Bool("acknodelay"))
log.Println("dscp:", c.Int("dscp"))
for {
@@ -187,7 +251,12 @@ func main() {
conn.SetWindowSize(c.Int("sndwnd"), c.Int("rcvwnd"))
conn.SetACKNoDelay(c.Bool("acknodelay"))
conn.SetDSCP(c.Int("dscp"))
go handleMux(conn, c.String("target"))
if c.Bool("nocomp") {
go handleMux(conn, c.String("target"))
} else {
go handleMux(newCompStream(conn), c.String("target"))
}
} else {
log.Println(err)
}
+2 -2
View File
@@ -12,10 +12,10 @@ import (
)
func init() {
go sig_handler()
go sigHandler()
}
func sig_handler() {
func sigHandler() {
ch := make(chan os.Signal, 1)
signal.Notify(ch, syscall.SIGUSR1)