欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

同一局域网内,在不知道对方ip的情况下进行tcp连接(go语言实现)

程序员文章站 2022-05-16 20:58:23
...

业务场景:同一局域网内,在不知道对方ip的情况下,进行文件的传输。

实现方式:

  1. 规定连接端口
  2. 找到本机ip
  3. 遍历网段

由于存在本地实际ip和对外开放ip不同的情况(例:本地连有线,使用360wifi开的无线)
同一局域网内,在不知道对方ip的情况下进行tcp连接(go语言实现)

完整代码如下:

var remoteCon net.Conn 
const Handle_Port = 5557
func GetRemoteCon() (net.Conn, error) {
	if remoteCon == nil {
		err := _startRemoteCon()
		if err != nil {
			return nil, err
		}
	} else {
		err := CheckConnect(remoteCon, "start")
		if err != nil {
			log.Println("长在尝试重连")
			er := _startRemoteCon()
			if er != nil {
				return nil, er
			}
		}
	}

	return remoteCon, nil
}

// 获取所有的ipv4地址
func LocalIPv4s() ([]string, error) {
	var ips []string
	addrs, err := net.InterfaceAddrs()
	if err != nil {
		return ips, err
	}

	for _, a := range addrs {
		if ipnet, ok := a.(*net.IPNet); ok && !ipnet.IP.IsLoopback() && ipnet.IP.To4() != nil {
			ips = append(ips, ipnet.IP.String())
		}
	}

	return ips, nil
}

func _startRemoteCon() error {
	ips, err := LocalIPv4s()
	if err != nil {
		return err
	}

	for _, ip := range ips {
		con := _syncConLan(ip)
		if con != nil {
			remoteCon = con
			return nil
		}
	}

	return errors.New("未连接成功,请检查服务是否已启动")
}

// 若5557端口被占用,该情况暂未处理
func _syncConLan(ip string) (net.Conn) {
	index := strings.LastIndex(ip, ".")
	format := fmt.Sprintf("%s.%%d:%d", ip[:index], Handle_Port)
	s := time.Now()
	length := 254
	wg := &sync.WaitGroup{}
	ch := make(chan net.Conn, length)
	for i := 0; i <= length; i++ {
		wg.Add(1)
		go func(i int) {
			defer wg.Done()
			con, err := net.DialTimeout("tcp", fmt.Sprintf(format, i), time.Millisecond*500)
			if err != nil {
				return
			}
			err = CheckConnect(con, "start")
			if err != nil {
				return
			}

			ch <- con
		}(i)
	}
	wg.Wait()

	if len(ch) <= 0 {
		return nil
	}
	res := make([]net.Conn, 0)
	for i := 0; i < len(ch); i++ {
		res = append(res, <-ch)
	}
	return res[0]
}
func CheckConnect(client net.Conn, str string) (err error) {
	_, err = client.Write([]byte(str))
	if err != nil {
		common.Log.Info(err)
		return
	}
	buf := make([]byte, 1024)
	size, err := client.Read(buf)
	if err != nil {
		common.Log.Info(err)
		return
	}
	var status = string(buf[0:size])
	if status != "ok" {
		err = errors.New("connect failed")
		return
	}
	return
}