zoukankan      html  css  js  c++  java
  • golang实现udp接入服务器

    前端通过udp与接入服务器连接,接入服务器与后端tcp服务器维持tcp连接。目录结构及后端tcp服务器代码同上一篇博客。

    main.go

    package main
    
    import (
        "lotuslib"
    )
    
    const (
        ip   = "0.0.0.0"
        port = 1987
    )
    
    func main() {
        udplotus.UdpLotusMain(ip, port)
    }

    udplotus.go

    package udplotus
    
    import (
        "encoding/json"
        "log"
        "net"
        "strconv"
        "time"
    )
    
    const (
        proxy_timeout = 5
        proxy_server  = "127.0.0.1:1988"
        msg_length    = 1024
    )
    
    type Request struct {
        reqId      int
        reqContent string
        rspChan    chan<- string // writeonly chan
    }
    
    var requestMap map[int]*Request
    
    type Clienter struct {
        client  net.Conn
        isAlive bool
        SendStr chan *Request
        RecvStr chan string
    }
    
    func (c *Clienter) Connect() bool {
        if c.isAlive {
            return true
        } else {
            var err error
            c.client, err = net.Dial("tcp", proxy_server)
            if err != nil {
                return false
            }
            c.isAlive = true
            log.Println("connect to " + proxy_server)
        }
        return true
    }
    
    func ProxySendLoop(c *Clienter) {
    
        //store reqId and reqContent
        senddata := make(map[string]string)
        for {
            if !c.isAlive {
                time.Sleep(1 * time.Second)
                c.Connect()
            }
            if c.isAlive {
                req := <-c.SendStr
    
                //construct request json string
                senddata["reqId"] = strconv.Itoa(req.reqId)
                senddata["reqContent"] = req.reqContent
                sendjson, err := json.Marshal(senddata)
                if err != nil {
                    continue
                }
    
                _, err = c.client.Write([]byte(sendjson))
                if err != nil {
                    c.RecvStr <- string("proxy server close...")
                    c.client.Close()
                    c.isAlive = false
                    log.Println("disconnect from " + proxy_server)
                    continue
                }
                //log.Println("Write to proxy server: " + string(sendjson))
            }
        }
    }
    
    func ProxyRecvLoop(c *Clienter) {
        buf := make([]byte, msg_length)
        recvdata := make(map[string]string, 2)
        for {
            if !c.isAlive {
                time.Sleep(1 * time.Second)
                c.Connect()
            }
            if c.isAlive {
                n, err := c.client.Read(buf)
                if err != nil {
                    c.client.Close()
                    c.isAlive = false
                    log.Println("disconnect from " + proxy_server)
                    continue
                }
                //log.Println("Read from proxy server: " + string(buf[0:n]))
    
                if err := json.Unmarshal(buf[0:n], &recvdata); err == nil {
                    reqidstr := recvdata["reqId"]
                    if reqid, err := strconv.Atoi(reqidstr); err == nil {
                        req, ok := requestMap[reqid]
                        if !ok {
                            continue
                        }
                        req.rspChan <- recvdata["resContent"]
                    }
                    continue
                }
            }
        }
    }
    
    func handle(conn *net.UDPConn, remote *net.UDPAddr, id int, tc *Clienter, data []byte) {
    
        handleProxy := make(chan string)
        request := &Request{reqId: id, rspChan: handleProxy}
    
        request.reqContent = string(data)
    
        requestMap[id] = request
        //send to proxy
        select {
        case tc.SendStr <- request:
        case <-time.After(proxy_timeout * time.Second):
            conn.WriteToUDP([]byte("proxy server send timeout."), remote)
        }
    
        //read from proxy
        select {
        case rspContent := <-handleProxy:
            conn.WriteToUDP([]byte(rspContent), remote)
        case <-time.After(proxy_timeout * time.Second):
            conn.WriteToUDP([]byte("proxy server recv timeout."), remote)
        }
    }
    
    func UdpLotusMain(ip string, port int) {
        //start tcp server
        addr, err := net.ResolveUDPAddr("udp", ip+":"+strconv.Itoa(port))
        if err != nil {
            log.Fatalln("net.ResolveUDPAddr fail.", err)
            return
        }
        conn, err := net.ListenUDP("udp", addr)
        if err != nil {
            log.Fatalln("net.ListenUDP fail.", err)
            //os.Exit(1)
            return
        }
        log.Println("start udp server " + ip + " " + strconv.Itoa(port))
        defer conn.Close()
    
        //start proxy connect and loop
        var tc Clienter
        tc.SendStr = make(chan *Request, 1000)
        tc.RecvStr = make(chan string)
        tc.Connect()
        go ProxySendLoop(&tc)
        go ProxyRecvLoop(&tc)
    
        //listen new request
        requestMap = make(map[int]*Request)
    
        buf := make([]byte, msg_length)
        var id int = 0
        for {
            rlen, remote, err := conn.ReadFromUDP(buf)
            if err == nil {
                id++
                log.Println("connected from " + remote.String())
                go handle(conn, remote, id, &tc, buf[:rlen]) //new thread
            }
        }
    }

    udpclient.go

    package main
    
    import (
        "bufio"
        "fmt"
        "net"
        "os"
    )
    
    func main() {
    
        addr, err := net.ResolveUDPAddr("udp", ":1987")
        if err != nil {
            fmt.Println("net.ResolveUDPAddr fail.", err)
            os.Exit(1)
        }
    
        socket, err := net.DialUDP("udp", nil, addr)
        if err != nil {
            fmt.Println("net.DialUDP fail.", err)
            os.Exit(1)
        }
        defer socket.Close()
        r := bufio.NewReader(os.Stdin)
        for {
            switch line, ok := r.ReadString('
    '); true {
            case ok != nil:
                fmt.Printf("bye bye!
    ")
                return
            default:
                socket.Write([]byte(line))
                data := make([]byte, 1024)
                _, remoteAddr, err := socket.ReadFromUDP(data)
                if err != nil {
                    fmt.Println("error recv data")
                    return
                }
                fmt.Printf("from %s:%s
    ", remoteAddr.String(), string(data))
            }
        }
    }
  • 相关阅读:
    P4213【模板】杜教筛
    【SDOI2006】线性方程组
    【AHOI2018】排列
    【NOI2001】炮兵阵地
    【NOIP2012】疫情控制
    【AHKOI2017】rexp
    【十二省联考2019】春节十二响
    【TJOI2014】匹配
    【AT2645】Exhausted?
    P3809 【模板】后缀排序
  • 原文地址:https://www.cnblogs.com/ciaos/p/3854867.html
Copyright © 2011-2022 走看看