[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")
}

  

posted @ 2024-09-08 21:46  耳边呢喃  阅读(9)  评论(0编辑  收藏  举报