lua開發筆記

    由於最近的項目須要,學習了lua編程,並使用lua進行網絡相關的開發,在此記錄一下用到的相關的知識。
html

    在整個項目中,我只是負責其中的固件升級模塊的開發,數據格式是自定義的,並無採用Json或者是XML,主要是由於傳輸的字段比較少,並且不但願引入太多的第三方庫。
node

1、LuaSocket編程

    項目中,採用的是tcp通訊,這裏僅介紹tcp相關的知識。
網絡

    1.首先須要加載socket模塊:app

local socket = require('socket')

    若是要查看LuaSocket的版本:socket

print('LuaSocket ver: ', socket._VERSION)

    2. tcp經常使用方法:
tcp

    關於如下方法的說明,我以爲官方文檔已經說得很清楚了,在此就直接引用官方說明:函數

    1)socket.bind(address, port [, backlog])學習

    建立一個tcp server object bind to (address, port), backlog是用於listen函數的。熟悉Linux下的socket編程,會以爲這些都很熟悉的。此函數返回一個tcp server object,若是失敗返回nil。
ui

    2)server:accept()

    Waits for a remote connection on the server object and returns a client object representing that connection.

    3)client:getsockname() : 獲取socket的ip與port

    4)server:getpeername() : 獲取對端的ip與port

    5)client:receive([pattern [, prefix]])

    接收數據,pattern與lua file I/O format相似,取值有:

    ’*all‘, ’*a' : reads from the socket until the connection is closed. No end-of-line translation is performed;

    '*line', '*l' : reads a line of text from the socket. The line is terminated by a LF character (ASCII 10), optionally preceded by a CR character (ASCII 13). The CR and LF characters are not included in the returned line. In fact, all CR characters are ignored by the pattern. This is the default pattern;

    number : causes the method to read a specified number of bytes from the socket.

    If successful, the method returns the received pattern.

    In case of error, the method returns nil followed by an error message which can be the string 'closed' in case the connection was closed before the transmission was completed or the string 'timeout' in case there was a timeout during the operation. Also, after the error message, the function returns the partial result of the transmission. 

    6) client:send(data [, i [, j]])       

    Sends data through client object.

    Data is the string to be sent. The optional arguments i and j work exactly like the standard string.sub Lua function to allow the selection of a substring to be sent.

    If successful, the method returns the index of the last byte within [i, j] that has been sent.

    In case of error, the method returns nil, followed by an error message,followed by the index of the last byte within [i, j] that has been sent. 

    7) client:close() Closes a TCP object.

   8)master:settimeout(value [, mode]

    Changes the timeout values for the object. By default, all I/O operations are blocking. 

    9) server:setoption(option [, value])

    Sets options for the TCP object. Options are only needed by low-level or time-critical applications.

    如咱們經常使用的:'keepalive', 'reuseaddr', 'tcp-nodelay'

    11) master:connect(address, port) : 用於戶客戶端發起鏈接請求

    下面的代碼分別展現了tcp服務端與客戶端的大體結構:

-- echo server
local socket = require('socket')

local serv = socket.bind('*', 8000) -- bind to any ip and 8000 port.
if not serv then
	print('bind error')
	os.exit(-1)
end

while true do
	print('begin accept')
	local client = serv:accept()
	if not client then
		print('accept failed')
		os.exit(-1)
	end

	local peer_ip, peer_port = client:getpeername()
	print(string.format('handle %s:%d request begin', peer_ip, peer_port))
	while true do
		local data, err = client:receive('*line') -- read one line data
		if not err then
		    print('data: ', data)
		    client:send(data) -- send data back to client
		else
		    print('err: ', err)
		    break
		end
	end
	client:close()
end

-- echo client

local socket = require('socket')

local client = socket.connect('localhost', 8000) -- connect to localhost:8000
if not client then
	print('connect failed')
	os.exit(-1)
end

while true do
    local data = io.read('*line')
    if not data then
        print('EOF')
        break
    end
    
    client:send(data)
    local resp, err, partial = client:receive()
    if not err then
        print('receive: ', resp)
    else
        print('err: ', err)
        break
    end
end
client:close()


2、Lua bit operation module

    lua語言自身並無提供位運算,要進行位運算,須要引入第三方module.

local bit = require('bit')

    y = bit.band(x1 [,x2...]) : 按位與

 y = bit.bor(x1 [,x2...]) : 按位或

 y = bit.bxor(x1 [,x2...]) : 按位異或

 y = bit.bnot(x) : 按位取反

 y = bit.lshift(x, n) : 邏輯左移

 y = bit.rshift(x, n) : 邏輯右移

 y = bit.arshift(x, n) : 算術右移

    由於我在項目中須要傳遞整數,須要把整數的低位在前,高位在後進行傳輸,因此須要用到移位運算。

3、 string模塊使用到的一些方法

        由於項目中的數據格式採用的是自定義的,爲了解決tcp的粘包問題,因此會存在一個固定大小的頭。好比咱們的頭是:

uin8_t head[4] ;
head[0] = 0xA5; // head frame
head[1] = 0x1l; // cmd_id
uint16_t len = 0x0010;
head[2] = len & 0xff; // low byte of len
head[3] = len >> 8; // hight byte of len

    那麼在Lua中,咱們要怎麼才能作到把上述的4個字節頭髮送出去呢?能夠用以下的方法:string.char()

local len = 0x0010
local t = {0xA5, 0x1, bit.band(len, 0xff), bit.rshift(len, 8)}
local data = string.char(unpack(t))
client:send(data)

    那麼接收方,在收取到數據頭時,須要怎麼去解析呢? string.byte()

local req , err = client:receive(4)
if not err then
    local req_t = {string.byte(req, 1, -1)}
    local frame = req_t[1]
    local cmd_id = req_t[2]
    local len = req_t[3] + bit.lshift(req_t[4], 8)
    print(string.format('frame:%02x, cmd_id:%02x, len:%d', frame, cmd_id, len))
else
    print('err: ', err)
    client:close()
end


PS : 關於Lua編程的學習,能夠參考《lua程序設計》這本書,還有一個博客lua step by step,內容也是根據此書寫的,寫的很是的好,http://www.cnblogs.com/stephen-liu74/archive/2012/07/30/2487201.html

    今天先記錄到此,後續若有須要再補充。

相關文章
相關標籤/搜索