Browse Source

add custom client disconnect timeout option, close #485

ffdfgdfg 5 years ago
parent
commit
f459acdfb4
15 changed files with 89 additions and 60 deletions
  1. 23 21
      bridge/bridge.go
  2. 5 3
      client/client.go
  3. 1 1
      client/control.go
  4. 2 2
      client/local.go
  5. 19 18
      cmd/npc/npc.go
  6. 1 1
      cmd/npc/sdk.go
  7. 5 1
      cmd/nps/nps.go
  8. 1 0
      conf/npc.conf
  9. 3 0
      conf/nps.conf
  10. 5 0
      docs/feature.md
  11. 5 4
      go.mod
  12. 13 6
      go.sum
  13. 1 1
      gui/npc/npc.go
  14. 3 0
      lib/config/config.go
  15. 2 2
      server/server.go

+ 23 - 21
bridge/bridge.go

@@ -41,28 +41,30 @@ func NewClient(t, f *nps_mux.Mux, s *conn.Conn, vs string) *Client {
 }
 
 type Bridge struct {
-	TunnelPort  int //通信隧道端口
-	Client      sync.Map
-	Register    sync.Map
-	tunnelType  string //bridge type kcp or tcp
-	OpenTask    chan *file.Tunnel
-	CloseTask   chan *file.Tunnel
-	CloseClient chan int
-	SecretChan  chan *conn.Secret
-	ipVerify    bool
-	runList     sync.Map //map[int]interface{}
+	TunnelPort     int //通信隧道端口
+	Client         sync.Map
+	Register       sync.Map
+	tunnelType     string //bridge type kcp or tcp
+	OpenTask       chan *file.Tunnel
+	CloseTask      chan *file.Tunnel
+	CloseClient    chan int
+	SecretChan     chan *conn.Secret
+	ipVerify       bool
+	runList        sync.Map //map[int]interface{}
+	disconnectTime int
 }
 
-func NewTunnel(tunnelPort int, tunnelType string, ipVerify bool, runList sync.Map) *Bridge {
+func NewTunnel(tunnelPort int, tunnelType string, ipVerify bool, runList sync.Map, disconnectTime int) *Bridge {
 	return &Bridge{
-		TunnelPort:  tunnelPort,
-		tunnelType:  tunnelType,
-		OpenTask:    make(chan *file.Tunnel),
-		CloseTask:   make(chan *file.Tunnel),
-		CloseClient: make(chan int),
-		SecretChan:  make(chan *conn.Secret),
-		ipVerify:    ipVerify,
-		runList:     runList,
+		TunnelPort:     tunnelPort,
+		tunnelType:     tunnelType,
+		OpenTask:       make(chan *file.Tunnel),
+		CloseTask:      make(chan *file.Tunnel),
+		CloseClient:    make(chan int),
+		SecretChan:     make(chan *conn.Secret),
+		ipVerify:       ipVerify,
+		runList:        runList,
+		disconnectTime: disconnectTime,
 	}
 }
 
@@ -242,7 +244,7 @@ func (s *Bridge) typeDeal(typeVal string, c *conn.Conn, id int, vs string) {
 		go s.GetHealthFromClient(id, c)
 		logs.Info("clientId %d connection succeeded, address:%s ", id, c.Conn.RemoteAddr())
 	case common.WORK_CHAN:
-		muxConn := nps_mux.NewMux(c.Conn, s.tunnelType)
+		muxConn := nps_mux.NewMux(c.Conn, s.tunnelType, s.disconnectTime)
 		if v, ok := s.Client.LoadOrStore(id, NewClient(muxConn, nil, nil, vs)); ok {
 			v.(*Client).tunnel = muxConn
 		}
@@ -263,7 +265,7 @@ func (s *Bridge) typeDeal(typeVal string, c *conn.Conn, id int, vs string) {
 			logs.Error("secret error, failed to match the key successfully")
 		}
 	case common.WORK_FILE:
-		muxConn := nps_mux.NewMux(c.Conn, s.tunnelType)
+		muxConn := nps_mux.NewMux(c.Conn, s.tunnelType, s.disconnectTime)
 		if v, ok := s.Client.LoadOrStore(id, NewClient(nil, muxConn, nil, vs)); ok {
 			v.(*Client).file = muxConn
 		}

+ 5 - 3
client/client.go

@@ -28,10 +28,11 @@ type TRPClient struct {
 	signal         *conn.Conn
 	ticker         *time.Ticker
 	cnf            *config.Config
+	disconnectTime int
 }
 
 //new client
-func NewRPClient(svraddr string, vKey string, bridgeConnType string, proxyUrl string, cnf *config.Config) *TRPClient {
+func NewRPClient(svraddr string, vKey string, bridgeConnType string, proxyUrl string, cnf *config.Config, disconnectTime int) *TRPClient {
 	return &TRPClient{
 		svrAddr:        svraddr,
 		p2pAddr:        make(map[string]string, 0),
@@ -39,6 +40,7 @@ func NewRPClient(svraddr string, vKey string, bridgeConnType string, proxyUrl st
 		bridgeConnType: bridgeConnType,
 		proxyUrl:       proxyUrl,
 		cnf:            cnf,
+		disconnectTime: disconnectTime,
 	}
 }
 
@@ -138,7 +140,7 @@ func (s *TRPClient) newUdpConn(localAddr, rAddr string, md5Password string) {
 			conn.SetUdpSession(udpTunnel)
 			logs.Trace("successful connection with client ,address %s", udpTunnel.RemoteAddr().String())
 			//read link info from remote
-			conn.Accept(nps_mux.NewMux(udpTunnel, s.bridgeConnType), func(c net.Conn) {
+			conn.Accept(nps_mux.NewMux(udpTunnel, s.bridgeConnType, s.disconnectTime), func(c net.Conn) {
 				go s.handleChan(c)
 			})
 			break
@@ -153,7 +155,7 @@ func (s *TRPClient) newChan() {
 		logs.Error("connect to ", s.svrAddr, "error:", err)
 		return
 	}
-	s.tunnel = nps_mux.NewMux(tunnel.Conn, s.bridgeConnType)
+	s.tunnel = nps_mux.NewMux(tunnel.Conn, s.bridgeConnType, s.disconnectTime)
 	for {
 		src, err := s.tunnel.Accept()
 		if err != nil {

+ 1 - 1
client/control.go

@@ -175,7 +175,7 @@ re:
 	} else {
 		logs.Notice("web access login username:%s password:%s", cnf.CommonConfig.Client.WebUserName, cnf.CommonConfig.Client.WebPassword)
 	}
-	NewRPClient(cnf.CommonConfig.Server, vkey, cnf.CommonConfig.Tp, cnf.CommonConfig.ProxyUrl, cnf).Start()
+	NewRPClient(cnf.CommonConfig.Server, vkey, cnf.CommonConfig.Tp, cnf.CommonConfig.ProxyUrl, cnf, cnf.CommonConfig.DisconnectTime).Start()
 	CloseLocalServer()
 	goto re
 }

+ 2 - 2
client/local.go

@@ -73,7 +73,7 @@ func startLocalFileServer(config *config.CommonConfig, t *file.Tunnel, vkey stri
 	}
 	logs.Info("start local file system, local path %s, strip prefix %s ,remote port %s ", t.LocalPath, t.StripPre, t.Ports)
 	fileServer = append(fileServer, srv)
-	listener := nps_mux.NewMux(remoteConn.Conn, common.CONN_TCP)
+	listener := nps_mux.NewMux(remoteConn.Conn, common.CONN_TCP, config.DisconnectTime)
 	logs.Error(srv.Serve(listener))
 }
 
@@ -214,6 +214,6 @@ func newUdpConn(localAddr string, config *config.CommonConfig, l *config.LocalSe
 	logs.Trace("successful create a connection with server", remoteAddress)
 	conn.SetUdpSession(udpTunnel)
 	udpConn = udpTunnel
-	muxSession = nps_mux.NewMux(udpConn, "kcp")
+	muxSession = nps_mux.NewMux(udpConn, "kcp", config.DisconnectTime)
 	p2pNetBridge = &p2pBridge{}
 }

+ 19 - 18
cmd/npc/npc.go

@@ -21,23 +21,24 @@ import (
 )
 
 var (
-	serverAddr   = flag.String("server", "", "Server addr (ip:port)")
-	configPath   = flag.String("config", "", "Configuration file path")
-	verifyKey    = flag.String("vkey", "", "Authentication key")
-	logType      = flag.String("log", "stdout", "Log output mode(stdout|file)")
-	connType     = flag.String("type", "tcp", "Connection type with the server(kcp|tcp)")
-	proxyUrl     = flag.String("proxy", "", "proxy socks5 url(eg:socks5://111:222@127.0.0.1:9007)")
-	logLevel     = flag.String("log_level", "7", "log level 0~7")
-	registerTime = flag.Int("time", 2, "register time long /h")
-	localPort    = flag.Int("local_port", 2000, "p2p local port")
-	password     = flag.String("password", "", "p2p password flag")
-	target       = flag.String("target", "", "p2p target")
-	localType    = flag.String("local_type", "p2p", "p2p target")
-	logPath      = flag.String("log_path", "", "npc log path")
-	debug        = flag.Bool("debug", true, "npc debug")
-	pprofAddr    = flag.String("pprof", "", "PProf debug addr (ip:port)")
-	stunAddr     = flag.String("stun_addr", "stun.stunprotocol.org:3478", "stun server address (eg:stun.stunprotocol.org:3478)")
-	ver          = flag.Bool("version", false, "show current version")
+	serverAddr     = flag.String("server", "", "Server addr (ip:port)")
+	configPath     = flag.String("config", "", "Configuration file path")
+	verifyKey      = flag.String("vkey", "", "Authentication key")
+	logType        = flag.String("log", "stdout", "Log output mode(stdout|file)")
+	connType       = flag.String("type", "tcp", "Connection type with the server(kcp|tcp)")
+	proxyUrl       = flag.String("proxy", "", "proxy socks5 url(eg:socks5://111:222@127.0.0.1:9007)")
+	logLevel       = flag.String("log_level", "7", "log level 0~7")
+	registerTime   = flag.Int("time", 2, "register time long /h")
+	localPort      = flag.Int("local_port", 2000, "p2p local port")
+	password       = flag.String("password", "", "p2p password flag")
+	target         = flag.String("target", "", "p2p target")
+	localType      = flag.String("local_type", "p2p", "p2p target")
+	logPath        = flag.String("log_path", "", "npc log path")
+	debug          = flag.Bool("debug", true, "npc debug")
+	pprofAddr      = flag.String("pprof", "", "PProf debug addr (ip:port)")
+	stunAddr       = flag.String("stun_addr", "stun.stunprotocol.org:3478", "stun server address (eg:stun.stunprotocol.org:3478)")
+	ver            = flag.Bool("version", false, "show current version")
+	disconnectTime = flag.Int("disconnect_timeout", 60, "not receiving check packet times, until timeout will disconnect the client")
 )
 
 func main() {
@@ -231,7 +232,7 @@ func run() {
 	if *verifyKey != "" && *serverAddr != "" && *configPath == "" {
 		go func() {
 			for {
-				client.NewRPClient(*serverAddr, *verifyKey, *connType, *proxyUrl, nil).Start()
+				client.NewRPClient(*serverAddr, *verifyKey, *connType, *proxyUrl, nil, *disconnectTime).Start()
 				logs.Info("It will be reconnected in five seconds")
 				time.Sleep(time.Second * 5)
 			}

+ 1 - 1
cmd/npc/sdk.go

@@ -16,7 +16,7 @@ func StartClientByVerifyKey(serverAddr, verifyKey, connType, proxyUrl *C.char) i
 	if cl != nil {
 		cl.Close()
 	}
-	cl = client.NewRPClient(C.GoString(serverAddr), C.GoString(verifyKey), C.GoString(connType), C.GoString(proxyUrl), nil)
+	cl = client.NewRPClient(C.GoString(serverAddr), C.GoString(verifyKey), C.GoString(connType), C.GoString(proxyUrl), nil, 60)
 	go func() {
 		cl.Start()
 		return

+ 5 - 1
cmd/nps/nps.go

@@ -205,5 +205,9 @@ func run() {
 	crypt.InitTls()
 	tool.InitAllowPort()
 	tool.StartSystemInfo()
-	go server.StartNewServer(bridgePort, task, beego.AppConfig.String("bridge_type"))
+	timeout, err := beego.AppConfig.Int("disconnect_timeout")
+	if err != nil {
+		timeout = 60
+	}
+	go server.StartNewServer(bridgePort, task, beego.AppConfig.String("bridge_type"), timeout)
 }

+ 1 - 0
conf/npc.conf

@@ -13,6 +13,7 @@ web_password=1234
 crypt=true
 compress=true
 #pprof_addr=0.0.0.0:9999
+disconnect_timeout=60
 
 [health_check_test1]
 health_check_timeout=1

+ 3 - 0
conf/nps.conf

@@ -80,3 +80,6 @@ http_add_origin_header=false
 #pprof debug options
 #pprof_ip=0.0.0.0
 #pprof_port=9999
+
+#client disconnect timeout
+disconnect_timeout=60

+ 5 - 0
docs/feature.md

@@ -243,3 +243,8 @@ LevelInformational->6 LevelDebug->7
 可在服务端与客户端配置中开启pprof端口,用于性能分析与调试,注释或留空相应参数为关闭。
 
 默认为关闭状态
+
+## 自定义客户端超时检测断开时间
+
+客户端与服务端间会间隔5s相互发送延迟测量包,这个时间间隔不可修改。
+可修改延迟测量包丢包的次数,默认为60也就是5分钟都收不到一个延迟测量回包,则会断开客户端连接。

+ 5 - 4
go.mod

@@ -3,7 +3,7 @@ module ehang.io/nps
 go 1.13
 
 require (
-	ehang.io/nps-mux v0.0.0-20200319121657-f4af26331c9f
+	ehang.io/nps-mux v0.0.0-20200407130948-165521618e58
 	fyne.io/fyne v1.2.4
 	github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect
 	github.com/astaxie/beego v1.12.0
@@ -16,14 +16,15 @@ require (
 	github.com/hooklift/assert v0.0.0-20170704181755-9d1defd6d214 // indirect
 	github.com/kardianos/service v1.0.0
 	github.com/klauspost/pgzip v1.2.1 // indirect
+	github.com/klauspost/reedsolomon v1.9.6 // indirect
 	github.com/panjf2000/ants/v2 v2.3.1
 	github.com/pkg/errors v0.9.1
 	github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 // indirect
 	github.com/shirou/gopsutil v2.19.11+incompatible
 	github.com/xtaci/kcp-go v5.4.20+incompatible
-	golang.org/x/crypto v0.0.0-20200317142112-1b76d66859c6 // indirect
-	golang.org/x/net v0.0.0-20200301022130-244492dfa37a
-	golang.org/x/sys v0.0.0-20200317113312-5766fd39f98d // indirect
+	golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79 // indirect
+	golang.org/x/net v0.0.0-20200506145744-7e3656a0809f
+	golang.org/x/sys v0.0.0-20200501145240-bc7a7d42d5c3 // indirect
 )
 
 replace github.com/astaxie/beego => github.com/exfly/beego v1.12.0-export-init

+ 13 - 6
go.sum

@@ -1,5 +1,5 @@
-ehang.io/nps-mux v0.0.0-20200319121657-f4af26331c9f h1:uAc/HZ939kibvYzVCPc1kp24PEjxxJy/N4Gs3Ybpm1Q=
-ehang.io/nps-mux v0.0.0-20200319121657-f4af26331c9f/go.mod h1:hTpHjFEac582vs7OjOaN8R2o3EOPOs2qeBeqTvIQAgs=
+ehang.io/nps-mux v0.0.0-20200407130948-165521618e58 h1:KGA7iiDIA+taxu5Dvh4/oRDCWnSsPKElCjqvdaPagI0=
+ehang.io/nps-mux v0.0.0-20200407130948-165521618e58/go.mod h1:hTpHjFEac582vs7OjOaN8R2o3EOPOs2qeBeqTvIQAgs=
 fyne.io/fyne v1.2.4 h1:QN5GQEZ9FANvFxkIQLQ5qnmmpSwBAoDiH8hQiuz2Zyo=
 fyne.io/fyne v1.2.4/go.mod h1:nsGex1XH/8p/kq6KiQV4bNu0XTKaFJRbZEOOj4fqJF8=
 github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
@@ -64,10 +64,14 @@ github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0
 github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
 github.com/klauspost/cpuid v1.2.3 h1:CCtW0xUnWGVINKvE/WWOYKdsPV6mawAtvQuSl8guwQs=
 github.com/klauspost/cpuid v1.2.3/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
+github.com/klauspost/cpuid v1.2.4 h1:EBfaK0SWSwk+fgk6efYFWdzl8MwRWoOO1gkmiaTXPW4=
+github.com/klauspost/cpuid v1.2.4/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
 github.com/klauspost/pgzip v1.2.1 h1:oIPZROsWuPHpOdMVWLuJZXwgjhrW8r1yEX8UqMyeNHM=
 github.com/klauspost/pgzip v1.2.1/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
 github.com/klauspost/reedsolomon v1.9.3 h1:N/VzgeMfHmLc+KHMD1UL/tNkfXAt8FnUqlgXGIduwAY=
 github.com/klauspost/reedsolomon v1.9.3/go.mod h1:CwCi+NUr9pqSVktrkN+Ondf06rkhYZ/pcNv7fu+8Un4=
+github.com/klauspost/reedsolomon v1.9.6 h1:sXZANEgYACIcmbk90z6MV4XL29d0Lm6AFleWRPZJxi8=
+github.com/klauspost/reedsolomon v1.9.6/go.mod h1:+8WD025Xpby8/kG5h/HDPIFhiiuGEtZOKw+5Y4drAD8=
 github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
 github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
 github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
@@ -123,8 +127,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
 golang.org/x/crypto v0.0.0-20191219195013-becbf705a915/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073 h1:xMPOj6Pz6UipU1wXLkrtqpHbR0AVFnyPEQq/wRWz9lM=
 golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20200317142112-1b76d66859c6 h1:TjszyFsQsyZNHwdVdZ5m7bjmreu0znc2kRYsEml9/Ww=
-golang.org/x/crypto v0.0.0-20200317142112-1b76d66859c6/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79 h1:IaQbIIB2X/Mp/DKctl6ROxz1KyMlKp4uyvL6+kQ7C88=
+golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/image v0.0.0-20190802002840-cff245a6509b h1:+qEpEAPhDZ1o0x3tHzZTQDArnOixOzGD9HUJfcg0mb4=
 golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
 golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
@@ -135,6 +139,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
 golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0=
 golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200506145744-7e3656a0809f h1:QBjCr1Fz5kw158VqdE9JfI9cJnl/ymnJWAdMuinqL7Y=
+golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -142,8 +148,9 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 h1:uYVVQ9WP/Ds2ROhcaGPeIdVq0RIXVLwsHlnvJ+cT1So=
 golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200317113312-5766fd39f98d h1:62ap6LNOjDU6uGmKXHJbSfciMoV+FeI1sRXx/pLDL44=
-golang.org/x/sys v0.0.0-20200317113312-5766fd39f98d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200501145240-bc7a7d42d5c3 h1:5B6i6EAiSYyejWfvc5Rc9BbI3rzIsrrXfAQBWnYfn+w=
+golang.org/x/sys v0.0.0-20200501145240-bc7a7d42d5c3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/tools v0.0.0-20190808195139-e713427fea3f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=

+ 1 - 1
gui/npc/npc.go

@@ -107,7 +107,7 @@ func onclick(s, v, c string) {
 		if sp != s || vk != v || ct != c {
 			saveConfig(s, v, c)
 		}
-		cl = client.NewRPClient(s, v, c, "", nil)
+		cl = client.NewRPClient(s, v, c, "", nil, 60)
 		go cl.Start()
 	} else {
 		// close the npc

+ 3 - 0
lib/config/config.go

@@ -17,6 +17,7 @@ type CommonConfig struct {
 	AutoReconnection bool
 	ProxyUrl         string
 	Client           *file.Client
+	DisconnectTime   int
 }
 
 type LocalServer struct {
@@ -147,6 +148,8 @@ func dealCommon(s string) *CommonConfig {
 			c.Client.Remark = item[1]
 		case "pprof_addr":
 			common.InitPProfFromArg(item[1])
+		case "disconnect_timeout":
+			c.DisconnectTime = common.GetIntNoErrByStr(item[1])
 		}
 	}
 	return c

+ 2 - 2
server/server.go

@@ -85,8 +85,8 @@ func DealBridgeTask() {
 }
 
 //start a new server
-func StartNewServer(bridgePort int, cnf *file.Tunnel, bridgeType string) {
-	Bridge = bridge.NewTunnel(bridgePort, bridgeType, common.GetBoolByStr(beego.AppConfig.String("ip_limit")), RunList)
+func StartNewServer(bridgePort int, cnf *file.Tunnel, bridgeType string, bridgeDisconnect int) {
+	Bridge = bridge.NewTunnel(bridgePort, bridgeType, common.GetBoolByStr(beego.AppConfig.String("ip_limit")), RunList, bridgeDisconnect)
 	go func() {
 		if err := Bridge.StartTunnel(); err != nil {
 			logs.Error("start server bridge error", err)