[TODO]MultiClient
MulitClient:
package plugin
import (
"log"
"sync"
"time"
)
type MultiClientConfig struct {
FirstAddress string
FirstPort int
SecondEnable bool
SecondAddress string
SecondPort int
ConnectionType int
}
const (
CLIENT_NONE = iota
CLIENT_FIRST
CLIENT_SECOND
)
type MultiClientConSate struct {
IsConnected bool
ClientObject int
}
const (
DETECT_MODE_NONE = iota
DETECT_MODE_ONLY_FIRST
DETECT_MODE_FIRST_TO_SECOND
DETECT_MODE_SECOND_TO_FIRST
)
type MultiClient struct {
Config MultiClientConfig
ClientConState MultiClientConSate
FirstClient TCPClient
SecondClient TCPClient
Mtx sync.Mutex
DetectMode int
StopCh chan string
wg sync.WaitGroup
}
func (p *MultiClient) SetClientConState(state *MultiClientConSate) {
p.Mtx.Lock()
defer p.Mtx.Unlock()
p.ClientConState.IsConnected = state.IsConnected
p.ClientConState.ClientObject = state.ClientObject
log.Printf("set %v,%v", p.ClientConState.IsConnected, p.ClientConState.ClientObject)
return
}
func (p *MultiClient) getClientConState() MultiClientConSate {
p.Mtx.Lock()
defer p.Mtx.Unlock()
return p.ClientConState
}
func (p *MultiClient) SetConfig(cfg *MultiClientConfig) {
p.Mtx.Lock()
defer p.Mtx.Unlock()
p.Config.FirstAddress = cfg.FirstAddress
p.Config.FirstPort = cfg.FirstPort
p.Config.SecondEnable = cfg.SecondEnable
p.Config.SecondAddress = cfg.SecondAddress
p.Config.SecondPort = cfg.SecondPort
p.Config.ConnectionType = cfg.ConnectionType
// 同步至主、备
firstCfg := TCPClientConfig{
Address: p.Config.FirstAddress,
Port: p.Config.FirstPort,
ConnectionType: p.Config.ConnectionType,
}
p.FirstClient.SetConfig(&firstCfg)
if p.Config.SecondEnable {
secondCfg := TCPClientConfig{
Address: p.Config.SecondAddress,
Port: p.Config.SecondPort,
ConnectionType: p.Config.ConnectionType,
}
p.SecondClient.SetConfig(&secondCfg)
}
}
// 外部业务判定网络异常时候,调用接口通知
func (p *MultiClient) NotifyConAbnormal() {
//根据现状来判定网络异常的切换逻辑
if !p.isEnableFirstAndSecond() {
//仅主配置了
p.FirstClient.Stop()
p.SetClientConState(&MultiClientConSate{IsConnected: false, ClientObject: CLIENT_FIRST})
p.setDetectMode(DETECT_MODE_ONLY_FIRST)
return
} else {
currentMultiClientCon := p.getClientConState()
log.Printf("notify check %v,%v", currentMultiClientCon.IsConnected, currentMultiClientCon.ClientObject)
switch currentMultiClientCon.ClientObject {
case CLIENT_FIRST:
p.FirstClient.Stop()
p.SetClientConState(&MultiClientConSate{IsConnected: false, ClientObject: CLIENT_FIRST})
p.setDetectMode(DETECT_MODE_FIRST_TO_SECOND)
case CLIENT_SECOND:
p.SecondClient.Stop()
p.SetClientConState(&MultiClientConSate{IsConnected: false, ClientObject: CLIENT_SECOND})
p.setDetectMode(DETECT_MODE_SECOND_TO_FIRST)
default:
return
}
}
return
}
func (p *MultiClient) setDetectMode(mode int) {
p.Mtx.Lock()
defer p.Mtx.Unlock()
p.DetectMode = mode
return
}
func (p *MultiClient) getDetectMode() int {
p.Mtx.Lock()
defer p.Mtx.Unlock()
return p.DetectMode
}
func (p *MultiClient) getConfig() MultiClientConfig {
p.Mtx.Lock()
defer p.Mtx.Unlock()
return p.Config
}
func (p *MultiClient) Start() {
log.Printf("MultiClient start enter\n")
// 1.启动检测携程
if p.StopCh == nil {
p.StopCh = make(chan string, 1)
}
p.wg.Add(1)
go p.handleMultiCenterProc()
// 2.启动主连接
p.SetClientConState(&MultiClientConSate{IsConnected: false, ClientObject: CLIENT_FIRST})
if p.FirstClient.Start() {
p.SetClientConState(&MultiClientConSate{IsConnected: true, ClientObject: CLIENT_FIRST})
} else {
log.Printf("start first fail\n")
if p.isEnableFirstAndSecond() {
p.setDetectMode(DETECT_MODE_FIRST_TO_SECOND)
} else {
p.setDetectMode(DETECT_MODE_ONLY_FIRST)
}
}
log.Printf("MultiClient start leave\n")
}
func (p *MultiClient) Stop() {
log.Printf("MultiClient Stop enter!\n")
p.StopCh <- "EXIT"
close(p.StopCh)
p.StopCh = nil
p.wg.Wait()
log.Printf("proc wait over\n")
p.FirstClient.Stop()
p.SecondClient.Stop()
log.Printf("MultiClient Stop leave\n")
}
func (p *MultiClient) isEnableFirstAndSecond() bool {
if p.Config.SecondEnable && p.Config.SecondAddress != "" {
return true
}
return false
}
func (p *MultiClient) handleMultiCenterProc() {
log.Printf("enter handle Multi proc")
defer p.wg.Done()
ticker := time.NewTicker(3 * time.Second)
defer ticker.Stop()
for {
if p.StopCh == nil {
log.Printf("stop ch closed\n")
return
}
select {
case value := <-p.StopCh:
log.Printf("ch:%v\n", value)
if value == "EXIT" {
log.Printf("MAIN stop proc\n")
return
}
case <-ticker.C:
p.timerProc()
log.Printf("================\n")
}
}
return
}
func (p *MultiClient) timerProc() {
switch p.DetectMode {
case DETECT_MODE_NONE:
log.Printf("NONE\n")
return
//当第一连接异常时
case DETECT_MODE_ONLY_FIRST:
log.Printf("ONLY_FIRST\n")
if p.FirstClient.TestCon() {
if p.FirstClient.Start() {
p.SetClientConState(&MultiClientConSate{IsConnected: true, ClientObject: CLIENT_FIRST})
p.setDetectMode(DETECT_MODE_NONE)
} else {
log.Printf("FirstClient test ok but start fail\n")
}
} else {
log.Printf("FirstClient test fail\n")
p.SetClientConState(&MultiClientConSate{IsConnected: false, ClientObject: CLIENT_FIRST})
}
//当第一连接异常时
case DETECT_MODE_FIRST_TO_SECOND:
log.Printf("FIRST_TO_SECOND\n")
if p.FirstClient.TestCon() {
if p.FirstClient.Start() {
p.SetClientConState(&MultiClientConSate{IsConnected: true, ClientObject: CLIENT_FIRST})
p.setDetectMode(DETECT_MODE_NONE)
} else {
log.Printf("FirstClient test ok but start fail\n")
}
} else {
log.Printf("FirstClient test fail, to test second\n")
if p.SecondClient.TestCon() {
if p.SecondClient.Start() {
p.SetClientConState(&MultiClientConSate{IsConnected: true, ClientObject: CLIENT_SECOND})
p.setDetectMode(DETECT_MODE_SECOND_TO_FIRST)
} else {
log.Printf("SecondClient test ok but start fail\n")
}
} else {
log.Printf("FirstClient test fail, second test fail\n")
}
}
//当第二连接异常时或正常时
case DETECT_MODE_SECOND_TO_FIRST:
log.Printf("SECOND_TO_FIRST\n")
if p.FirstClient.TestCon() {
if p.FirstClient.Start() {
p.SetClientConState(&MultiClientConSate{IsConnected: true, ClientObject: CLIENT_FIRST})
p.setDetectMode(DETECT_MODE_NONE)
} else {
log.Printf("FirstClient test ok but start fail\n")
}
} else {
// 判断当前第2连接是否处于异常状态
currentConstate := p.getClientConState()
if currentConstate.ClientObject == CLIENT_SECOND && currentConstate.IsConnected {
return
} else {
if p.SecondClient.TestCon() {
if p.SecondClient.Start() {
p.SetClientConState(&MultiClientConSate{IsConnected: true, ClientObject: CLIENT_SECOND})
p.setDetectMode(DETECT_MODE_SECOND_TO_FIRST)
} else {
log.Printf("SecondClient test ok but start fail\n")
}
}
}
}
}
}
func (p *MultiClient) SendAndRecv() {
// 根据当前状态决定
}
TCPClient
package plugin
import (
"fmt"
"log"
"net"
"sync"
"time"
)
type TCPClientConfig struct {
Address string
Port int
ConnectionType int
}
type TCPClient struct {
Address string
Port int
Config TCPClientConfig
Mtx sync.Mutex
LongCon net.Conn
}
func (p *TCPClient) SetConfig(cfg *TCPClientConfig) {
p.Mtx.Lock()
defer p.Mtx.Unlock()
p.Config.Address = cfg.Address
p.Config.Port = cfg.Port
p.Config.ConnectionType = cfg.ConnectionType
}
func (p *TCPClient) Start() bool {
return p.conServer(p.Config.Address, p.Config.Port)
}
func (p *TCPClient) Stop() bool {
if p.LongCon != nil {
p.LongCon.Close()
}
return true
}
func (p *TCPClient) conServer(addr string, port int) bool {
serverAddress := fmt.Sprintf("%s:%d", addr, port)
// 尝试创建TCP连接
conn, err := net.DialTimeout("tcp", serverAddress, 3*time.Second)
if err != nil {
log.Println("连接失败:", err)
return false
}
//defer conn.Close() // 确保连接最后能关闭
p.LongCon = conn
log.Println("conServer ok, ", serverAddress)
return true
}
func (p *TCPClient) TestCon() bool {
serverAddress := fmt.Sprintf("%s:%d", p.Config.Address, p.Config.Port)
// 尝试创建TCP连接
conn, err := net.DialTimeout("tcp", serverAddress, 3*time.Second)
if err != nil {
log.Println("连接失败:", err)
return false
}
defer conn.Close() // 确保连接最后能关闭
log.Println("TestCon ok, ", serverAddress)
return true
}
main
func testMultiClient() {
fmt.Println("testMultiClient begin")
mult := plugin.MultiClient{StopCh: make(chan string, 1)}
cfg := plugin.MultiClientConfig{
FirstAddress: "192.168.163.1",
FirstPort: 60000,
SecondEnable: true,
SecondAddress: "192.168.163.1",
SecondPort: 60001}
mult.SetConfig(&cfg)
mult.Start()
time.Sleep(30 * time.Second)
fmt.Println("test notify abnormal -1")
mult.NotifyConAbnormal()
fmt.Println("test notify abnormal -1 over")
time.Sleep(30 * time.Second)
fmt.Println("test notify abnormal -2")
mult.NotifyConAbnormal()
time.Sleep(30 * time.Second)
mult.Stop()
fmt.Println("testMultiClient end")
}
func main() {
fmt.Println("hello world")
//testMutilGO()
//testMutilGOSub()
testMultiClient()
fmt.Println("main over")
}

浙公网安备 33010602011771号