netman
v1.0.5
net
, una conexión requiere una goroutine
para mantenerse, pero netman
no la necesita según el bucle de eventos, lo que reduce en gran medida el uso de memoria, lo cual es más obvio en escenarios con un. gran número de conexiones.3.8GB
. El propósito era probar el uso de la memoria. Se seleccionó el entorno de intranet para la prueba. go get -u github.com/ikilobyte/netman
包头:4Byte
se usa para indicar la longitud del cuerpo del paquete, MsgID:4Byte
, ambos usan LittleEndian
package main
import (
"fmt"
"github.com/ikilobyte/netman/iface"
"github.com/ikilobyte/netman/server"
"time"
)
type Hello struct {
}
func ( h * Hello ) Do ( request iface. IRequest ) {
// 消息内容
body := request . GetMessage (). Bytes ()
// 当前连接
connect := request . GetConnect ()
// 所有连接(包含当前连接)
connections := request . GetConnects ()
fmt . Println ( body , connect , connections )
// 发送消息
n , err := connect . Send ( 0 , [] byte ( "hello world" ))
fmt . Printf ( "written %d err %v" , n , err )
// 关闭连接
connect . Close ()
}
type Hooks struct {
}
func ( h * Hooks ) OnOpen ( connect iface. IConnect ) {
fmt . Printf ( "connect onopen %d n " , connect . GetID ())
}
func ( h * Hooks ) OnClose ( connect iface. IConnect ) {
fmt . Printf ( "connect closed %d n " , connect . GetID ())
}
func main () {
s := server . New (
"0.0.0.0" ,
6650 ,
// 以下配置都是可选的,更多配置请看下方 `配置` 文档
// 包体最大长度
server . WithMaxBodyLength ( 1024 * 1024 * 100 ),
// Hooks,同样适用于UDP,是的框架将UDP和epoll结合在了一起
server . WithHooks ( new ( Hooks )),
// 使用自己的封包规则
// server.WithPacker(new(xxx))
// 开启TLS
//server.WithTLSConfig(&tls.Config{Certificates: nil})
// 心跳检测(允许连接的空闲时间),需要同时配置才能生效
server . WithHeartbeatIdleTime ( time . Hour * 5 ),
server . WithHeartbeatCheckInterval ( time . Second * 5 ),
)
// 添加路由
s . AddRouter ( 0 , new ( Hello )) // 消息ID为0的处理方法
//s.AddRouter(1,new(xxx))
s . Start ()
}
Este marco no encapsula deliberadamente
client
. Se pueden conectartcp client
en varios idiomas.go
se utiliza como ejemplo a continuación. Este ejemplo es solo para mostrar cómo usarlo. entorno de producción!
package main
import (
"fmt"
"github.com/ikilobyte/netman/util"
"io"
"log"
"net"
)
func main () {
conn , err := net . Dial ( "tcp" , "127.0.0.1:6565" )
if err != nil {
log . Panicln ( err )
}
// 使用默认的消息封包实现,当然你也可以自行实现
packer := util . NewDataPacker ()
body , err := packer . Pack ( 0 , [] byte ( "hello world" ))
if err != nil {
log . Panicln ( err )
}
// 发送消息
_ , err = conn . Write ( body )
if err != nil {
log . Panicln ( err )
}
// 读取消息
head := make ([] byte , 8 )
_ , err = io . ReadFull ( conn , head )
if err != nil {
log . Panicln ( err )
}
// 使用packer解析出message
message , err := packer . UnPack ( head )
if err != nil {
log . Panicln ( err )
}
// 根据消息长度读取包体
buff := make ([] byte , message . Len ())
n , err := conn . Read ( buff )
if err != nil {
log . Panicln ( err )
}
fmt . Printf ( "recv %s n " , buff [: n ])
conn . Close ()
}
El método de uso es el mismo que el de tcp. La capa de marco se ha adaptado para combinar udp con
epoll
para lograr una alta concurrencia de udp.
package main
import (
"fmt"
"github.com/ikilobyte/netman/iface"
"github.com/ikilobyte/netman/server"
)
type Handler struct {}
// Open 连接建立时
func ( h * Handler ) Open ( connect iface. IConnect ) {
// 获取query参数
query := connect . GetQueryStringParam ()
// 客户端连接的url应该设置为:ws://ip:port/path?key=value&token=xxx
// 支持任意path,如:ws://ip:port/x/y/z/a/b/c?key=value&token=xxx
if query . Get ( "token" ) != "xxx" {
connect . Close ()
return
}
fmt . Println ( "onopen" , connect . GetID ())
}
// Message 消息到来时
func ( h * Handler ) Message ( request iface. IRequest ) {
// 消息
message := request . GetMessage ()
// 当前连接
connect := request . GetConnect ()
// 判断是什么消息类型
if message . IsText () {
// 发送文本消息
fmt . Println ( connect . Text ( message . Bytes ()))
} else {
// 发送二进制消息
fmt . Println ( connect . Binary ( message . Bytes ()))
}
}
// Close 连接关闭时
func ( h * Handler ) Close ( connect iface. IConnect ) {
fmt . Println ( "onclose" , connect . GetID ())
}
func main () {
s := server . Websocket (
"0.0.0.0" ,
6565 ,
new ( Handler ), // websocket事件回调处理
)
s . Start ()
}
new Websocket
de Javascript.client.html
全局中间件
y分组中间件
. Actualmente, websocket solo admite全局中间件
全局中间件
>分组中间件
Definir middleware
// 用作全局中间件
func global () iface. MiddlewareFunc {
return func ( ctx iface. IContext , next iface. Next ) interface {} {
fmt . Println ( "前置中间件" )
fmt . Println ( "ctx data" , ctx . GetConnect (), ctx . GetRequest (), ctx . GetMessage ())
ctx . Set ( "key" , "value" )
ctx . Set ( "now" , time . Now (). UnixNano ())
// 继续往下执行
resp := next ( ctx )
fmt . Println ( "后置中间件" )
return resp
}
}
// 用作分组中间件
func space () iface. MiddlewareFunc {
return func ( ctx iface. IContext , next iface. Next ) interface {} {
fmt . Println ( ctx . Get ( "key" ), ctx . Get ( "now" ))
return next ( ctx )
}
}
Usar software intermedio
// 全局中间件
s . Use ( global ())
// 分组,只有对应的路由才会执行
g := s . Group ( space ())
{
g . AddRouter ( 1 , new ( xxx ))
//g.AddRouter(2,new(xxx))
//g.AddRouter(3,new(xxx))
}
Tcp(TLS)
, UDP
y Websocket
options.go
Ambos deben configurarse al mismo tiempo para que surtan efecto.
server . New (
"0.0.0.0" , 6565 ,
// 表示60秒检测一次
server . WithHeartbeatCheckInterval ( time . Second * 60 ),
// 表示一个连接如果180秒内未向服务器发送任何数据,此连接将被强制关闭
server . WithHeartbeatIdleTime ( time . Second * 180 ),
)
server . New (
"0.0.0.0" ,
6565 ,
// 0表示不限制长度
// 这里配置的是100MB,当某条消息超过100MB时,会被拒绝处理
server . WithMaxBodyLength ( 1024 * 1024 * 100 ),
)
server . New (
"0.0.0.0" ,
6565 ,
server . WithTCPKeepAlive ( time . Second * 30 ),
)
tlsConfig := & tls. Config {
Certificates : []tls. Certificate { ... },
}
s := server . New (
"0.0.0.0" ,
6565 ,
// 传入相关配置后,即可开启TLS
server . WithTLSConfig ( tlsConfig ),
)
IPacker
. // IPacker 定义(框架内部已经定义,你只需要实现即可)
type IPacker interface {
Pack ( msgID uint32 , data [] byte ) ([] byte , error ) // 封包
UnPack ([] byte ) ( IMessage , error ) // 解包
SetMaxBodyLength ( uint32 ) // 设置包体最大长度限制
GetHeaderLength () uint32 // 获取头部长度
}
type YouPacker struct {
// implements IPacker
// ...
}
server . New (
"0.0.0.0" ,
6565 ,
// 自定义Packer
server . server . WithPacker ( new ( YouPacker )),
)
server . New (
"0.0.0.0" ,
6565 ,
server . WithNumEventLoop ( runtime . NumCPU () * 3 ),
server . WithHooks ( new ( Hooks )), // hooks
server . WithMaxBodyLength ( 0 ), // 配置包体最大长度,默认为0(不限制大小)
server . WithTCPKeepAlive ( time . Second * 30 ), // 设置TCPKeepAlive
server . WithLogOutput ( os . Stdout ), // 框架运行日志保存的地方
server . WithPacker ( new ( YouPacker )), // 可自行实现数据封包解包
// 心跳检测机制,二者需要同时配置才会生效
server . WithHeartbeatCheckInterval ( time . Second * 60 ), // 表示60秒检测一次
server . WithHeartbeatIdleTime ( time . Second * 180 ), // 表示一个连接如果180秒内未向服务器发送任何数据,此连接将被强制关闭
// 开启TLS
server . WithTLSConfig ( tlsConfig ),
)
c1000k.png
en el directorio de examples
. Gracias a JetBrains por brindar soporte a la herramienta de desarrollo GoLand para este proyecto de código abierto: