netman
v1.0.5
net
، ويتطلب الاتصال goroutine
للمحافظة عليه، لكن netman
لا يحتاج إليه بناءً على حلقة الحدث، مما يقلل بشكل كبير من استخدام الذاكرة، وهو أكثر وضوحًا في السيناريوهات ذات عدد كبير من الاتصالات.3.8GB
. وكان الغرض هو اختبار استخدام الذاكرة، وتم اختيار بيئة الإنترانت للاختبار go get -u github.com/ikilobyte/netman
包头:4Byte
للإشارة إلى طول نص الحزمة، MsgID:4Byte
، وكلاهما يستخدم 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 ()
}
لا يقوم هذا الإطار بتغليف
client
tcp client
بلغات مختلفة، ويتم استخدام لغةgo
كمثال أدناه فقط لتوضيح كيفية استخدامها بيئة الإنتاج!
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 ()
}
طريقة الاستخدام هي نفس طريقة tcp، وقد تم تكييف طبقة الإطار لدمج udp مع
epoll
لتحقيق التزامن العالي لـ 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
الخاص بـ Javascriptclient.html
全局中间件
وبرامج分组中间件
حاليًا. يدعم websocket全局中间件
全局中间件
>分组中间件
تعريف الوسيطة
// 用作全局中间件
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 )
}
}
استخدم البرامج الوسيطة
// 全局中间件
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
و Websocket
options.go
يجب تكوين كلاهما في نفس الوقت حتى يصبح ساري المفعول.
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
في دليل examples
. شكرًا لـ JetBrains لتوفير دعم أداة تطوير GoLand لهذا المشروع مفتوح المصدر: