首页 > 其他分享 >[TODO]MultiClient

[TODO]MultiClient

时间:2024-09-08 21:49:05浏览次数:10  
标签:MultiClient Mtx return Config func TODO FIRST

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

  

标签:MultiClient,Mtx,return,Config,func,TODO,FIRST
From: https://www.cnblogs.com/iamcdx-2017/p/18403556

相关文章

  • HPC应用&生命科学领域软件AutoDock-GPU详细安装使用教程
    目录应用简介编译安装测试算例及提交脚本应用简介AutoDock-GPU是基于OpenCL的GPU加速版本分子对接软件autodock-4.2.6。可以支持DCU已经其他支持OpenCL的设备,如CPU和NvidiaGPU等。github源码: https://github.com/ccsb-scripps/AutoDock-GPU编译安装AutoDock-GPU......
  • autodock vina后处理分析
    拆分对接结果vina_split--inputresult.pdbqt--ligandcomplex/lig使用mv命令批量修改文件名,把01-09修改成1-9,便于批量处理foriin`seq19`;do>mv"lig0${i}.pdbqt""lig${i}.pdbqt">done使用Openbabel把pdbqt转成pdbforiin`seq120`;do>obabel......
  • 【python】一文带你领略,Python中非常强大的加密库--pycryptodome
    ✨✨欢迎大家来到景天科技苑✨✨......
  • 【A GUIDE TO CRC ERROR DETECTION ALGORITHM】 (译文3-Todo)
    11."Reflected"Table-DrivenImplementations“反射”表驱动实现Despitethefactthattheabovecodeisprobablyoptimizedaboutasmuchasitcouldbe,thisdidnotstopsomeenterprisingindividualsfrommakingthingsevenmorecomplicated.Toundersta......
  • 无法安装 autodock vina(可能是由于 boost)
    作为我正在编写的脚本的一部分,我需要安装autodockvina软件包以实现配体和蛋白质结合。每次我尝试“pipinstallvina”时,都会收到一条错误消息“ValueError:未找到Boost库位置!”。在尝试手动安装boost时,我无法运行bootstrap文件,因为它没有创建在线教程所说的b2文件夹。......
  • electron TodoList网页应用打包成linux deb、AppImage应用
    这里用的是windows的wsl的ubuntu环境electron应用打包linux应用需要linux下打包,这里用windows的wsl的ubuntu环境进行操作1)linuxubuntu安装nodejs、electron安装nodejs:sudoaptupdatesudoaptupgrade##快捷安装curl-fsSLhttps://deb.nodesource.com/setup_20.x......
  • 手写TodoList
    手写TodoList<scriptsetup>import{ref}from'vue'//给每个todo对象一个唯一的idletid=0constnewTodo=ref('')consttodos=ref([{id:id++,text:'LearnHTML'},{id:id++,text:'LearnJavaScript'},......
  • 【Python】Python中TODO的用法解析
    目录一.Python中的TODO是什么二.Python中什么时候使用TODO三.Pycharm中关于TODO的使用方式一.Python中的TODO是什么在Python中, TODO 通常不是一个语言内置的关键字或功能,而是被用作一种注释约定,来标记代码中需要进一步实现或改进的部分。开发者会在代码中使用 TODO......
  • 超简洁的待办事项自托管便签todo
    什么是todotodo是一个自托管的todoweb应用程序,可让您以简单且最少的方式跟踪您的todo。搭建使用Docker命令行方式进行搭建dockerrun-d-p8000:8000-vtodo_db:/usr/local/go/src/todo/todo.dbprologic/todoDocker-compose.ymlversion:'3'​services:to......
  • Wpf 使用 Prism 开发MyToDo应用程序
    MyToDo是使用WPF,并且塔配Prism框架进行开发的项目。项目中进行了前后端分离设计,客户端所有的数据均通过API接口获取。适合新手入门学习WPF以及Prism框架使用。首页统计以及点击导航到相关模块功能待办事项增删改查功能备忘录增删改查功能登录注册功能系统设备主题颜......