前端通过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('\n'); true {
case ok != nil:
fmt.Printf("bye bye!\n")
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\n", remoteAddr.String(), string(data))
}
}
}

golang实现udp接入服务器的更多相关文章

  1. golang实现tcp接入服务器

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

  2. Golang 高性能UDP Server实现

    通过Goroutine实现UDP消息并发处理 package main import ( "net" "fmt" "os" ) // 限制g ...

  3. 【Networking】k8s容器网络 && golang相关

    Bookmarks flannel/proxy.c at master · coreos/flannel kubernetes/kubernetes: Production-Grade Contain ...

  4. 【Network】高性能 UDP 应该怎么做?

    参考资料: EPOLL-UDP-GOLANG golang udp epoll - Google 搜索 go - golang: working with multiple client/server ...

  5. GPS服务端(上)-Socket服务端(golang)

    从第一次写GPS的服务端到现在,已经过去了八年时光.一直是用.net修修改改,从自己写的socket服务,到suppersocket,都是勉强在坚持着,没有真正的稳定过. 最近一段时间,服务端又出了两 ...

  6. TODO:Golang语言TCP/UDP协议重用地址端口

    TODO:Golang语言TCP/UDP协议重用地址端口 这是一个简单的包来解决重用地址的问题. go net包(据我所知)不允许设置套接字选项. 这在尝试进行TCP NAT时尤其成问题,其需要在同一 ...

  7. TODO:Golang UDP连接简单测试慎用Deadline

    TODO:Golang UDP连接简单测试慎用Deadline UDP 是User Datagram Protocol的简称, 中文名是用户数据报协议,是OSI(Open System Interco ...

  8. 【Network】golang 容器项目 flannel/UDP相关资料

    参考资料: flannel_百度搜索 Flannel首页.文档和下载 - 容器集群子网 - 开源中国社区 docker下基于flannel的overlay网络分析 - OPEN 开发经验库 flann ...

  9. golang中的udp编程

    1. udp server package main import ( "fmt" "net" ) func main() { // udp server li ...

随机推荐

  1. HelloWorld——Cocos2d-x学习历程(二)

    HelloWorld分析: 1."resource"文件夹 该文件夹主要用于存放游戏中需要的图片.音频和配置等资源文件. 2."include"和"s ...

  2. github/python/ show me the code 25题(二)

    第 0014 题: 纯文本文件 student.txt为学生信息, 里面的内容(包括花括号)如下所示: { "1":["张三",150,120,100], &q ...

  3. java 线程学习

    转载:详见处http://lavasoft.blog.51cto.com/62575/27069   Java多线程编程总结   下面是Java线程系列博文的一个编目:   Java线程:概念与原理 ...

  4. VS插件

    VS插件 背景 前些天去考科目二,感觉经历了一场不是高考却胜似高考的考试(10年前的5分之差, 还是难以释怀)!    一行八人,就我学的时间最少(4天,8人一辆车),教练都觉得我肯定还得再来一次! ...

  5. 身份验证cookies和Token

    后端服务器有两种基本的身份验证:1.是基于Cookie的身份验证,使用服务器端的cookie来对每次请求的用户进行身份验证.2. 较新的方法,基于令牌Token的认证,依赖于被发送到服务器上每个请求的 ...

  6. Sunday字符串匹配算法

    逛ACM神犇的博客的时候看到的这个神奇的算法 KMP吧,失配函数难理解,代码量长 BF吧,慢,很慢,特别慢. BM吧,我不会写... 现在看到了Sunday算法呀,眼前一亮,神清气爽啊. 字符串匹配算 ...

  7. 用JS判断两个数字的大小

    js中的var定义的变量默认是字符串,如果单纯的比较字符串的话,会出现错误,需要先转化为int类型在做比较. [备注:110和18在你写的程序中是18大的,因为 这两个数都是字符串,而1和1相等之后比 ...

  8. U3D 自带navmesh自动寻路教学

    网易博客转载 博主:啊赵 unity自带寻路Navmesh入门教程(一) 说明:从今天开始,我阿赵打算写一些简单的教程,方便自己日后回顾,或者方便刚入门的朋友学习.水平有限请勿见怪.不过请尊重码字截图 ...

  9. Java如何实现对Mysql数据库的行锁

    场景如下:     用户账户有余额,当发生交易时,需要实时更新余额.这里如果发生并发问题,那么会造成用户余额和实际交易的不一致,这对公司和客户来说都是很危险的. 那么如何避免:     网上查了下,有 ...

  10. ajax 上传图片 并预览

     <img {if !$article[pic]}style="display: none"{/if} width="82" height="6 ...