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
과 같이 각 언어의 Websocket 클라이언트 라이브러리를 사용할 수 있습니다.client.html
全局中间件
및分组中间件
로 정의할 수 있습니다. 현재 웹소켓은全局中间件
全局中间件
->分组中间件
미들웨어 정의
// 用作全局中间件
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 ),
)
examples
디렉터리에서 c1000k.png
그림을 볼 수 있습니다. 이 오픈 소스 프로젝트에 GoLand 개발 도구 지원을 제공한 JetBrains에게 감사드립니다.