mirror of
https://github.com/fatedier/frp.git
synced 2025-01-08 06:59:18 +01:00
(1)优化重连和心跳检测
This commit is contained in:
parent
af6fc61537
commit
5d6f37aa82
2
.gitignore
vendored
2
.gitignore
vendored
@ -26,3 +26,5 @@ _testmain.go
|
|||||||
# Self
|
# Self
|
||||||
bin/
|
bin/
|
||||||
|
|
||||||
|
# Cache
|
||||||
|
*.swp
|
||||||
|
@ -15,8 +15,7 @@ const (
|
|||||||
heartbeatDuration = 2 //心跳检测时间间隔,单位秒
|
heartbeatDuration = 2 //心跳检测时间间隔,单位秒
|
||||||
)
|
)
|
||||||
|
|
||||||
// client与server之间连接的保护锁
|
var isHeartBeatContinue bool = true
|
||||||
var connProtect sync.Mutex
|
|
||||||
|
|
||||||
func ControlProcess(cli *models.ProxyClient, wait *sync.WaitGroup) {
|
func ControlProcess(cli *models.ProxyClient, wait *sync.WaitGroup) {
|
||||||
defer wait.Done()
|
defer wait.Done()
|
||||||
@ -28,13 +27,11 @@ func ControlProcess(cli *models.ProxyClient, wait *sync.WaitGroup) {
|
|||||||
}
|
}
|
||||||
defer c.Close()
|
defer c.Close()
|
||||||
|
|
||||||
go startHeartBeat(c)
|
|
||||||
|
|
||||||
for {
|
for {
|
||||||
// ignore response content now
|
// ignore response content now
|
||||||
_, err := c.ReadLine()
|
_, err := c.ReadLine()
|
||||||
if err == io.EOF {
|
if err == io.EOF {
|
||||||
connProtect.Lock() // 除了这里,其他地方禁止对连接进行任何操作
|
isHeartBeatContinue = false
|
||||||
log.Debug("ProxyName [%s], server close this control conn", cli.Name)
|
log.Debug("ProxyName [%s], server close this control conn", cli.Name)
|
||||||
var sleepTime time.Duration = 1
|
var sleepTime time.Duration = 1
|
||||||
for {
|
for {
|
||||||
@ -51,7 +48,6 @@ func ControlProcess(cli *models.ProxyClient, wait *sync.WaitGroup) {
|
|||||||
}
|
}
|
||||||
time.Sleep(sleepTime * time.Second)
|
time.Sleep(sleepTime * time.Second)
|
||||||
}
|
}
|
||||||
connProtect.Unlock()
|
|
||||||
continue
|
continue
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
log.Warn("ProxyName [%s], read from server error, %v", cli.Name, err)
|
log.Warn("ProxyName [%s], read from server error, %v", cli.Name, err)
|
||||||
@ -104,6 +100,8 @@ func loginToServer(cli *models.ProxyClient) (connection *conn.Conn) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
connection = c
|
connection = c
|
||||||
|
go startHeartBeat(connection)
|
||||||
|
log.Debug("ProxyName [%s], connect to server[%s:%d] success!", cli.Name, ServerAddr, ServerPort)
|
||||||
}
|
}
|
||||||
|
|
||||||
if connection == nil {
|
if connection == nil {
|
||||||
@ -114,14 +112,17 @@ func loginToServer(cli *models.ProxyClient) (connection *conn.Conn) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func startHeartBeat(con *conn.Conn) {
|
func startHeartBeat(con *conn.Conn) {
|
||||||
|
isHeartBeatContinue = true
|
||||||
for {
|
for {
|
||||||
time.Sleep(heartbeatDuration * time.Second)
|
time.Sleep(heartbeatDuration * time.Second)
|
||||||
|
if isHeartBeatContinue { // 把isHeartBeatContinue放在这里是为了防止SIGPIPE
|
||||||
connProtect.Lock()
|
|
||||||
err := con.Write("\r\n")
|
err := con.Write("\r\n")
|
||||||
connProtect.Unlock()
|
//log.Debug("send heart beat to server!")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Send hearbeat to server failed! Err:%s", err.Error())
|
log.Error("Send hearbeat to server failed! Err:%s", err.Error())
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"time"
|
||||||
|
|
||||||
"frp/pkg/utils/log"
|
|
||||||
"frp/pkg/utils/conn"
|
|
||||||
"frp/pkg/models"
|
"frp/pkg/models"
|
||||||
|
"frp/pkg/utils/conn"
|
||||||
|
"frp/pkg/utils/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ProcessControlConn(l *conn.Listener) {
|
func ProcessControlConn(l *conn.Listener) {
|
||||||
@ -19,6 +21,8 @@ func ProcessControlConn(l *conn.Listener) {
|
|||||||
|
|
||||||
// control connection from every client and server
|
// control connection from every client and server
|
||||||
func controlWorker(c *conn.Conn) {
|
func controlWorker(c *conn.Conn) {
|
||||||
|
defer c.Close()
|
||||||
|
|
||||||
// the first message is from client to server
|
// the first message is from client to server
|
||||||
// if error, close connection
|
// if error, close connection
|
||||||
res, err := c.ReadLine()
|
res, err := c.ReadLine()
|
||||||
@ -47,13 +51,14 @@ func controlWorker(c *conn.Conn) {
|
|||||||
err = c.Write(string(buf) + "\n")
|
err = c.Write(string(buf) + "\n")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn("Write error, %v", err)
|
log.Warn("Write error, %v", err)
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// work conn, just return
|
// work conn, just return
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
defer c.Close()
|
|
||||||
// others is from server to client
|
// others is from server to client
|
||||||
server, ok := ProxyServers[clientCtlReq.ProxyName]
|
server, ok := ProxyServers[clientCtlReq.ProxyName]
|
||||||
if !ok {
|
if !ok {
|
||||||
@ -61,10 +66,16 @@ func controlWorker(c *conn.Conn) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// read control msg from client
|
||||||
|
go readControlMsgFromClient(server, c)
|
||||||
|
|
||||||
serverCtlReq := &models.ClientCtlReq{}
|
serverCtlReq := &models.ClientCtlReq{}
|
||||||
serverCtlReq.Type = models.WorkConn
|
serverCtlReq.Type = models.WorkConn
|
||||||
for {
|
for {
|
||||||
server.WaitUserConn()
|
_, isStop := server.WaitUserConn()
|
||||||
|
if isStop {
|
||||||
|
break
|
||||||
|
}
|
||||||
buf, _ := json.Marshal(serverCtlReq)
|
buf, _ := json.Marshal(serverCtlReq)
|
||||||
err = c.Write(string(buf) + "\n")
|
err = c.Write(string(buf) + "\n")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -76,6 +87,7 @@ func controlWorker(c *conn.Conn) {
|
|||||||
log.Debug("ProxyName [%s], write to client to add work conn success", server.Name)
|
log.Debug("ProxyName [%s], write to client to add work conn success", server.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Error("ProxyName [%s], I'm dead!", server.Name)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,3 +144,32 @@ func checkProxy(req *models.ClientCtlReq, c *conn.Conn) (succ bool, msg string,
|
|||||||
succ = true
|
succ = true
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func readControlMsgFromClient(server *models.ProxyServer, c *conn.Conn) {
|
||||||
|
isContinueRead := true
|
||||||
|
f := func() {
|
||||||
|
isContinueRead = false
|
||||||
|
server.StopWaitUserConn()
|
||||||
|
}
|
||||||
|
timer := time.AfterFunc(10*time.Second, f)
|
||||||
|
defer timer.Stop()
|
||||||
|
|
||||||
|
for isContinueRead {
|
||||||
|
content, err := c.ReadLine()
|
||||||
|
//log.Debug("Receive msg from client! content:%s", content)
|
||||||
|
if err != nil {
|
||||||
|
if err == io.EOF {
|
||||||
|
log.Warn("Server detect client[%s] is dead!", server.Name)
|
||||||
|
server.StopWaitUserConn()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
log.Error("ProxyName [%s], read error:%s", server.Name, err.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if content == "\r\n" {
|
||||||
|
log.Debug("receive hearbeat:%s", content)
|
||||||
|
timer.Reset(10 * time.Second)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"sync"
|
|
||||||
"container/list"
|
"container/list"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"frp/pkg/utils/conn"
|
"frp/pkg/utils/conn"
|
||||||
"frp/pkg/utils/log"
|
"frp/pkg/utils/log"
|
||||||
@ -22,6 +22,7 @@ type ProxyServer struct {
|
|||||||
Status int64
|
Status int64
|
||||||
Listener *conn.Listener // accept new connection from remote users
|
Listener *conn.Listener // accept new connection from remote users
|
||||||
CtlMsgChan chan int64 // every time accept a new user conn, put "1" to the channel
|
CtlMsgChan chan int64 // every time accept a new user conn, put "1" to the channel
|
||||||
|
StopBlockChan chan int64 // put any number to the channel, if you want to stop wait user conn
|
||||||
CliConnChan chan *conn.Conn // get client conns from control goroutine
|
CliConnChan chan *conn.Conn // get client conns from control goroutine
|
||||||
UserConnList *list.List // store user conns
|
UserConnList *list.List // store user conns
|
||||||
Mutex sync.Mutex
|
Mutex sync.Mutex
|
||||||
@ -30,6 +31,7 @@ type ProxyServer struct {
|
|||||||
func (p *ProxyServer) Init() {
|
func (p *ProxyServer) Init() {
|
||||||
p.Status = Idle
|
p.Status = Idle
|
||||||
p.CtlMsgChan = make(chan int64)
|
p.CtlMsgChan = make(chan int64)
|
||||||
|
p.StopBlockChan = make(chan int64)
|
||||||
p.CliConnChan = make(chan *conn.Conn)
|
p.CliConnChan = make(chan *conn.Conn)
|
||||||
p.UserConnList = list.New()
|
p.UserConnList = list.New()
|
||||||
}
|
}
|
||||||
@ -110,7 +112,15 @@ func (p *ProxyServer) Close() {
|
|||||||
p.Unlock()
|
p.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *ProxyServer) WaitUserConn() (res int64) {
|
func (p *ProxyServer) WaitUserConn() (res int64, isStop bool) {
|
||||||
res = <-p.CtlMsgChan
|
select {
|
||||||
return
|
case res = <-p.CtlMsgChan:
|
||||||
|
return res, false
|
||||||
|
case <-p.StopBlockChan:
|
||||||
|
return 0, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *ProxyServer) StopWaitUserConn() {
|
||||||
|
p.StopBlockChan <- 1
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
package conn
|
package conn
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"net"
|
|
||||||
"bufio"
|
"bufio"
|
||||||
"sync"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"net"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"frp/pkg/utils/log"
|
"frp/pkg/utils/log"
|
||||||
)
|
)
|
||||||
@ -59,8 +59,10 @@ func (c *Conn) Write(content string) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Conn) Close() {
|
func (c *Conn) Close() {
|
||||||
|
if c.TcpConn != nil { // ZWF:我觉得应该加一个非空保护
|
||||||
c.TcpConn.Close()
|
c.TcpConn.Close()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func Listen(bindAddr string, bindPort int64) (l *Listener, err error) {
|
func Listen(bindAddr string, bindPort int64) (l *Listener, err error) {
|
||||||
tcpAddr, err := net.ResolveTCPAddr("tcp4", fmt.Sprintf("%s:%d", bindAddr, bindPort))
|
tcpAddr, err := net.ResolveTCPAddr("tcp4", fmt.Sprintf("%s:%d", bindAddr, bindPort))
|
||||||
|
Loading…
Reference in New Issue
Block a user