Lua Web Development Quick Guide (8) - use service httpd provide Websocket

Websocket technical background

WebSocketIt is a protocol of the full duplex communication over a single TCP connection, WebSocketa communication protocol specified by the IETF in 2011 as a standard RFC 6455by RFC7936supplementary specifications.

WebSocketSo that data exchange between the client and the server easier, use WebSocketthe API only need to complete one 握手directly can create a persistent connection and two-way data transmission.

WebSocketSupported clients are not limited to 浏览器(Web application), many customers in the App end of today's application market push service has a long connection is based mostly WebSocketto interact agreement.

WebsocketSince the upgrade from the HTTP protocol, at the beginning of interaction of the protocol HTTP is required according to the normal process. Thus, Websocket can be easily established communication based on SSL encryption technology.

protocol

WebSocketSimilar to the HTTP protocol to achieve slightly different but also mentioned earlier: WebSocketthe agreement before making the need for interaction 握手, 握手协议interaction is to use HTTP协议upgraded from.

As we all know, HTTP protocol is a stateless protocol. For this based 请求->回应on the mode of connection, even in HTTP/1.1the specification achieved Keep-alivecan not avoid this problem.

Therefore, Websocketby HTTP/1.1agreement of 101the protocol negotiated to upgrade the status code, under the conditions of the protocol supported by the server upgrade will respond to the request to complete the upgrade HTTP->TCPof 协议升级.

principle

The client after TCP3 handshake after sending an HTTP upgrade connection request that includes not only the HTTP header information needed to interact, but also includes Websocketinteractive unique encrypted information.

When the server receives the client's request to upgrade the agreement, the actual situation of various types of Web service implementation, the request for which version of encrypted information, details of agreements upgrade judge. Error (invalid) information will be rejected.

After confirming the completion of both ends of the interaction, the two sides interact agreement will abandon from the original HTTP protocol instead use Websocketa unique protocol interaction. Protocol specification may refer to the RFC .

Advantage

The need to push the message, the connection remains, interactive efficiency requirements, changing the two protocols will bring a different way of interacting.

First, Websocketthe protocol header compression technique used to compress the head and contains 2-10 byte size data payload length, which significantly reduces the overhead network interaction and ensures data integrity information.

If we assume that in a stable (possible) network environment will reduce the overhead of establishing a connection, authentication, and so bring the network overhead as much as possible, while than have HTTPa more convenient way protocol packet analysis.

Secondly, because the basis Websocketof agreement in 请求->回应the bi-directional, so it will not clog the case of multiple requests appear connected. It also greatly reduces the extent of the problems delayed the normal request.

Finally, Websocketalso giving developers the ability to control more of the connection: connection timed out, heartbeat judgment under reasonable connection management plan, which can provide users with better development programs.

API

cf framework httpdlibrary built Websocketrouting, provided the above-described Websocketconnection management capabilities.

WebsocketRouting requires developers to provide a version of lua classobject to abstract the process of routing process, such abstraction can simplify the coding difficulty.

lua class

classParaphrase 'class' is an abstract description of 'Object' and used for a variety of object-oriented programming language. Lua no native classtype, but provide the basic building element method.

cf for convenience of description and built-in library package built-in objects, to establish a basic model class associated element method using the lua table. rely almost most cf the built-in library class library.

Meanwhile, in order to simplify class. Learning costs, in addition to class originally owned by 'multiple inheritance' concept which is only defined for the completion of the class-> objectinitialization work.

More about classdetails, please refer to the Wiki on classlibrary documents .

Websocket related API

Now we start learning Websocketassociated with API

WebSocket:ctor(opt)

Websocket initialize the object, Websocket client connection is established to be called before completion.

This method is called before on_open method is generally used to tell httpdhow how data packets interaction.

function websocket:ctor (opt)
  self.ws = opt.ws             -- websocket对象
  self.send_masked = false     -- 掩码(默认为false, 不建议修改或者使用)
  self.max_payload_len = 65535 -- 最大有效载荷长度(默认为65535, 不建议修改或者使用)
end  
复制代码

WebSocket:on_open()

After the completion of this connection initialization method is called. Although this method Websocket:ctor, but generally only when using a similar service for internal initialization.

function websocket:on_open()
  local cf = require "cf"
  self.timer = cf.at(0.01, function ( ... ) -- 启动一个循环定时器
    self.count = self.count + 1
    self.ws:send(tostring(self.count))
  end)
end
复制代码

WebSocket:on_message(data, type)

When this method sends text / binary data in the user is called back.

Parameter is a string type of data playload; type is a boolean variable, true for the binary type, text type otherwise.

function websocket:on_message(data, typ)
  print('on_message', self.ws, data, typ)
  self.ws:send('welcome')
  -- self.ws:close(data)
end
复制代码

WebSocket:on_error(error)

This method is called back when the protocol error with an unknown error occurred, error parameter is a string type of error message.

Normally we do not use this method.

function websocket:on_error(error)
  print('on_error:', error)
end
复制代码

WebSocket:on_close(data)

This callback method when the connection is closed. Transmits data over the data connection is closed, it is possible for the data nil.

Whatever the case, when the connection is closed all will call this method, but this method is usually the role of cleaning up the data.

function websocket:on_close(data)
  if self.timer then -- 清理定时器
    print("清理定时器")
    self.timer:stop()
    self.timer = nil
  end
end
复制代码

More API

More about Websocketthe API Wiki, please refer to the documentation .

Start practice

Establish a route

! Let us in scriptthe new two files in the directory: main.luaand ws.luathen fill in respectively the following:

-- app/script/ws.lua
local class = require "class"

local ws = class("websocket")

function ws:ctor(opt)
  self.ws = opt.ws
  self.send_masked = false
  self.max_payload_len = 65535
end

function ws:on_open()

end

function ws:on_message(data, typ)

end

function ws:on_error(error)

end

function ws:on_close(data)

end

return ws
复制代码
-- main.lua
local httpd = require "httpd"
local app = httpd:new("httpd")

app:ws('/ws', require "ws")

app:listen("", 8080)

app:run()
复制代码

We use the httpdlibrary started a Web Server, while ws.luain the classregistration object Websocketto be processed.

At the same time, we have Websocket:ctorinternal methods for routing the connection initialization Websocket some connection information. The above is the most streamlined Websocket routes.

Start writing a simple Demo

First, we ws:on_openadd a piece of code inside the method timer, the timer continued to push for incremental news to developers after the connection is established.

function ws:on_open()
  local cf = require "cf"
  local count = 1
  self.timer = cf.at(3, function(...)
    self.ws:send(tostring(count))
    count = count + 1
  end)
  print(self.ws, "客户端连接成功.")
end
复制代码

Then, we ws:on_closeway to add some code to prevent the destruction of timer memory leaks.

function ws:on_close(data)
  if self.timer then
    self.timer:stop()
    self.timer = nil
  end
  print(self.ws, "客户端关闭了连接.")
end
复制代码

Finally, the implementation of a message sent by the client once for each echo response.

function ws:on_message(data, type)
  self.ws:send(data, type)
  print(self.ws, "接受到客户端发送的消息.", data)
end
复制代码

Run cfadmin,

Let's use chrome browser click here , using the extraction code cgwrdownload Websocketclient plug-in and install it.

Then open just downloaded websocket client plug-in and its Websocket Addressinput connected to address our connection and view the push message service side.

Developers can run in cfadminto view the connection establishment message printing terminal.

[candy@MacBookPro:~/Documents/core_framework] $ ./cfadmin
[2019/06/18 21:48:36] [INFO] httpd正在监听: 0.0.0.0:8080
[2019/06/18 21:48:36] [INFO] httpd正在运行Web Server服务...
[2019/06/18 21:48:39] - ::1 - ::1 - /ws - GET - 101 - req_time: 0.000080/Sec
websocket-server: 0x7f9495e01200	客户端连接成功.
websocket-server: 0x7f9495e01200	接受到客户端发送的消息.	hello world
websocket-server: 0x7f9495e01200	客户端关闭了连接.
复制代码

The full code

-- main.lua
local httpd = require "httpd"
local app = httpd:new("httpd")

app:ws('/ws', require "ws")

app:listen("", 8080)

app:run()
复制代码
-- app/script/ws.lua
local class = require "class"

local ws = class("websocket")

function ws:ctor(opt)
  self.ws = opt.ws
  self.send_masked = false
  self.max_payload_len = 65535
end

function ws:on_open()
  local cf = require "cf"
  local count = 1
  self.timer = cf.at(3, function(...)
    self.ws:send(tostring(count))
    count = count + 1
  end)
  print(self.ws, "客户端连接成功.")
end

function ws:on_message(data, type)
  self.ws:send(data, type)
  print(self.ws, "接受到客户端发送的消息.", data)
end

function ws:on_error(error)

end

function ws:on_close(data)
  if self.timer then
    self.timer:stop()
    self.timer = nil
  end
  print(self.ws, "客户端关闭了连接.")
end

return ws
复制代码

Continue studying

The next chapter we will learn cf framework built-in asynchronous library

Reproduced in: https: //juejin.im/post/5d09ccb06fb9a07ee27b1939

Guess you like

Origin blog.csdn.net/weixin_34301307/article/details/93181010