首页 > 代码库 > golang实现tcp接入服务器

golang实现tcp接入服务器

接入服务器和后端业务服务其维持tcp连接,多个前端请求通过接入服务器访问后端业务服务器,接入服务器可以方便增加路由功能,维护多个业务服务器,根据消息ID路由到具体的业务服务器。

项目目录如下

simplelotus  src    lotus      main.go    lotuslib      tcplotus.go    test      tcpclient.go      tcpserver.go  install

install源码如下:

#!/usr/bin/env bashif [ ! -f install ]; thenecho ‘install must be run within its container folder‘ 1>&2exit 1fiCURDIR=`pwd`OLDGOPATH="$GOPATH"export GOPATH="$CURDIR"gofmt -w srcgo install lotusexport GOPATH="$OLDGOPATH"echo ‘finished‘

main.go

package mainimport (    "lotuslib")const (    ip   = "0.0.0.0"    port = 1987)func main() {    tcplotus.TcpLotusMain(ip, port)}

tcplotus.go(和上游维持tcp连接)

package tcplotusimport (    "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}//store request mapvar requestMap map[int]*Requesttype 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}//send msg to upstream serverfunc 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))        }    }}//recv msg from upstream serverfunc 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            }        }    }}//one handle per requestfunc handle(conn *net.TCPConn, id int, tc *Clienter) {    data := make([]byte, msg_length)    handleProxy := make(chan string)    request := &Request{reqId: id, rspChan: handleProxy}    requestMap[id] = request    for {        n, err := conn.Read(data)        if err != nil {            log.Println("disconnect from " + conn.RemoteAddr().String())            conn.Close()            delete(requestMap, id)            return        }        request.reqContent = string(data[0:n])        //send to proxy        select {        case tc.SendStr <- request:        case <-time.After(proxy_timeout * time.Second):            //proxyChan <- &Request{cancel: true, reqId: id}            _, err = conn.Write([]byte("proxy server send timeout."))            if err != nil {                conn.Close()                delete(requestMap, id)                return            }            continue        }        //read from proxy        select {        case rspContent := <-handleProxy:            _, err := conn.Write([]byte(rspContent))            if err != nil {                conn.Close()                delete(requestMap, id)                return            }        case <-time.After(proxy_timeout * time.Second):            _, err = conn.Write([]byte("proxy server recv timeout."))            if err != nil {                conn.Close()                delete(requestMap, id)                return            }            continue        }    }}func TcpLotusMain(ip string, port int) {    //start tcp server    listen, err := net.ListenTCP("tcp", &net.TCPAddr{net.ParseIP(ip), port, ""})    if err != nil {        log.Fatalln("listen port error")        return    }    log.Println("start tcp server " + ip + " " + strconv.Itoa(port))    defer listen.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)    var id int = 0    for {        conn, err := listen.AcceptTCP()        if err != nil {            log.Println("receive connection failed")            continue        }        id++        log.Println("connected from " + conn.RemoteAddr().String())        go handle(conn, id, &tc)    }}

测试代码如下:

tcpserver.go

package mainimport (    "encoding/json"    "fmt"    "net")const (    msg_length = 1024)func Echo(c net.Conn) {    data := make([]byte, msg_length)    defer c.Close()    var recvdata map[string]string    recvdata = make(map[string]string, 2)    var senddata map[string]string    senddata = make(map[string]string, 2)    for {        n, err := c.Read(data)        if err != nil {            fmt.Printf("read message from lotus failed")            return        }        if err := json.Unmarshal(data[0:n], &recvdata); err == nil {            senddata["reqId"] = recvdata["reqId"]            senddata["resContent"] = "Hello " + recvdata["reqContent"]            sendjson, err := json.Marshal(senddata)            _, err = c.Write([]byte(sendjson))            if err != nil {                fmt.Printf("disconnect from lotus server")                return            }        }    }}func main() {    fmt.Printf("Server is ready...\n")    l, err := net.Listen("tcp", ":1988")    if err != nil {        fmt.Printf("Failure to listen: %s\n", err.Error())    }    for {        if c, err := l.Accept(); err == nil {            go Echo(c) //new thread        }    }}

tcpclient.go

package mainimport (    "bufio"    "fmt"    "net"    "os"    "time")type Clienter struct {    client  net.Conn    isAlive bool    SendStr chan string    RecvStr chan string}func (c *Clienter) Connect() bool {    if c.isAlive {        return true    } else {        var err error        c.client, err = net.Dial("tcp", "127.0.0.1:1987")        if err != nil {            fmt.Printf("Failure to connet:%s\n", err.Error())            return false        }        c.isAlive = true    }    return true}func (c *Clienter) Echo() {    line := <-c.SendStr    c.client.Write([]byte(line))    buf := make([]byte, 1024)    n, err := c.client.Read(buf)    if err != nil {        c.RecvStr <- string("Server close...")        c.client.Close()        c.isAlive = false        return    }    time.Sleep(1 * time.Second)    c.RecvStr <- string(buf[0:n])}func Work(tc *Clienter) {    if !tc.isAlive {        if tc.Connect() {            tc.Echo()        } else {            <-tc.SendStr            tc.RecvStr <- string("Server close...")        }    } else {        tc.Echo()    }}func main() {    var tc Clienter    tc.SendStr = make(chan string)    tc.RecvStr = make(chan string)    if !tc.Connect() {        return    }    r := bufio.NewReader(os.Stdin)    for {        switch line, ok := r.ReadString(‘\n‘); true {        case ok != nil:            fmt.Printf("bye bye!\n")            return        default:            go Work(&tc)            tc.SendStr <- line            s := <-tc.RecvStr            fmt.Printf("back:%s\n", s)        }    }}