go语言转发ip Go语言发展

Golang 端口转发工具

初学go,写一个端口转发工具。很方便的小工具,希望能对大家学习go语言有所帮助。

创新互联建站主要从事网站建设、成都网站设计、网页设计、企业做网站、公司建网站等业务。立足成都服务江南,十多年网站建设经验,价格优惠、服务专业,欢迎来电咨询建站服务:13518219792

```Golang

package main

import(

"fmt"

"io"

"net"

"sync"

)

varlocksync.Mutex

vartrueList[]string

varipstring

varliststring

funcmain(){

ip="0.0.0.0:888"

server()

}

funcserver(){

fmt.Printf("Listening%s",ip)

lis,err:=net.Listen("tcp",ip)

iferr!=nil{

fmt.Println(err)

return

}

deferlis.Close()

for{

conn,err:=lis.Accept()

iferr!=nil{

fmt.Println("建立连接错误:%v\n",err)

continue

}

fmt.Println(conn.RemoteAddr(),conn.LocalAddr())

gohandle(conn)

}

}

funchandle(sconnnet.Conn){

defersconn.Close()

ip:="127.0.0.1:8888"

dconn,err:=net.Dial("tcp",ip)

iferr!=nil{

fmt.Printf("连接%v失败:%v\n",ip,err)

return

}

ExitChan:=make(chanbool,1)

gofunc(sconnnet.Conn,dconnnet.Conn,Exitchanbool){

io.Copy(dconn,sconn)

ExitChan-true

}(sconn,dconn,ExitChan)

gofunc(sconnnet.Conn,dconnnet.Conn,Exitchanbool){

io.Copy(sconn,dconn)

ExitChan-true

}(sconn,dconn,ExitChan)

-ExitChan

dconn.Close()

}

WebSocket+SLB(负载均衡)会话保持解决重连问题

写在最前面:由于现在游戏基本上采用全球大区的模式,全球玩家在同一个大区进行游戏,传统的单服模式已经不能够满足当前的服务需求,所以现在游戏服务器都在往微服务架构发展。当前我们游戏也是利用微服务架构来实现全球玩家同服游戏。

玩家每次断线(包括切换网络/超时断线)后应该会重新连接服务器,重连成功的话可以继续当前情景继续游戏,但是之前写的底层重连机制一直不能生效,导致每次玩家断线后重连都失败,要从账号登陆开始重新登陆,该文章写在已经定位了重连问题是由SLB引起后,提出的解决方案。

每次重连后,客户端向SLB发送建立连接,SLB都会重新分配一个网关节点,导致客户端连接到其他网关,重连失败。

会话保持的作用是什么?

开启SLB会话保持功能后,SLB会记录客户端的IP地址,在一定时间内,自动将同一个IP的连接转发到上次连接的网关。

在网络不稳定的情况下,游戏容易心跳或者发包超时,开启会话保持,能解决大部分情况下的重连问题。

但是在切换网络的时候,手机网络从Wifi切换成4G,自身IP会变,这时候连接必定和服务器断开,需要重新建立连接。由于IP已经变化,SLB不能识别到是同一个客户端发出的请求,会将连接转发到其他网关节点。所以使用TCP连接的情况下,SLB开启会话保持并不能解决所有的重连问题。

另外某些时刻,手机频繁开启和断开WI-FI,有时候可能不会断开网络,这并不是因为4G切换WI-FI时网络没断开,从4G切换到Wi-Fi网络,因为IP变了,服务器不能识别到新的IP,连接肯定是断开的。这时候网络没断开,主要是因为现在智能手机会对4G和Wi-Fi网络做个权重判断,当Wi-Fi网络频繁打开关闭时,手机会判断Wi-Fi网络不稳定,所有流量都走4G。所以网络没断开是因为一直使用4G连接,才没有断开。想要验证,只需要切换Wi-Fi时,把4G网络关闭,这样流量就必定走Wi-Fi。

上面说过,四层的TCP协议主要是基于IP来实现会话保持。但是切换网络的时候客户端的IP会变。所以要解决切换网络时的重连问题,只有两个方法:1. 当客户端成功连接网关节点后,记录下网关节点的IP,下次重连后不经过SLB,直接向网关节点发送连接请求。2.使用 SLB的七层(HTTP)转发服务。

当客户端经过SLB将连接转发到网关时,二次握手验证成功后向客户端发送自己节点的IP,这样客户端下次连接的时候就能直接连接网关节点。但是这样会暴露网关的IP地址,为安全留下隐患。

如果不希望暴露网关的IP地址,就需要增加一层代理层,SLB将客户端请求转发到代理层,代理层再根据客户端带有的key,转发到正确的网关节点上。增加一层代理层,不仅会增加请求的响应时间,还会增加整体框架的复杂度。

阿里云的七层SLB会话保持服务,主要是基于cookie的会话保持。客户端在往服务器发送HTTP请求后,服务器会返回客户端一个Response,SLB会在这时候,将经过的Response插入或者重写cookie。客户端获取到这个cookie,下次请求时会带上cookie,SLB判断Request的Headers里面有cookie,就将连接转发到之前的网关节点。

HTTP是短链接,我们游戏是长连接,所以用HTTP肯定不合适。但是可以考虑基于HTTP的WebSocket。

什么是WebSocket?

WSS(Web Socket Secure)是WebSocket的加密版本。

SLB对WebSocket的支持

查看阿里云SLB文档对WS的支持,说明SLB是支持WS协议的,并且SLB对于WS无需配置,只需要选用HTTP监听时,就能够转发WS协议。说明WS协议在SLB这边看来就是一个HTTP,这样WS走的也是七层的转发服务。只要SLB能够正常识别WS握手协议里Request的cookie和正常识别服务器返回的Response并且往里面插入cookie,就可以利用会话保持解决重连问题。

Go语言实现WS服务器有两种方法,一种是利用golang.org/x/net下的websocket包,另外一种方法就是自己解读Websocket协议来实现,由于WS协议一样是基于TCP协议之上,完全可以通过监听TCP端口来实现。

客户端发送Request消息

服务器返回Response消息

其中服务器返回的Sec-WebSocket-Accept字段,主要是用于客户端需要验证服务器是否支持WS。RFC6455文档中规定,在WebSocket通信协议中服务端为了证实已经接收了握手,它需要把两部分的数据合并成一个响应。一部分信息来自客户端握手的Sec-WebSocket-Keyt头字段:Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==。对于这个字段,服务端必须得到这个值(头字段中经过base64编码的值减去前后的空格)并与GUID"258EAFA5-E914-47DA-95CA-C5AB0DC85B11"组合成一个字符串,这个字符串对于不懂WebSocket协议的网络终端来说是不能使用的。这个组合经过SHA-1掩码,base64编码后在服务端的握手中返回。如果这个Sec-WebSocket-Accept计算错误浏览器会提示:Sec-WebSocket-Accept dismatch

如果返回成功,Websocket就会回调onopen事件

游戏服务器的使用的TCP协议,是在协议的包头使用4Byte来声明本协议长度,然后将协议一次性发送。但是在WS协议是通过Frame形式发送的,会将一条消息分为几个frame,按照先后顺序传输出去。这样做会有几个好处:

websocket的协议格式:

参数说明如下:

阿里云的SLB开启HTTP监听后,会检查过往的Request和Response请求,收到服务器返回的Response后,会往Response插入一个Cookie

客户端收到服务器的Response后,可以在Header中查到有个“Set-Cookie”字段,里面是SLB插入的Cookie值

客户端断开连接后,下次发送请求需要往Headers插入Cookie字段

分别在阿里云的两台ECS实例上部署WS服务器,打开8000端口,开启一个SLB服务,SLB服务选择HTTP方式监听,并且打开会话保持功能,Cookie处理方式选择植入Cookie。Demo服务器没有做HTTP健康监听的处理,健康检查这块可以先关掉。

在两台ECS上启动WS服务器,然后本地运行客户端,分别测试两台服务器是否能正常连接,测试完毕后,测试SLB能否正常工作。服务器和SLB都正常的情况下,运行客户端,客户端会得到以下结果

收到的三次Cookie都相同,说明Cookie是有正常植入工作的,并且三次都被SLB正确抓取了。

收到的三次serverId也都是同样的值,说明三次都是同一个ECS上的服务器响应。

至此,验证成功。

Websocket+SLB会话保持能够解决超时重连和切换网络时重连的问题。

参考:

阿里云会话保持

解答Wi-Fi与4G网络切换的困惑

WebSocket的实现原理

阿里云SLB对WebSocket的支持

HTTP Headers和Cookie

go语言聊天室实现(六)创建HTTP连接,并升级为长连接

我们在mian函数中,首先初始化配置文件,然后新建http连接。

这个连接创建之后,监听服务器的9999端口。如果url的路径后缀为 "/ws",就转发到ws/ws.go中的IndexHandler方法中。

这个方法中首先我们创建一个websocket的Upgrader实例,然后我们使用Upgrader的upgrade方法来升级一下我们的连接为长连接。

升级完成之后会返回一个*websocket.Conn的连接,我们之后所有的关于连接的操作,都是基于该conn的。

在该连接完成之后,我们将连接存放到一个名为Client的map中,以便之后管理更为方便。

之后,我们启动一个goroutine来读取连接中发送的信息内容,再根据内容进行相应的操作。

基于go的websocket消息推送的集群实现

目前websocket技术已经很成熟,选型Go语言,当然是为了节省成本以及它强大的高并发性能。我使用的是第三方开源的websocket库即gorilla/websocket。

由于我们线上推送的量不小,推送后端需要部署多节点保持高可用,所以需要自己做集群,具体架构方案如图:

Auth Service:鉴权服务,根据Token验证用户权限。

Collect Service:消息采集服务,负责收集业务系统消息,存入MongoDB后,发送给消息分发服务。

Dispatch Service:消息分发服务,根据路由规则分发至对应消息推送服务节点上。

Push Service:消息推送服务,通过websocket将消息推送给用户。

集群推送的关键点在于,web端与服务端建立长连接之后,具体跟哪个推送节点保持长连接的,如果我们能够找到对应的连接节点,那么我们就可以将消息推送出去。下面讲解一下集群的大致流程:

1. web端用户登录之后,带上token与后端推送服务(Push Service)保持长连接。

2. 推送服务收到连接请求之后,携带token去鉴权服务(Auth Service)验证此token权限,并返回用户ID。

3. 把返回的用户ID与长连接存入本地缓存,保持用户ID与长连接绑定关系。

4. 再将用户ID与本推送节点IP存入redis,建立用户(即长连接)与节点绑定关系,并设置失效时间。

5. 采集服务(Collect Service)收集业务消息,首先存入mongodb,然后将消息透传给分发服务(Dispatch Service)。

6. 分发服务收到消息之后,根据消息体中的用户ID,从redis中获取对应的推送服务节点IP,然后转发给对应的推送节点。

7. 推送服务节点收到消息之后,根据用户ID,从本地缓存中取出对应的长连接,将消息推送给客户端。

其他注意事项:

分享题目:go语言转发ip Go语言发展
URL地址:https://www.cdcxhl.com/article16/dodosgg.html

成都网站建设公司_创新互联,为您提供标签优化动态网站品牌网站制作网站导航微信小程序定制开发

广告

声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联

营销型网站建设