正在显示
4 个修改的文件
包含
261 行增加
和
43 行删除
pkg/websocket/connmgr.go
0 → 100644
1 | +package websocket | ||
2 | + | ||
3 | +import ( | ||
4 | + "encoding/json" | ||
5 | + "fmt" | ||
6 | + "github.com/astaxie/beego" | ||
7 | + "github.com/gorilla/websocket" | ||
8 | + "gitlab.fjmaimaimai.com/mmm-go/gocomm/pkg/mybeego" | ||
9 | + "reflect" | ||
10 | + "sync" | ||
11 | +) | ||
12 | + | ||
13 | +var ( | ||
14 | + ErrorNotFound =fmt.Errorf("conn not exist") | ||
15 | +) | ||
16 | + | ||
17 | +var DefaultConnmgrs Connmgrs | ||
18 | +//初始化websocket链路管理器数量,通过uid取模放入不同的管理器 | ||
19 | +func InitWebsocketConnmgrs(mgrsSize int){ | ||
20 | + connmgrs :=make(map[int]IConnmgr,mgrsSize) | ||
21 | + for i:=0;i<mgrsSize;i++{ | ||
22 | + connmgrs[i] = NewMemoryConnmgr() | ||
23 | + } | ||
24 | + DefaultConnmgrs = Connmgrs(connmgrs) | ||
25 | +} | ||
26 | + | ||
27 | +type IConnmgr interface { | ||
28 | + Put(key,value interface{})(bool) | ||
29 | + Remove(key interface{}) error | ||
30 | + Get(key interface{})(value interface{},err error) | ||
31 | +} | ||
32 | +//连接管理器 | ||
33 | +type Connmgrs map[int]IConnmgr | ||
34 | +//将连接从指定连接管理器中移除 | ||
35 | +func (m Connmgrs)Remove(connmgrId int,key interface{})(err error){ | ||
36 | + //删除特定链接管理的连接 | ||
37 | + if mgr,ok:= m[connmgrId];ok{ | ||
38 | + err =mgr.Remove(key) | ||
39 | + if err!=nil{ | ||
40 | + return err | ||
41 | + } | ||
42 | + } | ||
43 | + return | ||
44 | +} | ||
45 | +//将连接装载到指定 连接管理器 | ||
46 | +func (m Connmgrs)Put(connmgrId int,key,value interface{})(result bool){ | ||
47 | + result =false | ||
48 | + if mgr,ok:= m[connmgrId];ok{ | ||
49 | + result =mgr.Put(key,value) | ||
50 | + if !result{ | ||
51 | + return | ||
52 | + } | ||
53 | + } | ||
54 | + return | ||
55 | +} | ||
56 | + | ||
57 | + | ||
58 | +type MemoryConnmgr struct { | ||
59 | + mutex sync.RWMutex | ||
60 | + Connections *JMap //conn | ||
61 | + Clients *JMap // key=uid(int64) value(*WebsocketConnection) | ||
62 | + //rooms //房间 | ||
63 | +} | ||
64 | + | ||
65 | +func NewMemoryConnmgr()*MemoryConnmgr{ | ||
66 | + keyType := reflect.TypeOf(&websocket.Conn{}) | ||
67 | + valueType := reflect.TypeOf(&WebsocketConnection{}) | ||
68 | + return &MemoryConnmgr{ | ||
69 | + Connections:NewJMap(keyType, valueType), | ||
70 | + Clients:NewJMap(reflect.TypeOf("1:1"), valueType), | ||
71 | + } | ||
72 | +} | ||
73 | + | ||
74 | +func(m *MemoryConnmgr)Put(key,value interface{})(result bool){ | ||
75 | + m.mutex.Lock() | ||
76 | + defer m.mutex.Unlock() | ||
77 | + if c,ok :=value.(*WebsocketConnection);ok{ | ||
78 | + idKey := fmt.Sprintf("%d:%d", c.Uid, c.AppId) | ||
79 | + return m.Connections.Put(c.Conn,c) && m.Clients.Put(idKey,c) | ||
80 | + } | ||
81 | + return false | ||
82 | +} | ||
83 | + | ||
84 | +func(m *MemoryConnmgr)Get(key interface{})(value interface{},err error){ | ||
85 | + var ok bool | ||
86 | + switch reflect.TypeOf(key).Kind() { | ||
87 | + case reflect.String: | ||
88 | + if value,ok = m.Clients.Get(key);!ok{ | ||
89 | + err = ErrorNotFound | ||
90 | + return | ||
91 | + } | ||
92 | + case reflect.Struct: | ||
93 | + if value,ok = m.Connections.Get(key);!ok{ | ||
94 | + err = ErrorNotFound | ||
95 | + return | ||
96 | + } | ||
97 | + default: | ||
98 | + err = ErrorNotFound | ||
99 | + } | ||
100 | + return | ||
101 | +} | ||
102 | + | ||
103 | +func(m *MemoryConnmgr)Remove(key interface{})(err error){ | ||
104 | + m.mutex.Lock() | ||
105 | + defer m.mutex.Unlock() | ||
106 | + if c,ok :=key.(*WebsocketConnection);ok{ | ||
107 | + key := fmt.Sprintf("%d:%d", c.Uid, c.AppId) | ||
108 | + m.Connections.Remove(c.Conn) | ||
109 | + m.Clients.Remove(key) | ||
110 | + } | ||
111 | + return | ||
112 | +} | ||
113 | + | ||
114 | +//发送数据 | ||
115 | +func SendDataByConnmgr(uid int64, appId int, sendMsg interface{}) bool { | ||
116 | + if sendMsg == nil || uid < 1 || appId < 1 { | ||
117 | + return false | ||
118 | + } | ||
119 | + var mgrId int =int(uid % int64(len(DefaultConnmgrs))) | ||
120 | + connmgr,ok :=(DefaultConnmgrs)[mgrId] | ||
121 | + if !ok{ | ||
122 | + return false | ||
123 | + } | ||
124 | + msg := &mybeego.Message{ | ||
125 | + Errno: 0, | ||
126 | + Errmsg: mybeego.NewMessage(0).Errmsg, | ||
127 | + Data: sendMsg, | ||
128 | + } | ||
129 | + msgByte, err := json.Marshal(msg) | ||
130 | + if err != nil { | ||
131 | + beego.Error(err) | ||
132 | + return false | ||
133 | + } | ||
134 | + key := fmt.Sprintf("%d:%d", uid, appId) | ||
135 | + if connI,err := connmgr.Get(key); err==nil { | ||
136 | + if conn, ok := connI.(*WebsocketConnection); ok { | ||
137 | + conn.Send(string(msgByte)) | ||
138 | + return true | ||
139 | + } | ||
140 | + } | ||
141 | + return false | ||
142 | +} |
pkg/websocket/connmgr_test.go
0 → 100644
1 | +package websocket | ||
2 | + | ||
3 | +import ( | ||
4 | + "github.com/gorilla/websocket" | ||
5 | + "testing" | ||
6 | +) | ||
7 | + | ||
8 | +func TestNewMemoryConnmgr(t *testing.T){ | ||
9 | + connmgr :=NewMemoryConnmgr() | ||
10 | + num:=100 | ||
11 | + var listConn []*WebsocketConnection | ||
12 | + for i:=0;i<num;i++{ | ||
13 | + listConn = append(listConn,&WebsocketConnection{ | ||
14 | + Uid:int64(i), | ||
15 | + AppId:1, | ||
16 | + Conn:&websocket.Conn{}, | ||
17 | + }) | ||
18 | + } | ||
19 | + for i:=range listConn{ | ||
20 | + connmgr.Put(listConn[i],listConn[i]) | ||
21 | + } | ||
22 | + if connmgr.Clients.Size() !=num && connmgr.Connections.Size()!=num{ | ||
23 | + t.Fatal("size error :",connmgr.Clients.Size(),connmgr.Connections.Size()) | ||
24 | + } | ||
25 | + for i:=range listConn{ | ||
26 | + connmgr.Remove(listConn[i]) | ||
27 | + } | ||
28 | + if connmgr.Clients.Size() !=0 && connmgr.Connections.Size()!=0{ | ||
29 | + t.Fatal("size error :",connmgr.Clients.Size(),connmgr.Connections.Size()) | ||
30 | + } | ||
31 | +} | ||
32 | + | ||
33 | +func BenchmarkNewMemoryConnmgr(b *testing.B) { | ||
34 | + connmgr :=NewMemoryConnmgr() | ||
35 | + var listConn []*WebsocketConnection | ||
36 | + for i:=0;i<b.N;i++{ | ||
37 | + listConn = append(listConn,&WebsocketConnection{ | ||
38 | + Uid:int64(i), | ||
39 | + AppId:1, | ||
40 | + Conn:&websocket.Conn{}, | ||
41 | + }) | ||
42 | + } | ||
43 | + b.ResetTimer() | ||
44 | + for i:=0;i<b.N;i++{ | ||
45 | + connmgr.Put(listConn[i],listConn[i]) | ||
46 | + } | ||
47 | + for i:=0;i<b.N;i++{ | ||
48 | + connmgr.Remove(listConn[i]) | ||
49 | + } | ||
50 | + if connmgr.Clients.Size() !=0 && connmgr.Connections.Size()!=0{ | ||
51 | + b.Fatal("size error :",connmgr.Clients.Size(),connmgr.Connections.Size()) | ||
52 | + } | ||
53 | +} |
@@ -17,12 +17,12 @@ const ( | @@ -17,12 +17,12 @@ const ( | ||
17 | Connected | 17 | Connected |
18 | ) | 18 | ) |
19 | 19 | ||
20 | -func init() { | ||
21 | - keyType := reflect.TypeOf(&websocket.Conn{}) | ||
22 | - valueType := reflect.TypeOf(&WebsocketConnection{}) | ||
23 | - Connections = NewJMap(keyType, valueType) | ||
24 | - Clients = NewJMap(reflect.TypeOf("1:1"), valueType) | ||
25 | -} | 20 | +//func init() { |
21 | +// keyType := reflect.TypeOf(&websocket.Conn{}) | ||
22 | +// valueType := reflect.TypeOf(&WebsocketConnection{}) | ||
23 | +// Connections = NewJMap(keyType, valueType) | ||
24 | +// Clients = NewJMap(reflect.TypeOf("1:1"), valueType) | ||
25 | +//} | ||
26 | 26 | ||
27 | type ReceiveHandler (func([]byte) *mybeego.Message) | 27 | type ReceiveHandler (func([]byte) *mybeego.Message) |
28 | 28 | ||
@@ -35,6 +35,7 @@ type WebsocketConnection struct { | @@ -35,6 +35,7 @@ type WebsocketConnection struct { | ||
35 | State ConnState | 35 | State ConnState |
36 | OnReceive ReceiveHandler | 36 | OnReceive ReceiveHandler |
37 | OnceClose sync.Once | 37 | OnceClose sync.Once |
38 | + Connmgrg *Connmgrs | ||
38 | } | 39 | } |
39 | 40 | ||
40 | func NewWebsocketConnection(conn *websocket.Conn,head *mybeego.RequestHead,recv ReceiveHandler)*WebsocketConnection{ | 41 | func NewWebsocketConnection(conn *websocket.Conn,head *mybeego.RequestHead,recv ReceiveHandler)*WebsocketConnection{ |
@@ -46,14 +47,15 @@ func NewWebsocketConnection(conn *websocket.Conn,head *mybeego.RequestHead,recv | @@ -46,14 +47,15 @@ func NewWebsocketConnection(conn *websocket.Conn,head *mybeego.RequestHead,recv | ||
46 | Wchan: make(chan string, 10), | 47 | Wchan: make(chan string, 10), |
47 | State: Connected, | 48 | State: Connected, |
48 | OnReceive: recv, | 49 | OnReceive: recv, |
50 | + Connmgrg:&DefaultConnmgrs, | ||
49 | } | 51 | } |
50 | } | 52 | } |
51 | 53 | ||
52 | //声明了两个cliets 管理 一个通过uid 一个通过conn管理 | 54 | //声明了两个cliets 管理 一个通过uid 一个通过conn管理 |
53 | // key(*websocket.Conn) value(*WebsocketConnection) | 55 | // key(*websocket.Conn) value(*WebsocketConnection) |
54 | -var Connections *JMap | 56 | +//var Connections *JMap |
55 | // key=uid(int64) value(*WebsocketConnection) | 57 | // key=uid(int64) value(*WebsocketConnection) |
56 | -var Clients *JMap | 58 | +//var Clients *JMap |
57 | 59 | ||
58 | type JMap struct { | 60 | type JMap struct { |
59 | sync.RWMutex | 61 | sync.RWMutex |
@@ -107,13 +109,12 @@ func (this *JMap) Put(k interface{}, v interface{}) bool { | @@ -107,13 +109,12 @@ func (this *JMap) Put(k interface{}, v interface{}) bool { | ||
107 | if !this.acceptable(k, v) { | 109 | if !this.acceptable(k, v) { |
108 | return false | 110 | return false |
109 | } | 111 | } |
110 | - if connI, ok := Clients.Get(k); ok { | 112 | + if connI, ok := this.m[k]; ok { |
111 | beego.Debug("key:", k, "已经连接,先剔除下线") | 113 | beego.Debug("key:", k, "已经连接,先剔除下线") |
112 | if conn, ok := connI.(*WebsocketConnection); ok { | 114 | if conn, ok := connI.(*WebsocketConnection); ok { |
113 | //conn.Conn.WriteMessage(websocket.TextMessage, []byte("您的帐号在其它地方登录,您被剔除下线")) | 115 | //conn.Conn.WriteMessage(websocket.TextMessage, []byte("您的帐号在其它地方登录,您被剔除下线")) |
114 | conn.Close() | 116 | conn.Close() |
115 | } | 117 | } |
116 | - | ||
117 | } | 118 | } |
118 | this.Lock() | 119 | this.Lock() |
119 | this.m[k] = v | 120 | this.m[k] = v |
@@ -152,14 +153,18 @@ func (this *JMap) Contains(k interface{}) bool { | @@ -152,14 +153,18 @@ func (this *JMap) Contains(k interface{}) bool { | ||
152 | 153 | ||
153 | func (c *WebsocketConnection) Serve() { | 154 | func (c *WebsocketConnection) Serve() { |
154 | c.State = Connected | 155 | c.State = Connected |
155 | - Connections.Put(c.Conn, c) | ||
156 | - key := fmt.Sprintf("%d:%d", c.Uid, c.AppId) | ||
157 | - Clients.Put(key, c) | ||
158 | - | 156 | + //Connections.Put(c.Conn, c) |
157 | + //key := fmt.Sprintf("%d:%d", c.Uid, c.AppId) | ||
158 | + //Clients.Put(key, c) | ||
159 | + c.Connmgrg.Put(c.GetConnmgrId(c.Uid),c,c) | ||
159 | go doWrite(c) | 160 | go doWrite(c) |
160 | doRead(c) | 161 | doRead(c) |
161 | } | 162 | } |
162 | 163 | ||
164 | +func(c *WebsocketConnection)GetConnmgrId(uid int64)int{ | ||
165 | + return (int)(uid % int64(len(*c.Connmgrg))) | ||
166 | +} | ||
167 | + | ||
163 | func (c *WebsocketConnection) Send(msg string) { | 168 | func (c *WebsocketConnection) Send(msg string) { |
164 | //panic("panic in websocket.send...") | 169 | //panic("panic in websocket.send...") |
165 | c.Wchan <- msg | 170 | c.Wchan <- msg |
@@ -167,14 +172,15 @@ func (c *WebsocketConnection) Send(msg string) { | @@ -167,14 +172,15 @@ func (c *WebsocketConnection) Send(msg string) { | ||
167 | 172 | ||
168 | func (c *WebsocketConnection) Close() { | 173 | func (c *WebsocketConnection) Close() { |
169 | c.OnceClose.Do(func(){ | 174 | c.OnceClose.Do(func(){ |
170 | - beego.Info("ws:close----uid:", c.Uid, "appid:", c.AppId, "state:", c.State) | 175 | + beego.Info("ws:close----uid:", c.Uid, "appid:", c.AppId, "state:", c.State ,"connmgr-id:",c.GetConnmgrId(c.Uid)) |
171 | if c.State == Disconnected { | 176 | if c.State == Disconnected { |
172 | return | 177 | return |
173 | } | 178 | } |
174 | 179 | ||
175 | - Connections.Remove(c.Conn) | ||
176 | - key := fmt.Sprintf("%d:%d", c.Uid, c.AppId) | ||
177 | - Clients.Remove(key) | 180 | + //Connections.Remove(c.Conn) |
181 | + //key := fmt.Sprintf("%d:%d", c.Uid, c.AppId) | ||
182 | + //Clients.Remove(key) | ||
183 | + c.Connmgrg.Remove(c.GetConnmgrId(c.Uid),c) | ||
178 | 184 | ||
179 | c.State = Disconnected | 185 | c.State = Disconnected |
180 | close(c.Echan) | 186 | close(c.Echan) |
@@ -236,27 +242,27 @@ func doWrite(c *WebsocketConnection) { | @@ -236,27 +242,27 @@ func doWrite(c *WebsocketConnection) { | ||
236 | } | 242 | } |
237 | } | 243 | } |
238 | 244 | ||
239 | -func SendDataByWs(uid int64, appId int, sendMsg interface{}) bool { | ||
240 | - if sendMsg == nil || uid < 1 || appId < 1 { | ||
241 | - return false | ||
242 | - } | ||
243 | - msg := &mybeego.Message{ | ||
244 | - Errno: 0, | ||
245 | - Errmsg: mybeego.NewMessage(0).Errmsg, | ||
246 | - Data: sendMsg, | ||
247 | - } | ||
248 | - msgByte, err := json.Marshal(msg) | ||
249 | - if err != nil { | ||
250 | - beego.Error(err) | ||
251 | - return false | ||
252 | - } | ||
253 | - key := fmt.Sprintf("%d:%d", uid, appId) | ||
254 | - if connI, ok := Clients.Get(key); ok { | ||
255 | - beego.Debug(ok) | ||
256 | - if conn, ok := connI.(*WebsocketConnection); ok { | ||
257 | - conn.Send(string(msgByte)) | ||
258 | - return true | ||
259 | - } | ||
260 | - } | ||
261 | - return false | ||
262 | -} | 245 | +//func SendDataByWs(uid int64, appId int, sendMsg interface{}) bool { |
246 | +// if sendMsg == nil || uid < 1 || appId < 1 { | ||
247 | +// return false | ||
248 | +// } | ||
249 | +// msg := &mybeego.Message{ | ||
250 | +// Errno: 0, | ||
251 | +// Errmsg: mybeego.NewMessage(0).Errmsg, | ||
252 | +// Data: sendMsg, | ||
253 | +// } | ||
254 | +// msgByte, err := json.Marshal(msg) | ||
255 | +// if err != nil { | ||
256 | +// beego.Error(err) | ||
257 | +// return false | ||
258 | +// } | ||
259 | +// key := fmt.Sprintf("%d:%d", uid, appId) | ||
260 | +// if connI, ok := Clients.Get(key); ok { | ||
261 | +// beego.Debug(ok) | ||
262 | +// if conn, ok := connI.(*WebsocketConnection); ok { | ||
263 | +// conn.Send(string(msgByte)) | ||
264 | +// return true | ||
265 | +// } | ||
266 | +// } | ||
267 | +// return false | ||
268 | +//} |
@@ -2,20 +2,37 @@ package websocket | @@ -2,20 +2,37 @@ package websocket | ||
2 | 2 | ||
3 | import ( | 3 | import ( |
4 | "github.com/gorilla/websocket" | 4 | "github.com/gorilla/websocket" |
5 | + "gitlab.fjmaimaimai.com/mmm-go/gocomm/pkg/log" | ||
5 | "gitlab.fjmaimaimai.com/mmm-go/gocomm/pkg/mybeego" | 6 | "gitlab.fjmaimaimai.com/mmm-go/gocomm/pkg/mybeego" |
6 | "html/template" | 7 | "html/template" |
7 | - "log" | ||
8 | "net/http" | 8 | "net/http" |
9 | "strconv" | 9 | "strconv" |
10 | "testing" | 10 | "testing" |
11 | + "time" | ||
11 | ) | 12 | ) |
12 | 13 | ||
13 | func Test_RunWebSocket(t *testing.T) { | 14 | func Test_RunWebSocket(t *testing.T) { |
15 | + //InitWebsocketConnmgrs(10) | ||
14 | //http.HandleFunc("/join",join) | 16 | //http.HandleFunc("/join",join) |
15 | //http.HandleFunc("/",home) | 17 | //http.HandleFunc("/",home) |
18 | + // | ||
19 | + //go TimerWork() | ||
16 | //log.Fatal(http.ListenAndServe(":8080",nil)) | 20 | //log.Fatal(http.ListenAndServe(":8080",nil)) |
17 | } | 21 | } |
18 | 22 | ||
23 | +func TimerWork(){ | ||
24 | + t :=time.NewTicker(10*time.Second) | ||
25 | + ch :=make(chan int,1) | ||
26 | + for { | ||
27 | + select { | ||
28 | + case <-t.C: | ||
29 | + //log.Info(DefaultConnmgrs[0]) | ||
30 | + SendDataByConnmgr(0,0,time.Now()) | ||
31 | + } | ||
32 | + } | ||
33 | + <-ch | ||
34 | +} | ||
35 | + | ||
19 | var upgrader = websocket.Upgrader{} | 36 | var upgrader = websocket.Upgrader{} |
20 | 37 | ||
21 | func join(w http.ResponseWriter, r *http.Request) { | 38 | func join(w http.ResponseWriter, r *http.Request) { |
-
请 注册 或 登录 后发表评论