jekeyhui99 发表于 2019-1-13 19:50:20

给skynet增加websocket模块

<p>&nbsp;最近迷上了skynet,代码质量很高,算开源游戏服务器框架中的佼佼者,不管是Python的firefly,C++/Python的kbengine,C#的scut,还是nodejs的pomelo,skynet在并发上和商业应用都有很大的优势,根据http://thislinux.com/blog/5_panic.html描述,skynet能支持单机3w在线用户,性能很是给力。</p><p><br></p><p>&nbsp; &nbsp; &nbsp; 最近做的都是一些h5小游戏,用tornado/django基本上也都绰绰有余,下个小游戏打算试试skynet,skynet没有带websocket库,于是就很happy的去造轮子去了,虽然有lua-resty-websocket这个nginx扩展库,有2个原因我不喜欢。</p><p><br></p><p>&nbsp; &nbsp; &nbsp;1.lua-resty-websocket实在太老了,现在已经是lua53的时代了</p><p><br></p><p>&nbsp; &nbsp; &nbsp;2.还是喜欢tornado websocket的基于回调的方式,当然我写的既可使用回调方式,也可使用lua-resty-websocket</p><p><br></p><p>基于直接recv的方式</p><p><br></p><p>&nbsp; &nbsp; 其实解析websocket还是比较简单的,比较复杂点的是websocket 的close操作。和握手一样,close也是需要客户端-服务器</p><p><br></p><p>端确认的。</p><p><br></p><p>&nbsp; &nbsp; 当客户端-&gt;close -&gt;服务端,服务端接收到opcode为8的close事件,服务端发送close frame,然后关闭客户端socket</p><p><br></p><p>&nbsp; &nbsp; 当服务端-&gt;close -&gt;客户端,服务器发送close frame,此时客户端得到close事件,客户端接着会主动发送close frame给服务端,服务端接收到</p><p><br></p><p>opcode为8的close事件,关闭客户端socket。</p><p><br></p><p>这里需要注意,如果用js 的话,var ws = new WebSocket('XXXX'),在onclose事件中不需要主动调用ws.close(),底层会帮你调用。</p><p>local skynet = require "skynet"</p><p>local string = require "string"</p><p>local crypt = require "crypt"</p><p>local socket = require "socket"</p><p>local httpd = require "http.httpd"</p><p>local sockethelper = require "http.sockethelper"</p><p>local urllib = require "http.url"</p><p>&nbsp;</p><p>local ws = {}</p><p>local ws_mt = { __index = ws }</p><p>&nbsp;</p><p>local function response(id, ...)</p><p>&nbsp; &nbsp; return httpd.write_response(sockethelper.writefunc(id), ...)</p><p>end</p><p>&nbsp;</p><p>&nbsp;</p><p>local function write(id, data)</p><p>&nbsp; &nbsp; socket.write(id, data)</p><p>end</p><p>&nbsp;</p><p>local function read(id, sz)</p><p>&nbsp; &nbsp; return socket.read(id, sz)</p><p>end</p><p>&nbsp;</p><p>&nbsp;</p><p>local function challenge_response(key, protocol)</p><p>&nbsp; &nbsp; local accept = crypt.base64encode(crypt.sha1(key .. "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"))</p><p>&nbsp; &nbsp; return string.format("HTTP/1.1 101 Switching Protocols\r\n" ..</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "Upgrade: websocket\r\n" ..</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "Connection: Upgrade\r\n" ..</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "Sec-WebSocket-Accept: %s\r\n" ..</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "%s\r\n", accept, protocol or "")</p><p>&nbsp; &nbsp;&nbsp;</p><p>end</p><p>&nbsp;</p><p>local function accept_connection(header, check_origin, check_origin_ok)</p><p>&nbsp; &nbsp; -- Upgrade header should be present and should be equal to WebSocket</p><p>&nbsp; &nbsp; if not header["upgrade"] or header["upgrade"]:lower() ~= "websocket" then</p><p>&nbsp; &nbsp; &nbsp; &nbsp; return 400, "Can \"Upgrade\" only to \"WebSocket\"."</p><p>&nbsp; &nbsp; end</p><p>&nbsp;</p><p>&nbsp; &nbsp; -- Connection header should be upgrade. Some proxy servers/load balancers</p><p>&nbsp; &nbsp; -- might mess with it.</p><p>&nbsp; &nbsp; if not header["connection"] or not header["connection"]:lower():find("upgrade", 1,true) then</p><p>&nbsp; &nbsp; &nbsp; &nbsp; return 400, "\"Connection\" must be \"Upgrade\"."</p><p>&nbsp; &nbsp; end</p><p>&nbsp;</p><p>&nbsp; &nbsp; -- Handle WebSocket Origin naming convention differences</p><p>&nbsp; &nbsp; -- The difference between version 8 and 13 is that in 8 the</p><p>&nbsp; &nbsp; -- client sends a "Sec-Websocket-Origin" header and in 13 it's</p><p>&nbsp; &nbsp; -- simply "Origin".</p><p>&nbsp; &nbsp; local origin = header["origin"] or header["sec-websocket-origin"]</p><p>&nbsp; &nbsp; if origin and check_origin and not check_origin_ok(origin, header["host"]) then</p><p>&nbsp; &nbsp; &nbsp; &nbsp; return 403, "Cross origin websockets not allowed"</p><p>&nbsp; &nbsp; end</p><p>&nbsp; &nbsp; if not header["sec-websocket-version"] or header["sec-websocket-version"] ~= "13" then</p><p>&nbsp; &nbsp; &nbsp; &nbsp; return 400, "HTTP/1.1 Upgrade Required\r\nSec-WebSocket-Version: 13\r\n\r\n"</p><p>&nbsp; &nbsp; end</p><p>&nbsp; &nbsp; local key = header["sec-websocket-key"]</p><p>&nbsp; &nbsp; if not key then</p><p>&nbsp; &nbsp; &nbsp; &nbsp; return 400, "\"Sec-WebSocket-Key\" must not be&nbsp; nil."</p><p>&nbsp; &nbsp; end</p><p>&nbsp; &nbsp; local protocol = header["sec-websocket-protocol"]&nbsp;</p><p>&nbsp; &nbsp; if protocol then</p><p>&nbsp; &nbsp; &nbsp; &nbsp; local i = protocol:find(",", 1, true)</p><p>&nbsp; &nbsp; &nbsp; &nbsp; protocol = "Sec-WebSocket-Protocol: " .. protocol:sub(1, i or i-1)</p><p>&nbsp; &nbsp; end</p><p>&nbsp; &nbsp; return nil, challenge_response(key, protocol)</p><p>end</p><p>local H = {}</p><p>function H.check_origin_ok(origin, host)</p><p>&nbsp; &nbsp; return urllib.parse(origin) == host</p><p>end</p><p>function H.on_open(ws)</p><p>&nbsp; &nbsp;&nbsp;</p><p>end</p><p>function H.on_message(ws, message)</p><p>&nbsp; &nbsp;</p><p>end</p><p>function H.on_close(ws, code, reason)</p><p>&nbsp; &nbsp;&nbsp;</p><p>end</p><p>function H.on_pong(ws, data)</p><p>&nbsp; &nbsp; -- Invoked when the response to a ping frame is received.</p><p>end</p><p>function ws.new(id, header, handler, conf)</p><p>&nbsp; &nbsp; local conf = conf or {}</p><p>&nbsp; &nbsp; local handler = handler or {}</p><p>&nbsp; &nbsp; setmetatable(handler, { __index = H })</p><p>&nbsp; &nbsp; local code, result = accept_connection(header, conf.check_origin, handler.check_origin_ok)</p><p>&nbsp; &nbsp; if code then</p><p>&nbsp; &nbsp; &nbsp; &nbsp; response(id, code, result)</p><p>&nbsp; &nbsp; &nbsp; &nbsp; socket.close(id)</p><p>&nbsp; &nbsp; else</p><p>&nbsp; &nbsp; &nbsp; &nbsp; write(id, result)</p><p>&nbsp; &nbsp; end</p><p>&nbsp; &nbsp; local self = {</p><p>&nbsp; &nbsp; &nbsp; &nbsp; id = id,</p><p>&nbsp; &nbsp; &nbsp; &nbsp; handler = handler,</p><p>&nbsp; &nbsp; &nbsp; &nbsp; mask_outgoing = conf.mask_outgoing,</p><p>&nbsp; &nbsp; &nbsp; &nbsp; check_origin = conf.check_origin</p><p>&nbsp; &nbsp; }</p><p>&nbsp; &nbsp; self.handler.on_open(self)</p><p>&nbsp;</p><p>&nbsp; &nbsp; return setmetatable(self, ws_mt)</p><p>end</p><p>function ws:send_frame(fin, opcode, data)</p><p>&nbsp; &nbsp; if fin then</p><p>&nbsp; &nbsp; &nbsp; &nbsp; finbit = 0x80</p><p>&nbsp; &nbsp; else</p><p>&nbsp; &nbsp; &nbsp; &nbsp; finbit = 0</p><p>&nbsp; &nbsp; end</p><p>&nbsp; &nbsp; frame = string.pack("B", finbit | opcode)</p><p>&nbsp; &nbsp; l = #data</p><p>&nbsp; &nbsp; if self.mask_outgoing then</p><p>&nbsp; &nbsp; &nbsp; &nbsp; mask_bit = 0x80</p><p>&nbsp; &nbsp; else</p><p>&nbsp; &nbsp; &nbsp; &nbsp; mask_bit = 0</p><p>&nbsp; &nbsp; end</p><p>&nbsp; &nbsp; if l &lt; 126 then</p><p>&nbsp; &nbsp; &nbsp; &nbsp; frame = frame .. string.pack("B", l | mask_bit)</p><p>&nbsp; &nbsp; elseif l &lt; 0xFFFF then</p><p>&nbsp; &nbsp; &nbsp; &nbsp; frame = frame .. string.pack("!BH", 126 | mask_bit, l)</p><p>&nbsp; &nbsp; else&nbsp;</p><p>&nbsp; &nbsp; &nbsp; &nbsp; frame = frame .. string.pack("!BL", 127 | mask_bit, l)</p><p>&nbsp; &nbsp; end</p><p>&nbsp; &nbsp; if self.mask_outgoing then</p><p>&nbsp; &nbsp; end</p><p>&nbsp; &nbsp; frame = frame .. data</p><p>&nbsp; &nbsp; write(self.id, frame)</p><p>&nbsp; &nbsp;&nbsp;</p><p>end</p><p>function ws:send_text(data)</p><p>&nbsp; &nbsp; self:send_frame(true, 0x1, data)</p><p>end</p><p>function ws:send_binary(data)</p><p>&nbsp; &nbsp; self:send_frame(true, 0x2, data)</p><p>end</p><p>function ws:send_ping(data)</p><p>&nbsp; &nbsp; self:send_frame(true, 0x9, data)</p><p>end</p><p>function ws:send_pong(data)</p><p>&nbsp; &nbsp; self:send_frame(true, 0xA, data)</p><p>end</p><p>function ws:close(code, reason)</p><p>&nbsp; &nbsp; -- 1000&nbsp; "normal closure" status code</p><p>&nbsp; &nbsp; if code == nil and reason ~= nil then</p><p>&nbsp; &nbsp; &nbsp; &nbsp; code = 1000</p><p>&nbsp; &nbsp; end</p><p>&nbsp; &nbsp; local data = ""</p><p>&nbsp; &nbsp; if code ~= nil then</p><p>&nbsp; &nbsp; &nbsp; &nbsp; data = string.pack("&gt;H", code)</p><p>&nbsp; &nbsp; end</p><p>&nbsp; &nbsp; if reason ~= nil then</p><p>&nbsp; &nbsp; &nbsp; &nbsp; data = data .. reason</p><p>&nbsp; &nbsp; end</p><p>&nbsp; &nbsp; self:send_frame(true, 0x8, data)</p><p>end</p><p>function ws:recv()</p><p>&nbsp; &nbsp; local data = ""</p><p>&nbsp; &nbsp; while true do</p><p>&nbsp; &nbsp; &nbsp; &nbsp; local success, final, message = self:recv_frame()</p><p>&nbsp; &nbsp; &nbsp; &nbsp; if not success then</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return success, message</p><p>&nbsp; &nbsp; &nbsp; &nbsp; end</p><p>&nbsp; &nbsp; &nbsp; &nbsp; if final then</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; data = data .. message</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break</p><p>&nbsp; &nbsp; &nbsp; &nbsp; else</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; data = data .. message</p><p>&nbsp; &nbsp; &nbsp; &nbsp; end</p><p>&nbsp; &nbsp; end</p><p>&nbsp; &nbsp; self.handler.on_message(self, data)</p><p>&nbsp; &nbsp; return data</p><p>end</p><p>local function websocket_mask(mask, data, length)</p><p>&nbsp; &nbsp; umasked = {}</p><p>&nbsp; &nbsp; for i=1, length do</p><p>&nbsp; &nbsp; &nbsp; &nbsp; umasked = string.char(string.byte(data, i) ~ string.byte(mask, (i-1)%4 + 1))</p><p>&nbsp; &nbsp; end</p><p>&nbsp; &nbsp; return table.concat(umasked)</p><p>end</p><p>function ws:recv_frame()</p><p>&nbsp; &nbsp; local data, err = read(self.id, 2)</p><p>&nbsp; &nbsp; if not data then</p><p>&nbsp; &nbsp; &nbsp; &nbsp; return false, nil, "Read first 2 byte error: " .. err</p><p>&nbsp; &nbsp; end</p><p>&nbsp; &nbsp; local header, payloadlen = string.unpack("BB", data)</p><p>&nbsp; &nbsp; local final_frame = header &amp; 0x80 ~= 0</p><p>&nbsp; &nbsp; local reserved_bits = header &amp; 0x70 ~= 0</p><p>&nbsp; &nbsp; local frame_opcode = header &amp; 0xf</p><p>&nbsp; &nbsp; local frame_opcode_is_control = frame_opcode &amp; 0x8 ~= 0</p><p>&nbsp; &nbsp; if reserved_bits then</p><p>&nbsp; &nbsp; &nbsp; &nbsp; -- client is using as-yet-undefined extensions</p><p>&nbsp; &nbsp; &nbsp; &nbsp; return false, nil, "Reserved_bits show using undefined extensions"</p><p>&nbsp; &nbsp; end</p><p>&nbsp; &nbsp; local mask_frame = payloadlen &amp; 0x80 ~= 0</p><p>&nbsp; &nbsp; payloadlen = payloadlen &amp; 0x7f</p><p>&nbsp; &nbsp; if frame_opcode_is_control and payloadlen &gt;= 126 then</p><p>&nbsp; &nbsp; &nbsp; &nbsp; -- control frames must have payload &lt; 126</p><p>&nbsp; &nbsp; &nbsp; &nbsp; return false, nil, "Control frame payload overload"</p><p>&nbsp; &nbsp; end</p><p>&nbsp; &nbsp; if frame_opcode_is_control and not final_frame then</p><p>&nbsp; &nbsp; &nbsp; &nbsp; return false, nil, "Control frame must not be fragmented"</p><p>&nbsp; &nbsp; end</p><p>&nbsp; &nbsp; local frame_length, frame_mask</p><p>&nbsp; &nbsp; if payloadlen &lt; 126 then</p><p>&nbsp; &nbsp; &nbsp; &nbsp; frame_length = payloadlen</p><p>&nbsp; &nbsp; elseif payloadlen == 126 then</p><p>&nbsp; &nbsp; &nbsp; &nbsp; local h_data, err = read(self.id, 2)</p><p>&nbsp; &nbsp; &nbsp; &nbsp; if not h_data then</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return false, nil, "Payloadlen 126 read true length error:" .. err</p><p>&nbsp; &nbsp; &nbsp; &nbsp; end</p><p>&nbsp; &nbsp; &nbsp; &nbsp; frame_length = string.pack("!H", h_data)</p><p>&nbsp; &nbsp; else --payloadlen == 127</p><p>&nbsp; &nbsp; &nbsp; &nbsp; local l_data, err = read(self.id, 8)</p><p>&nbsp; &nbsp; &nbsp; &nbsp; if not l_data then</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return false, nil, "Payloadlen 127 read true length error:" .. err</p><p>&nbsp; &nbsp; &nbsp; &nbsp; end</p><p>&nbsp; &nbsp; &nbsp; &nbsp; frame_length = string.pack("!L", l_data)</p><p>&nbsp; &nbsp; end</p><p>&nbsp; &nbsp; if mask_frame then</p><p>&nbsp; &nbsp; &nbsp; &nbsp; local mask, err = read(self.id, 4)</p><p>&nbsp; &nbsp; &nbsp; &nbsp; if not mask then</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return false, nil, "Masking Key read error:" .. err</p><p>&nbsp; &nbsp; &nbsp; &nbsp; end</p><p>&nbsp; &nbsp; &nbsp; &nbsp; frame_mask = mask</p><p>&nbsp; &nbsp; end</p><p>&nbsp; &nbsp; --print('final_frame:', final_frame, "frame_opcode:", frame_opcode, "mask_frame:", mask_frame, "frame_length:", frame_length)</p><p>&nbsp; &nbsp; local&nbsp; frame_data = ""</p><p>&nbsp; &nbsp; if frame_length &gt; 0 then</p><p>&nbsp; &nbsp; &nbsp; &nbsp; local fdata, err = read(self.id, frame_length)</p><p>&nbsp; &nbsp; &nbsp; &nbsp; if not fdata then</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return false, nil, "Payload data read error:" .. err</p><p>&nbsp; &nbsp; &nbsp; &nbsp; end</p><p>&nbsp; &nbsp; &nbsp; &nbsp; frame_data = fdata</p><p>&nbsp; &nbsp; end</p><p>&nbsp; &nbsp; if mask_frame and frame_length &gt; 0 then</p><p>&nbsp; &nbsp; &nbsp; &nbsp; frame_data = websocket_mask(frame_mask, frame_data, frame_length)</p><p>&nbsp; &nbsp; end</p><p>&nbsp; &nbsp; if not final_frame then</p><p>&nbsp; &nbsp; &nbsp; &nbsp; return true, false, frame_data</p><p>&nbsp; &nbsp; else</p><p>&nbsp; &nbsp; &nbsp; &nbsp; if frame_opcode&nbsp; == 0x1 then -- text</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return true, true, frame_data</p><p>&nbsp; &nbsp; &nbsp; &nbsp; elseif frame_opcode == 0x2 then -- binary</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return true, true, frame_data</p><p>&nbsp; &nbsp; &nbsp; &nbsp; elseif frame_opcode == 0x8 then -- close</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; local code, reason</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if #frame_data &gt;= 2 then</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; code = string.unpack("&gt;H", frame_data:sub(1,2))</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; end</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if #frame_data &gt; 2 then</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; reason = frame_data:sub(3)</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; end</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; self:close()</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; socket.close(self.id)</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; self.handler.on_close(self, code, reason)</p><p>&nbsp; &nbsp; &nbsp; &nbsp; elseif frame_opcode == 0x9 then --Ping</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; self:send_pong()</p><p>&nbsp; &nbsp; &nbsp; &nbsp; elseif frame_opcode == 0xA then -- Pong</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; self.handler.on_pong(self, frame_data)</p><p>&nbsp; &nbsp; &nbsp; &nbsp; end</p><p>&nbsp; &nbsp; &nbsp; &nbsp; return true, true, nil</p><p>&nbsp; &nbsp; end</p><p>end</p><p>function ws:start()</p><p>&nbsp; &nbsp; while true do</p><p>&nbsp; &nbsp; &nbsp; &nbsp; local message, err = self:recv()</p><p>&nbsp; &nbsp; &nbsp; &nbsp; if not message then</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; --print('recv eror:', message, err)</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; socket.close(self.id)</p><p>&nbsp; &nbsp; &nbsp; &nbsp; end</p><p>&nbsp; &nbsp; end</p><p>end</p><p>return ws</p><p><br></p><p>是用方法也很简单,基于回调的方式用起来真是舒服</p><p><br></p><p>local skynet = require "skynet"</p><p>local socket = require "socket"</p><p>local string = require "string"</p><p>local websocket = require "websocket"</p><p>local httpd = require "http.httpd"</p><p>local urllib = require "http.url"</p><p>local sockethelper = require "http.sockethelper"</p><p>&nbsp;</p><p>&nbsp;</p><p>local handler = {}</p><p>function handler.on_open(ws)</p><p>&nbsp; &nbsp; print(string.format("%d::open", ws.id))</p><p>end</p><p>&nbsp;</p><p>function handler.on_message(ws, message)</p><p>&nbsp; &nbsp; print(string.format("%d receive:%s", ws.id, message))</p><p>&nbsp; &nbsp; ws:send_text(message .. "from server")</p><p>end</p><p>&nbsp;</p><p>function handler.on_close(ws, code, reason)</p><p>&nbsp; &nbsp; print(string.format("%d close:%d&nbsp; %s", ws.id, code, reason))</p><p>end</p><p>&nbsp;</p><p>local function handle_socket(id)</p><p>&nbsp; &nbsp; -- limit request body size to 8192 (you can pass nil to unlimit)</p><p>&nbsp; &nbsp; local code, url, method, header, body = httpd.read_request(sockethelper.readfunc(id), 8192)</p><p>&nbsp; &nbsp; if code then</p><p>&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</p><p>&nbsp; &nbsp; &nbsp; &nbsp; if url == "/ws" then</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; local ws = websocket.new(id, header, handler)</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ws:start()</p><p>&nbsp; &nbsp; &nbsp; &nbsp; end</p><p>&nbsp; &nbsp; end</p><p>&nbsp;</p><p>&nbsp;</p><p>end</p><p>&nbsp;</p><p>skynet.start(function()</p><p>&nbsp; &nbsp; local address = "0.0.0.0:8001"</p><p>&nbsp; &nbsp; skynet.error("Listening "..address)</p><p>&nbsp; &nbsp; local id = assert(socket.listen(address))</p><p>&nbsp; &nbsp; socket.start(id , function(id, addr)</p><p>&nbsp; &nbsp; &nbsp; &nbsp;socket.start(id)</p><p>&nbsp; &nbsp; &nbsp; &nbsp;pcall(handle_socket, id)</p><p>&nbsp; &nbsp; end)</p><p>end)</p><p><br></p><p>---------------------&nbsp;</p><p>作者:yueguanghaidao&nbsp;</p><p>来源:CSDN&nbsp;</p><p>原文:https://blog.csdn.net/yueguanghaidao/article/details/45207059&nbsp;</p><p><br></p><p></p>
页: [1]
查看完整版本: 给skynet增加websocket模块