分享
  1. 首页
  2. 文章

golang实现tcp接入服务器

ciaos · · 11581 次点击 · · 开始浏览
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

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

项目目录如下

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

install源码如下:

#!/usr/bin/env bash
if [ ! -f install ]; then
echo 'install must be run within its container folder' 1>&2
exit 1
fi
CURDIR=`pwd`
OLDGOPATH="$GOPATH"
export GOPATH="$CURDIR"
gofmt -w src
go install lotus
export GOPATH="$OLDGOPATH"
echo 'finished'

main.go

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

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

package tcplotus
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
}
//store request map
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
}
//send msg to upstream server
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))
 }
 }
}
//recv msg from upstream server
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
 }
 }
 }
}
//one handle per request
func 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 main
import (
 "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 main
import (
 "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)
 }
 }
}

有疑问加站长微信联系(非本文作者)

本文来自:博客园

感谢作者:ciaos

查看原文:golang实现tcp接入服务器

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

关注微信
11581 次点击
暂无回复
添加一条新回复 (您需要 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传

用户登录

没有账号?注册
(追記) (追記ここまで)

今日阅读排行

    加载中
(追記) (追記ここまで)

一周阅读排行

    加载中

关注我

  • 扫码关注领全套学习资料 关注微信公众号
  • 加入 QQ 群:
    • 192706294(已满)
    • 731990104(已满)
    • 798786647(已满)
    • 729884609(已满)
    • 977810755(已满)
    • 815126783(已满)
    • 812540095(已满)
    • 1006366459(已满)
    • 692541889

  • 关注微信公众号
  • 加入微信群:liuxiaoyan-s,备注入群
  • 也欢迎加入知识星球 Go粉丝们(免费)

给该专栏投稿 写篇新文章

每篇文章有总共有 5 次投稿机会

收入到我管理的专栏 新建专栏