GO EASY 框架 之 Server 06

目录

1、Overview

2、监听服务接口

3、easy/servers package

3.1、基础类Server

3.2、WWServer 服务

3.3、TcpServer

3.4、KCPServer

4、hookAgent链接钩子

5、创建一个WebScoket监听服务


1、Overview

本节主要介绍,easy的监听服务。例如websocket 监听,tcp监听,kcp监听服务等。每个类型的监听可以多次实例,用以监听多个端口;每个实例可以绑定自己的路由器,编码解码器等。

2、监听服务接口


import ("github.com/slclub/easy/route""github.com/slclub/easy/vendors/option"
)type ListenServer interface {Init(assignment option.Assignment)OnInit()Router() route.RouterStart()Hook() *hookAgent // agent 链接 回调//OnClose(func())Close()
}

3、easy/servers package

3.1、基础类Server

WSServer(WebSocket) 和 TCPServer(TcpSocket)等监听服务都是基于Server实现的。

  • Import

import ("crypto/tls""errors""github.com/slclub/easy/log""github.com/slclub/easy/nets/agent""github.com/slclub/easy/nets/conns""github.com/slclub/easy/route""github.com/slclub/easy/route/bind""github.com/slclub/easy/route/encode""github.com/slclub/easy/typehandle""github.com/slclub/easy/vendors/option""io""net""sync""time"
)
  • Class

/*** 基类 监听服务*/
type Server struct {agent.Gateln         net.Listenerbox        *ConnBoxrouter     route.Routerhook       *hookAgentconnOption *conns.Option
}

成员:

        box (*ConnBox)链接存储盒子;

        router(route.Router)路由器;

        hook (*hookAgent)链接阶段的事件;

        connOption(*conns.Option)conns选项;

  • Methods

func (self *Server) Init(assignment option.Assignment) {//self.Gate.Init(gate)assignment.Target(&self.Gate)assignment.Default(option.OptionFunc(func() (string, any) {return "Protocol", typehandle.EnCriPT_DATA_PROTOBUF}),option.OptionFunc(func() (string, any) {return "MaxConnNum", 100}),option.OptionFunc(func() (string, any) {return "PendingWriteNum", 100}),option.OptionFunc(func() (string, any) {return "MaxMsgLen", 4096}),option.OptionFunc(func() (string, any) {return "HTTPTimeout", 10 * time.Second}),option.OptionFunc(func() (string, any) {return "MsgDigit", conns.CONST_MSG_DIGIT}),)//if self.Protocol == "" {//	self.Protocol = typehandle.EnCriPT_DATA_PROTOBUF//}assignment.Apply()self.defaultRouteEncripty()self.Router().Encoder().LittleEndian(self.LittleEndian)
}func (self *Server) startBefore() {self.connOption = &conns.Option{Encrypt:   self.Router().Encoder(),MaxMsgLen: self.MaxMsgLen,MinMsgLen: 2,MsgDigit:  self.MsgDigit,}ln, err := net.Listen("tcp", self.Addr)if err != nil {log.Fatal("Listen error: %v", err)}if self.CertFile != "" || self.KeyFile != "" {config := &tls.Config{}config.NextProtos = []string{"http/1.1"}var err errorconfig.Certificates = make([]tls.Certificate, 1)config.Certificates[0], err = tls.LoadX509KeyPair(self.CertFile, self.KeyFile)if err != nil {log.Fatal("%v", err)}ln = tls.NewListener(ln, config)}self.ln = ln// 链接容器self.box = &ConnBox{server: self,conns:  make(ConnSet),mutex:  sync.Mutex{},}
}func (self *Server) defaultRouteEncripty() {switch self.Protocol {case typehandle.ENCRIPT_DATA_JSON:self.router.Binding(bind.NewBindJson(self.router.PathMap()), encode.NewJson(self.router.PathMap()))default:self.router.Binding(bind.NewBindProto(self.router.PathMap()), encode.NewProtobuf(self.router.PathMap()))}
}func (self *Server) Close() {// 利用钩子优雅关闭self.hook.EmitWithKey(CONST_SERVER_CLOSE, nil)// 关闭监听self.ln.Close()// 关闭哦链接池self.box.Close()}func (self *Server) Router() route.Router {return self.router
}func (self *Server) Hook() *hookAgent {return self.hook
}

3.2、WWServer 服务

WebSocket Server 服务源码;

WebSocket是用http升级转换而来;链接的关键是使用http.Handler接口;

  • http.Handler接口
type Handler interface {ServeHTTP(ResponseWriter, *Request)
}
  • WebSocket Server 服务源码
package serversimport ("github.com/gorilla/websocket""github.com/slclub/easy/log""github.com/slclub/easy/nets/agent""github.com/slclub/easy/nets/conns""github.com/slclub/easy/route""net/http"
)/*** web socket 监听服务*/
type WSServer struct {Serverupgrader websocket.Upgrader
}func NewWSServer() *WSServer {ser := Server{router: route.NewRouter(),hook:   newHookAgent(),}return &WSServer{Server: ser,}
}func (self *WSServer) Start() {self.startBefore()handleHttp := &WebSocketHandle{server: self,handle: dealHandle(&self.Server),}httpServer := &http.Server{Addr:           self.Addr,Handler:        handleHttp,ReadTimeout:    self.HTTPTimeout,WriteTimeout:   self.HTTPTimeout,MaxHeaderBytes: 1024,}go httpServer.Serve(self.ln)
}var _ ListenServer = &WSServer{}// ------------------------------------------------------------
// serverHttpHandle
type WebSocketHandle struct {server *WSServerhandle agent.AgentHandle
}func (self *WebSocketHandle) ServeHTTP(w http.ResponseWriter, r *http.Request) {if r.Method != "GET" {http.Error(w, "Method not allowed", 405)return}conn, err := self.server.upgrader.Upgrade(w, r, nil)if err != nil {log.Debug("upgrade error: %v", err)return}conn.SetReadLimit(int64(self.server.MaxMsgLen))if err = self.server.box.Add(conn); err != nil {conn.Close()log.Error("", err)return}wsConn := conns.NewWSConn(conn, self.server.connOption, self.server.PendingWriteNum, self.server.MaxMsgLen)ag := agent.NewAgent(wsConn)self.server.hook.EmitWithKey(CONST_AGENT_NEW, ag)ag.LoopRecv(self.handle)ag.Close()//ag.OnClose()self.server.hook.EmitWithKey(CONST_AGENT_CLOSE, ag)self.server.box.Del(conn)
}// function handle 路由分发
func dealHandle(serv *Server) agent.AgentHandle {return func(data []byte, ag agent.Agent) {msg, err := serv.Router().Encoder().Unmarshal(data)if err != nil {log.Debug("unmarshal message error: %v", err)return}err = serv.Router().Route(msg, ag)if err != nil {log.Debug("route message error: %v", err)return}}
}

3.3、TcpServer

源码

package serversimport ("github.com/slclub/easy/log""github.com/slclub/easy/nets/agent""github.com/slclub/easy/nets/conns""github.com/slclub/easy/route""net""time"
)type TCPServer struct {Server
}func NewTCPServer() *TCPServer {ser := Server{router: route.NewRouter(),hook:   newHookAgent(),}return &TCPServer{Server: ser,}
}func (self *TCPServer) Start() {self.startBefore()self.run()
}func (self *TCPServer) run() {var tempDelay time.Durationfor {conn, err := self.ln.Accept()if err != nil {if ne, ok := err.(net.Error); ok && ne.Temporary() {if tempDelay == 0 {tempDelay = 5 * time.Millisecond} else {tempDelay *= 2}if max := 1 * time.Second; tempDelay > max {tempDelay = max}log.Release("accept error: %v; retrying in %v", err, tempDelay)time.Sleep(tempDelay)continue}return}tempDelay = 0if self.box.Len() >= self.MaxConnNum {conn.Close()log.Debug("EASY.TCP too many connections")continue}self.box.Add(conn)tcpConn := conns.NewTCPConn(conn, self.PendingWriteNum, self.connOption)ag := agent.NewAgent(tcpConn)go func() {self.hook.EmitWithKey(CONST_AGENT_NEW, ag)ag.LoopRecv(dealHandle(&self.Server))ag.Close()//ag.OnClose()self.hook.EmitWithKey(CONST_AGENT_CLOSE, ag)self.box.Del(conn)// cleanup}()}
}

3.4、KCPServer

待完成

4、hookAgent链接钩子

  • 钩子

const (CONST_AGENT_CLOSE  = "CloseAgent"CONST_AGENT_NEW    = "NewAgent"CONST_SERVER_CLOSE = "CloseServer" // running your defined functions where you closed the listening server
)
  • 源码

type hookAgent struct {hook map[string][]typehandle.AgentHandle
}func newHookAgent() *hookAgent {return &hookAgent{hook: make(map[string][]typehandle.AgentHandle),}
}func (self *hookAgent) Append(hkey string, handle typehandle.AgentHandle) {if self.hook[hkey] == nil {self.hook[hkey] = []typehandle.AgentHandle{}}self.hook[hkey] = append(self.hook[hkey], handle)
}func (self *hookAgent) EmitWithKey(hkey string, ag agent.Agent) {if nil == self.hook[hkey] || len(self.hook[hkey]) == 0 {return}for _, fn := range self.hook[hkey] {fn(ag)}
}

5、创建一个WebScoket监听服务

	server1 = servers.NewWSServer()server1.Init(option.OptionWith(&agent.Gate{Addr:            ":" + strconv.Itoa(ListenPort),Protocol:        typehandle.ENCRIPT_DATA_JSON,PendingWriteNum: 2000,LittleEndian:    true,MaxConnNum:      20000,}).Default(option.DEFAULT_IGNORE_ZERO))

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/660139.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Apache Commons

介绍 官网:https://commons.apache.org/ Apache Commons 是一个开源的 Java 项目,旨在提供一组通用的、可复用的 Java 组件。这些组件涵盖了多个领域,包括字符串操作、输入输出、集合操作、数学计算、命令行解析等。 版本 commons-lang 和 …

【面试】MySQL的几种查询方式

书读百遍,其意自现 文章目录 基本查询条件查询排序查询聚合查询分组查询连接查询子查询联合查询 基本查询 最简单的查询形式,用于选择表中的所有行或指定列的数据。例如: SELECT * FROM TableName; -- 选择表中所有列的所有行 SELECT Colu…

蓝桥杯算法赛第4场小白入门赛强者挑战赛

蓝桥杯算法赛第4场小白入门赛&强者挑战赛 小白1小白2小白3强者1小白4强者2小白5强者3小白6强者4强者5强者6 链接&#xff1a; 第 4 场 小白入门赛 第 4 场 强者挑战赛 小白1 直接用C内置函数即可。 #include <bits/stdc.h> using namespace std;#include <bits…

ArrayList在添加元素时报错java.lang.ArrayIndexOutOfBoundException

一、添加单个元素数组越界分析 add源码如下 public boolean add(E e) {ensureCapacityInternal(size 1); // Increments modCount!!elementData[size] e;return true; } size字段的定义 The size of the ArrayList (the number of elements it contains). ArrayList的大…

雷达DoA估计的跨行业应用--麦克风阵列声源定位(Matlab仿真)

一、概述 麦克风阵列&#xff1a; 麦克风阵列是由一定数目的声学传感器&#xff08;麦克风&#xff09;按照一定规则排列的多麦克风系统&#xff0c;而基于麦克风阵列的声源定位是指用麦克风拾取声音信号&#xff0c;通过对麦克风阵列的各路输出信号进行分析和处理&#xff0c;…

力扣hot100 跳跃游戏 贪心

Problem: 55. 跳跃游戏 文章目录 思路复杂度Code 思路 &#x1f468;‍&#x1f3eb; 参考 挨着跳&#xff0c;记录最远能到达的地方 复杂度 时间复杂度: O ( n ) O(n) O(n) 空间复杂度: O ( 1 ) O(1) O(1) Code class Solution {public boolean canJump(int[] nums)…

7 STL

1、STL简介 1.1基本概念 可复用利用的东西&#xff01; 面向对象和泛型编程&#xff08;模板&#xff09;的 目的->提升复用性 为了建立数据结构和算法的一套标准->STL横空出世 STL(Standard Template Liberary)标准模板库广义分&#xff1a;容器、算法、迭代器容器…

lwIP 初探(第一节)

一、TCP/IP 协议栈架构 网络协议有很多&#xff0c;如 MQTT、TCP、UDP、IP 等协议&#xff0c;这些协议组成了 TCP/IP 协议栈&#xff0c; 同时&#xff0c;这些协议具有层次性&#xff0c;它们分布在应用层&#xff0c;传输层和网络层。TCP/IP 协议栈的分层结 构和网络协议得…

百无聊赖之JavaEE从入门到放弃(十五)包装类

目录 一.包装类概念 二.自动装箱和拆箱 三.包装类的缓存问题 一.包装类概念 基本数据类型的包装类 我们前面学习的八种基本数据类型并不是对象&#xff0c;为了将基本类型数据和对象之间实现互 相转化&#xff0c;Java 为每一个基本数据类型提供了相应的包装类。 Java 是…

获取Webshell的一些思路

1️⃣CMS获取webshell方法&#xff1a; 1、什么是CMS? CMS系统指的是内容管理系统。已经有别人开发好了整个网站的前后端&#xff0c;使用者只需要部署cms&#xff0c;然后通过后台添加数据&#xff0c;修改图片等工作&#xff0c;就能搭建好一个的WEB系统。 2、如何查看CM…

八斗学习笔记

1 初始环境安装 Anaconda安装(一款可以同时创建跟管理多个python环境的软件) https://blog.csdn.net/run_success/article/details/134656460 Anaconda创建一个新python环境(安装人工智能常用的第三方python包&#xff0c;如&#xff1a;tensorflow、keras、pytorch) https://…

12nm工艺,2.5GHz频率,低功耗Cortex-A72处理器培训

“ 12nm工艺&#xff0c;2.5GHz频率&#xff0c;低功耗Cortex-A72处理器培训” 本项目是真实项目实战培训&#xff0c;低功耗UPF设计&#xff0c;后端参数如下&#xff1a; 工艺&#xff1a;12nm 频率&#xff1a;2.5GHz 资源&#xff1a;2000_0000 instances 为了满足更多…

element中el-table组件 一整行点击都可以跳转

1. 属性(更多) row-click 当某一行被点击时会触发该事件 row, column, event 在Element UI的el-table组件中&#xff0c;要实现点击整行跳转&#xff0c;可以使用row-click事件。这个事件会在用户点击表格的一行时触发&#xff0c;并提供当前行的数据和行索引。 以下是一个简…

mongodb config

windows&#xff1a; 1.同级bin&#xff0c;data&#xff0c;log创建mongo.config文件 dbpathD:\Program\mongodb\data\db logpathD:\Program\mongodb\log\mongo.log logappendtrue #默认启用日志 journaltrue #过滤无用日志信息&#xff0c;调试设置为false quiettrue port2…

中科大计网学习记录笔记(二):网络核心

前言&#xff1a; 学习视频&#xff1a;中科大郑烇、杨坚全套《计算机网络&#xff08;自顶向下方法 第7版&#xff0c;James F.Kurose&#xff0c;Keith W.Ross&#xff09;》课程 该视频是B站非常著名的计网学习视频&#xff0c;但相信很多朋友和我一样在听完前面的部分发现信…

科技云报道:云原生PaaS,如何让金融业数字化开出“繁花”?

科技云报道原创。 在中国金融业数字化转型的历史长卷中&#xff0c;过去十年无疑是一部磅礴的史诗。 2017年&#xff0c;南京银行第一次将传统线下金融业务搬到了线上。那一年&#xff0c;它的互联网金融信贷业务实现了过去10年的业务总额。 2021年&#xff0c;富滇银行通过…

Parrot系统下ROS1试用CoCubeSim

Ubuntu 22.04安装和使用ROS1可行吗_ubuntu22.04安装ros1-CSDN博客 Parrot系统 如果你还不了解这个系统&#xff0c;如下文字就不用接着看了。 为何使用 为何更好的应用各类互联网信息&#xff0c;仅此而已。 开发利器 终端 ROS1和ROS2支持所有操作系统&#xff0c;支持的硬件…

【金蝶BI方案】用一张报表,分析生产完成情况

当老板问生产完成地怎样&#xff1f;难道还能拿出一叠报表让老板逐个细看&#xff1f;奥威-金蝶BI方案只用一张BI数据可视化报表就把整个生产完成情况给讲明白了。甚至还能满足老板想从不同角度进行分析的需求。 奥威-金蝶BI方案-BI生产完成情况报表 这张报表总结计算了生产合…

【CSS】css获取子元素的父元素,即通过子元素选择父元素(使用CSS伪类 :has() :not() )

这里写目录标题 一、:has获取第一个div获取包含 a.active 的 li获取第二个div 二、:not除了类名为active 的 a,其他的a的字体都为18px <div><h1>标题</h1></div><div><ul><li><a href"#" class"active">测…

我的数据结构c(给自己用的)

目录 顺序表&#xff1a; 链表&#xff1a; 栈&#xff1a; 队列&#xff1a; 我想在之后的大学数据结构课上需要自己写来做题&#xff0c;但每次都自己写&#xff0c;那太麻烦了&#xff0c;所以我就将这个博客来把所有的C语言的数据结构弄上去&#xff0c; 问我为什么不…