WebSocket 模块

CBrother在1.0.7版本以后提供了WebSocket支持,包含在Http扩展中,既可以当服务器,也可以当客户端。

WebSocket可以说是HTTP服务与TCP服务的合体,当由HTTP服务器升级完成协议后交由TCP模块接管。在使用之前你需要先了解HttpServer和TcpModule的相关用法。

WebSocketModule

WebSocketModule底层是TcpModule,所以WebSocketModule是TcpModule的超集。

·WebSocketModule接口

函数描述用法
setWebSocketAction(actobj) 设置响应接口 wsModule.setWebSocketAction(actobj)
start() 启动服务,返回true为启动成功 wsModule.start()
stop() 停止服务 wsModule.stop()
setThreadCount(cnt) 设置工作线程数量 默认5个 可以大到CPU核数3 但是消耗资源增多 wsModule.setThreadCount(8)
setMaxConnectCount(cnt) 设置最大管理的连接数量,根据需求设置 过大了开销资源很大 默认2048 wsModule.setMaxConnectCount(5000)
setSockNormalBuflLen(recvLen,sendLen) 设置socket接收缓冲和发送缓冲默认值,默认4096 wsModule.setSockNormalBuflLen(1024\10,1024*15)
connect(req) 主动连接某TCP服务器,返回socketid,-1为失败,参数是一个HttpClientRequest对象 wsModule.connect(req)
sendData(socketid,type,str,ismask) 发送字符串数据,socketid:socket标示 type:消息类型(WS_MSG_TEXT) str:字符串 ismask为是否异或加密,默认不加密,返回true为成功 wsModule.sendData(socketid,WS_MSG_TEXT,"111")
sendData(socketid,type,bytearray,len,ismask) 发送二进制,socketid:socket标示 type:消息类型(WS_MSG_BINARY) bytearray:二进制数据 len:发送长度 ismask为是否异或加密,默认不加密,返回true为成功 wsModule.sendData(socketid,WS_MSG_BINARY,byteArray,10)
closeSocket(socketid) 关闭socket,返回true为成功 wsModule.closeSocket(socketid)
getRemoteIP(socketid) 获取socket对端IP var ip = wsModule.getRemoteIP(socketid)
setSockBuflLen(socketid,recvLen,sendLen) 设置socketid接收缓冲和发送缓冲大小,socketid:socket标示 recvLen:接收缓冲 sendLen:发送缓冲 不设置用默认的 只能在OnAccept和OnConnect里调用 wsModule.setSockBuflLen(socketid,10*1024,10,1024)
getSocketCount() 获取当前管理的socket数量 wsModule.getSocketCount()

setWebSocketAction,setThreadCount,setMaxConnectCount,setSockNormalBuflLen,要在start之前调用。

·WebSocketModule 响应Action类可以有如下接口

function OnUpgrade(req,sock,isaccept),协议升级成功。

function OnAccept(sock),接管新的连接。

function OnClose(sock),连接断开。

function OnRecv(socketid,type,data,len)接收到数据。websocket消息有四种:文本,二进制,ping和pong,定义在lib/wsdef.cb里

function OnSend(sock,len)发送成功。

function OnConnect(sock)接管主动发起的连接。

这个方法会被多线程调用,如果要访问公共资源需要加锁。但对于同一个socket而言,OnRecv是串行的。

·WebSocketModule 例子

服务器例子

  1. import CBHttp.code
  2. import lib/wsdef
  3. class WebSocketAction
  4. {
  5. var _webSocketModule;
  6. var _lock = new Lock();
  7. var _userMap = new Map();
  8. function WebSocketAction(wsModule)
  9. {
  10. _webSocketModule = wsModule;
  11. }
  12. function OnUpgrade(req,socketid,isaccept)
  13. {
  14. if(isaccept) //isaccept为true时表示是作为服务器接管客户端,req则为本次请求的request对象,你可以读取它的信息与socketid建立关系,运行在http服务线程内
  15. {
  16. var cookie = req.getCookie(0);
  17. var name = cookie.getValue();
  18. print "onupgrade " + name;
  19. _lock.lock();
  20. _userMap.add(socketid,name);
  21. _lock.unlock();
  22. }
  23. }
  24. function OnAccept(socketid)//接管成功,运行在TcpModule线程内
  25. {
  26. _lock.lock();
  27. var username = _userMap.get(socketid);
  28. if(username != null)
  29. {
  30. print username + " onaccept";
  31. }
  32. _lock.unlock();
  33. }
  34. function OnRecv(socketid,type,data,len)
  35. {
  36. if(type == WS_MSG_TEXT)//文本消息是个字符串
  37. {
  38. _lock.lock();
  39. var username = _userMap.get(socketid);
  40. if(username != null)
  41. {
  42. print "onrecv " + username + " text:" + data;
  43. _webSocketModule.sendData(socketid,WS_MSG_TEXT,"hi " + username + ",I recv your text msg.");
  44. }
  45. _lock.unlock();
  46. }
  47. else if(type == WS_MSG_BINARY)//二进制是个ByteArray对象
  48. {
  49. _lock.lock();
  50. var username = _userMap.get(socketid);
  51. if(username != null)
  52. {
  53. print "onrecv " + username + " binary datalen:" + len + " " + data.readString();
  54. _webSocketModule.sendData(socketid,WS_MSG_TEXT,"hi " + username + ",I recv your binary msg.");
  55. }
  56. _lock.unlock();
  57. }
  58. }
  59. function OnClose(socketid)
  60. {
  61. _lock.lock();
  62. var username = _userMap.get(socketid);
  63. if(username != null)
  64. {
  65. print username + " Onclose!";
  66. _userMap.remove(socketid);
  67. }
  68. _lock.unlock();
  69. }
  70. }
  71. function main(parm)
  72. {
  73. var websocket = new WebSocketModule();
  74. websocket.setWebSocketAction(new WebSocketAction(websocket));
  75. websocket.start();
  76. var httpServer = new HttpServer();
  77. httpServer.setWebSocketModule("wsb.cb",websocket);//将websocket模块交给httpserver,当用户访问ws://xxx.xxx.xxx.xxx/wsb.cb时候进行协议升级操作
  78. httpServer.startServer();
  79. while(1) //主线程不能退出
  80. {
  81. Sleep(1000);
  82. }
  83. }

客户端例子

  1. import CBHttp.code
  2. import lib/wsdef
  3. class WebSocketAction
  4. {
  5. var _webSocketModule;
  6. var _lock = new Lock();
  7. var _userMap = new Map();
  8. function WebSocketAction(wsModule)
  9. {
  10. _webSocketModule = wsModule;
  11. }
  12. function OnUpgrade(req,socketid,isaccept)
  13. {
  14. if(!isaccept)//主动连接的isaccept为false,运行在发起connect的线程里
  15. {
  16. var cookie = req.getCookie(0);
  17. if(cookie != null)
  18. {
  19. _lock.lock();
  20. _userMap.add(socketid,cookie.getValue());
  21. print cookie.getValue() + " onupgrade success!";
  22. _lock.unlock();
  23. }
  24. }
  25. }
  26. function OnConnect(socketid)
  27. {
  28. _lock.lock();
  29. var username = _userMap.get(socketid);
  30. _lock.unlock();
  31. if(username != null)
  32. {
  33. print username + " connect suc!";
  34. if(username == "xiaoming")
  35. {
  36. _webSocketModule.sendData(socketid,WS_MSG_TEXT,"this is " + username + ",I send a text msg.");
  37. }
  38. else
  39. {
  40. var byteary = new ByteArray();
  41. byteary.writeString("this is " + username + ",I send a binary msg.");
  42. _webSocketModule.sendData(socketid,WS_MSG_BINARY,byteary);
  43. }
  44. }
  45. }
  46. function OnRecv(socketid,type,data,len)
  47. {
  48. if(type == WS_MSG_TEXT)
  49. {
  50. _lock.lock();
  51. var username = _userMap.get(socketid);
  52. _lock.unlock();
  53. if(username != null)
  54. {
  55. print data;
  56. }
  57. }
  58. }
  59. function OnClose(socketid)
  60. {
  61. _lock.lock();
  62. var username = _userMap.get(socketid);
  63. if(username != null)
  64. {
  65. print username + " onclose!";
  66. _userMap.remove(socketid);
  67. }
  68. _lock.unlock();
  69. }
  70. }
  71. function main(parm)
  72. {
  73. var websocket = new WebSocketModule();
  74. websocket.setWebSocketAction(new WebSocketAction(websocket));
  75. websocket.start();
  76. var clientReq = new HttpClientRequest();
  77. clientReq.setUrl("ws://127.0.0.1:8000/wsb.cb"); //http替换为ws,https替换为wss
  78. var myReq = new HttpClientRequest();
  79. clientReq.addCookie(new Cookie("name","xiaoming"));
  80. websocket.connect(clientReq); //交给websocket模块连接
  81. clientReq = new HttpClientRequest();
  82. clientReq.setUrl("ws://127.0.0.1:8000/wsb.cb");
  83. var myReq = new HttpClientRequest();
  84. clientReq.addCookie(new Cookie("name","xiaohong"));
  85. websocket.connect(clientReq);
  86. Sleep(3000);//3秒后退出
  87. }

客户端结果如下:

  1. xiaoming onupgrade success!
  2. xiaohong onupgrade success!
  3. xiaoming connect suc!
  4. xiaohong connect suc!
  5. hi xiaoming,I recv your text msg.
  6. hi xiaohong,I recv your binary msg.

服务端结果如下:

  1. onupgrade xiaoming
  2. xiaoming onaccept
  3. onrecv xiaoming text:this is xiaoming,I send a text msg.
  4. onupgrade xiaohong
  5. xiaohong onaccept
  6. onrecv xiaohong binary datalen:38 this is xiaohong,I send a binary msg.
  7. xiaohong Onclose!
  8. xiaoming Onclose!

这里只是为了同时说明客户端与服务器的用法,在实际的开发过程中,websocket服务器往往是直接跟网页通信的,在下载包的sample/websocket/websocket.cb 是一个网页聊天室的例子,更切合实际开发。只是这个例子前端是一个html,需要一些网页开发的知识, 这里就不做讲解了。要将websocket用到网页的实际开发中,还是要研读一下sample中的例子。