pu369com

发现电脑上装着liteide,就用golang做一个TCP通讯测试(支持先启动client端和断线重连)

1、参考https://www.cnblogs.com/yin5th/p/9274495.html

server端 main.go

package main
 
import (
    "fmt"
    "net"
)
 
func main() {
    //   simple tcp server
    //1.listen ip+port
    listener, err := net.Listen("tcp", "0.0.0.0:9090")
    if err != nil {
        fmt.Printf("listen fail, err: %v\n", err)
        return
    }
 
    //2.accept client request
    //3.create goroutine for each request
    for {
        conn, err := listener.Accept()
        if err != nil {
            fmt.Printf("accept fail, err: %v\n", err)
            continue
        }
 
        //create goroutine for each connect
        go process(conn)
    }
}
 
func process(conn net.Conn) {
    defer conn.Close()
    for {
        var buf [128]byte
        n, err := conn.Read(buf[:])
 
        if err != nil {
            fmt.Printf("read from connect failed, err: %v\n", err)
            break
        }
        str := string(buf[:n])
        fmt.Printf("receive from client, data: %v\n", str)
    }
}

client端 main.go

package main
 
import (
    "bufio"
    "fmt"
    "net"
    "os"
    "strings"
)
 
func main() {
    conn, err := net.Dial("tcp", "localhost:9090")
    defer conn.Close()
    if err != nil {
        fmt.Printf("connect failed, err : %v\n", err.Error())
        return
    }
 
    inputReader := bufio.NewReader(os.Stdin)
 
    for {
        input, err := inputReader.ReadString('\n')
        if err != nil {
            fmt.Printf("read from console failed, err: %v\n", err)
            break
        }
        trimmedInput := strings.TrimSpace(input)
        if trimmedInput == "Q" {
            break
        }
        _, err = conn.Write([]byte(trimmedInput))
 
        if err != nil {
            fmt.Printf("write failed , err : %v\n", err)
            break
        }
    }
}

2.想要交互的话,只需在c/s两端的循环中适时用conn.Read 和conn.Write,用fmt.Printf显示出来即可

3、golang []byte和string相互转换 参考  https://www.cnblogs.com/DaBing0806/p/6680750.html

4,golang 几种字符串的连接方式 参考 https://blog.csdn.net/hatlonely/article/details/79156311  和https://studygolang.com/articles/3427

4、不想出现dos窗口的话 ,参考:https://blog.csdn.net/wangkai_123456/article/details/71158341

配置: go build -ldflags "-H windowsgui"
lite IDE配置 
     菜单 编译→编译配置

在“自定义”页面下的 BUILDAGRS 后添加 -ldflags "-H windowsgui"

5、不是本机测试的话,服务器端口参考https://blog.csdn.net/yoie01/article/details/21488457

如果只作为本地测试的话,可以写成loaclhost:xxxx

如果是监听外网的话,则直接写端口即可 :XXXX

注意添加防火墙入站规则。允许所有程序,指定本地特定端口,协议,远程所有端口。

 6,为解决断线重连问题,参考https://blog.csdn.net/mypc2010/article/details/78276702

将server端改为

 

//服务端反向控制
package main

import (
    "bytes"
    "fmt"
    "net"
)

func main() {
    //监听
    listener, err := net.Listen("tcp", ":9097")
    if err != nil {
        fmt.Printf("listen fail, err: %v\n", err)
        return
    }
    //循环,接受和处理
    for {
        conn, err := listener.Accept()
        if err != nil {
            fmt.Printf("accept fail, err: %v\n", err)
            continue
        }
        //在goroutine中处理
        go process(conn)
    }
}

func process(conn net.Conn) {
    defer conn.Close()
    for {
        //先向管道中写数据
        var buffer bytes.Buffer
        buffer.WriteString("i am server,ip: ")
        buffer.WriteString(LocalIp())
        ipa := buffer.String()
        conn.Write([]byte(ipa))
        //再从管道中读数据
        var buf [2048]byte
        n, err := conn.Read(buf[:])
        if err != nil {
            fmt.Printf("read from connect failed, err: %v\n", err)
            break
        }
        str := string(buf[:n])
        fmt.Printf("received from client, data: %v\n", str)
    }
}

//显示本机IP
func LocalIp() string {
    addrs, err := net.InterfaceAddrs()
    if err != nil {
        fmt.Println(err)
    }
    var ip string = "localhost"
    for _, address := range addrs {
        if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
            if ipnet.IP.To4() != nil {
                ip = ipnet.IP.String()
            }
        }
    }
    return ip
}

 

将client端改为

//client
package main

import (
    "bytes"
    "errors"
    "fmt"
    "net"
    "os"
    "time"
)

func main() {
    for {
        conn, err := net.Dial("tcp", "192.168.0.239:9097")
        if err != nil {
            fmt.Fprintf(os.Stderr, "Fatal error:%s", err.Error())
        } else {
            defer conn.Close()
            doWork(conn)
        }

        time.Sleep(3 * time.Second)
    }    
}
//显示本机IP
func LocalIp() string {
    addrs, err := net.InterfaceAddrs()
    if err != nil {
        fmt.Println(err)
    }
    var ip string = "localhost"
    for _, address := range addrs {
        if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
            if ipnet.IP.To4() != nil {
                ip = ipnet.IP.String()
            }
        }
    }
    return ip
}

//接收服务端发来的消息
func ClientMsgHandler(conn net.Conn, ch chan int) {

    var buf [2048]byte
    n, _ := conn.Read(buf[:])
    str := string(buf[:n])
    fmt.Printf("cmd from S, data: %v\n", str)
    if len(str) == 0 {
        //服务端无返回信息
        ch <- 2
    }
    //reply to server
    var buffer bytes.Buffer
    buffer.WriteString("i received,i am clent ip: ")
    buffer.WriteString(LocalIp())
    str2 := buffer.String()
    data2 := []byte(str2)
    conn.Write(data2)
}

//解决断线重连问题
func doWork(conn net.Conn) error {

    ch := make(chan int, 100)

    ticker := time.NewTicker(time.Second)
    defer ticker.Stop()
    for {
        select {
        case stat := <-ch:
            if stat == 2 {
                return errors.New("None Msg")
            }
        case <-ticker.C:
            ch <- 1
            go ClientMsgHandler(conn, ch)

        case <-time.After(time.Second * 10):
            defer conn.Close()
            fmt.Println("timeout")
        }

    }

    return nil
}

可先启动多个client,再启动server,且断线重连。

 

posted on 2018-12-11 12:43  pu369com  阅读(477)  评论(0编辑  收藏  举报

导航