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 สำหรับโครงการโอเพ่นซอร์สนี้: