一个易于使用、快速、轻量的游戏服务器网络库
参考自:
nano开源库学习 –by 这一切没有想象那么糟 
探索 Golang 云原生游戏服务器开发,5 分钟上手 Nano 游戏服务器框架 
github Nano 
注: github的官方例子貌似跑不了 它导的包是github.com/lonnng/nano而不是github.com/lonng/nano, 有些方法也不存在了, 作者可能是改了一次名, 并对原有有包进行了更新, 但教程并未跟进, 使用上则没有影响
Component:
 1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
  
// Component 组件
 type  Component  interface  { 
    // 初始化函数
  Init () 
    // 初始化之后运行的函数
  AfterInit () 
    // 销毁之前将被调用
  BeforeShutdown () 
    // 销毁时被调用
  Shutdown () 
} 
 
 
nano 应用的功能就是由一些松散耦合的 Component 组成的, 它的接口用于控制它的生命周期 除此之外它应该实现某些具体的功能
Session:
 1
  2
  3
  4
  5
  6
  7
  8
  9
 10
  
// Session instance related to the client will be passed to Handler method as the first
 type  Session  struct  { 
	sync . RWMutex                         // protect data
  id            int64                   // session global unique id
 uid           int64                   // binding user id
 lastTime      int64                   // last heartbeat time
 entity        NetworkEntity           // low-level network entity
 data          map [ string ] interface {}  // session data store
 router        * Router 
} 
 
 
客户端连接服务器后建立Session, 它可以存储一些临时数据, 连接断开时释放所有数据
Group:
1
 2
 3
 4
 5
 6
 7
 8
  
// Group represents a session group which used to manage a number of
 // sessions, data send to the group will send to all session in it.
 type  Group  struct  { 
	mu        sync . RWMutex 
 	status    int32                       // channel current status
  name      string                      // channel name
 sessions  map [ int64 ] * session . Session  // session id map to session instance
 } 
 
 
Session组的封装, 对Group发信息会广播给所有其中的Session
四种消息类型:
Request(请求)和Response(响应): 客户端发起Request到服务器端,服务器端处理后会给其返回响应ResponseNotify: 客户端发给服务端的通知, 也就是不需要服务端给予回复的RequestPush: 服务端主动给客户端推送消息的类型 
  1
   2
   3
   4
   5
   6
   7
   8
   9
  10
  11
  12
  13
  14
  15
  16
  17
  18
  19
  20
  21
  22
  23
  24
  25
  26
  27
  28
  29
  30
  31
  32
  33
  34
  35
  36
  37
  38
  39
  40
  41
  42
  43
  44
  45
  46
  47
  48
  49
  50
  51
  52
  53
  54
  55
  56
  57
  58
  59
  60
  61
  62
  63
  64
  65
  66
  67
  68
  69
  70
  71
  72
  73
  74
  75
  76
  77
  78
  79
  80
  81
  82
  83
  84
  85
  86
  87
  88
  89
  90
  91
  92
  93
  94
  95
  96
  97
  98
  99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
  
package  main 
 import  ( 
	"fmt" 
 	"net/http" 
 
 	"github.com/lonng/nano" 
 	"github.com/lonng/nano/component" 
 	"github.com/lonng/nano/serialize/json" 
 	"github.com/lonng/nano/session" 
 ) 
 const  ( 
	// 测试房间 id
  testRoomID  =  1 
	// 测试房间 key
  roomIDKey  =  "ROOM_ID" 
) 
 type  Room  struct  { 
	Name   string 
 	Id     int 
 	Group  * nano . Group 
 } 
 type  RoomManager  struct  { 
	component . Base 
 	Rooms  map [ int ] * Room 
 } 
 // RoomManager 初始化完成后将被调用
 func  ( mgr  * RoomManager )  AfterInit ()  { 
	// 用户断开连接后将会被调用
  // 将它从房间中移除
 session . Lifetime . OnClosed ( func ( s  * session . Session )  { 
		if  ! s . HasKey ( roomIDKey )  { 
 			return 
 		} 
 		room  :=  s . Value ( roomIDKey ).( * Room ) 
 		// 移除这个会话
  room . Group . Leave ( s ) 
	}) 
 } 
 // 加入房间的业务逻辑处理
 func  ( mgr  * RoomManager )  Join ( s  * session . Session ,  msg  [] byte )  error  { 
	// 注意:这里 demo 仅仅只是加入 testRoomID
  room ,  found  :=  mgr . Rooms [ testRoomID ] 
	if  ! found  { 
 		room  =  & Room { 
 			Group :  nano . NewGroup ( fmt . Sprintf ( "room-%d" ,  testRoomID )), 
 		} 
 		mgr . Rooms [ testRoomID ]  =  room 
 	} 
 
 	fakeUID  :=  s . ID ()       // 这里仅仅是用 sessionId 模拟下 uid
  s . Bind ( fakeUID )         // 绑定 uid 到 session
 s . Set ( roomIDKey ,  room )  // 设置一下当前 session 关联到的房间
 // 推送房间所有成员到当前的 session
 s . Push ( "onMembers" ,  & struct  { 
		Members  [] int64  `json:"members"` 
 	}{ Members :  room . Group . Members ()}) 
 	// 广播房间内其它成员,有新人加入
  room . Group . Broadcast ( "onNewUser" ,  & struct  { 
		Content  string  `json:"content"` 
 	}{ Content :  fmt . Sprintf ( "New user: %d" ,  s . ID ())}) 
 	// 将 session 加入到房间 group 统一管理
  room . Group . Add ( s ) 
	fmt . Println ( s . Value ( roomIDKey ).( * Room )) 
 	// 回应当前用户加入成功
  return  s . Response ( & struct  { 
		Code    int     `json:"code"` 
 		Result  string  `json:"result"` 
 	}{ Result :  "success" }) 
 } 
 // 同步最新的消息给房间内所有成员
 func  ( mgr  * RoomManager )  Message ( s  * session . Session ,  msg  * struct  { 
	Name     string  `json:"name"` 
 	Content  string  `json:"content"` 
 })  error  { 
	fmt . Printf ( "msg: %v\n" ,  msg ) 
 	if  ! s . HasKey ( roomIDKey )  { 
 		return  fmt . Errorf ( "not join room yet" ) 
 	} 
 	room  :=  s . Value ( roomIDKey ).( * Room ) 
 	// 广播
  return  room . Group . Broadcast ( "onMessage" ,  msg ) 
} 
 func  main ()  { 
	components  :=  & component . Components {} 
 
 	// 组件注册 前端能发现注册后的组件
  components . Register ( 
		// 组件实例
  & RoomManager { 
			Rooms :  map [ int ] * Room {}, 
 		}, 
 		// 重写组件名字
  component . WithName ( "room" ), 
	) 
 	http . Handle ( "/web/" ,  http . StripPrefix ( "/web/" ,  http . FileServer ( http . Dir ( "web" )))) 
 	// 启动 nano
  nano . Listen ( ":3250" ,  // 端口号
 nano . WithIsWebsocket ( true ),  // 是否使用 websocket
 // nano.WithPipeline(pip),     // 是否使用 pipeline
 nano . WithCheckOriginFunc ( func ( _  * http . Request )  bool  {  return  true  }),  // 允许跨域
 nano . WithWSPath ( "/nano" ),                   // websocket 连接地址
 nano . WithDebugMode (),                       // 开启 debug 模式
 nano . WithSerializer ( json . NewSerializer ()),  // 使用 json 序列化器
 nano . WithComponents ( components ),            // 加载组件
 ) 
} 
 
 
前端