From a8b80cd73ee1c09e050a182fb69ca8f163253b4d Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Sat, 19 Jul 2014 14:22:24 +0800 Subject: [PATCH] simplify clientsocket lib --- HISTORY.md | 1 + examples/client.lua | 74 ++++++++++++------ examples/login/client.lua | 124 +++++++++++++++++++----------- examples/simpledb.lua | 6 +- lualib-src/lua-clientsocket.c | 141 +++------------------------------- lualib/snax/loginserver.lua | 32 ++++++-- 6 files changed, 171 insertions(+), 207 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index 5c52c767..a769e314 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -2,6 +2,7 @@ Dev version ----------- * skynet.exit will quit service immediately. * Add snax.gateserver, snax.loginserver, snax.msgserver +* Simplify clientsocket lib v0.4.2 (2014-7-14) ----------- diff --git a/examples/client.lua b/examples/client.lua index 278922e6..d5bace7f 100644 --- a/examples/client.lua +++ b/examples/client.lua @@ -2,30 +2,47 @@ package.cpath = "luaclib/?.so" local socket = require "clientsocket" local cjson = require "cjson" +local bit32 = require "bit32" -local fd = socket.connect("127.0.0.1", 8888) +local fd = assert(socket.connect("127.0.0.1", 8888)) -local last -local result = {} +local function send_package(fd, pack) + local size = #pack + local package = string.format("%c%c%s", + bit32.extract(size,8,8), + bit32.extract(size,0,8), + pack) -local function dispatch() - while true do - local status - status, last = socket.recv(fd, last, result) - if status == nil then - error "Server closed" - end - if not status then - break - end - for _, v in ipairs(result) do - local session,t,str = string.match(v, "(%d+)(.)(.*)") - assert(t == '-' or t == '+') - session = tonumber(session) - local result = cjson.decode(str) - print("Response:",session, result[1], result[2]) - end + socket.send(fd, package) +end + +local function unpack_package(text) + local size = #text + if size < 2 then + return nil, text end + local s = text:byte(1) * 256 + text:byte(2) + if size < s+2 then + return nil, text + end + + return text:sub(3,2+s), text:sub(3+s) +end + +local function recv_package(last) + local result + result, last = unpack_package(last) + if result then + return result, last + end + local r = socket.recv(fd) + if not r then + return nil, last + end + if r == "" then + error "Server closed" + end + return unpack_package(last .. r) end local session = 0 @@ -33,12 +50,25 @@ local session = 0 local function send_request(v) session = session + 1 local str = string.format("%d+%s",session, cjson.encode(v)) - socket.send(fd, str) + send_package(fd, str) print("Request:", session) end +local last = "" + while true do - dispatch() + while true do + local v + v, last = recv_package(last) + if not v then + break + end + local session,t,str = string.match(v, "(%d+)(.)(.*)") + assert(t == '-' or t == '+') + session = tonumber(session) + local result = cjson.decode(str) + print("Response:",session, result[1], result[2]) + end local cmd = socket.readstdin() if cmd then local args = {} diff --git a/examples/login/client.lua b/examples/login/client.lua index 0ebed6a7..dfd66267 100644 --- a/examples/login/client.lua +++ b/examples/login/client.lua @@ -2,44 +2,65 @@ package.cpath = "luaclib/?.so" local socket = require "clientsocket" local crypt = require "crypt" +local bit32 = require "bit32" -local last local fd = assert(socket.connect("127.0.0.1", 8001)) -local input = {} -local function readline() - local line = table.remove(input, 1) - if line then - return line +local function writeline(fd, text) + socket.send(fd, text .. "\n") +end + +local function unpack_line(text) + local from = text:find("\n", 1, true) + if from then + return text:sub(1, from-1), text:sub(from+1) end + return nil, text +end - while true do - local status - status, last = socket.readline(fd, last, input) - if status == nil then +local last = "" + +local function unpack_f(f) + local function try_recv(fd, last) + local result + result, last = f(last) + if result then + return result, last + end + local r = socket.recv(fd) + if not r then + return nil, last + end + if r == "" then error "Server closed" end - if not status then - socket.usleep(100) - else - local line = table.remove(input, 1) - if line then - return line + return f(last .. r) + end + + return function() + while true do + local result + result, last = try_recv(fd, last) + if result then + return result end + socket.usleep(100) end end end +local readline = unpack_f(unpack_line) + local challenge = crypt.base64decode(readline()) local clientkey = crypt.randomkey() -socket.writeline(fd, crypt.base64encode(crypt.dhexchange(clientkey))) +writeline(fd, crypt.base64encode(crypt.dhexchange(clientkey))) local secret = crypt.dhsecret(crypt.base64decode(readline()), clientkey) print("sceret is ", crypt.hexencode(secret)) local hmac = crypt.hmac64(challenge, secret) -socket.writeline(fd, crypt.base64encode(hmac)) +writeline(fd, crypt.base64encode(hmac)) local token = { server = "sample", @@ -56,7 +77,7 @@ end local etoken = crypt.desencode(secret, encode_token(token)) local b = crypt.base64encode(etoken) -socket.writeline(fd, crypt.base64encode(etoken)) +writeline(fd, crypt.base64encode(etoken)) local result = readline() print(result) @@ -71,8 +92,18 @@ print("login ok, subid=", subid) ----- connect to game server local function send_request(v, session) - local s = string.char(bit32.extract(session,24,8), bit32.extract(session,16,8), bit32.extract(session,8,8), bit32.extract(session,0,8)) - socket.send(fd , v..s) + local size = #v + 4 + local package = string.format("%c%c%s%c%c%c%c", + bit32.extract(size,8,8), + bit32.extract(size,0,8), + v, + bit32.extract(session,24,8), + bit32.extract(session,16,8), + bit32.extract(session,8,8), + bit32.extract(session,0,8) + ) + + socket.send(fd, package) return v, session end @@ -87,29 +118,29 @@ local function recv_response(v) return ok ~=0 , content, session end -local input = {} - -local function readpackage() - local line = table.remove(input, 1) - if line then - return line +local function unpack_package(text) + local size = #text + if size < 2 then + return nil, text + end + local s = text:byte(1) * 256 + text:byte(2) + if size < s+2 then + return nil, text end - while true do - local status - status, last = socket.recv(fd, last, input) - if status == nil then - error "Server closed" - end - if not status then - socket.usleep(100) - else - local line = table.remove(input, 1) - if line then - return line - end - end - end + return text:sub(3,2+s), text:sub(3+s) +end + +local readpackage = unpack_f(unpack_package) + +local function send_package(fd, pack) + local size = #pack + local package = string.format("%c%c%s", + bit32.extract(size,8,8), + bit32.extract(size,0,8), + pack) + + socket.send(fd, package) end local text = "echo" @@ -117,12 +148,13 @@ local index = 1 print("connect") local fd = assert(socket.connect("127.0.0.1", 8888)) -input = {} +last = "" local handshake = string.format("%s@%s#%s:%d", crypt.base64encode(token.user), crypt.base64encode(token.server),crypt.base64encode(subid) , index) local hmac = crypt.hmac64(crypt.hashkey(handshake), secret) -socket.send(fd, handshake .. ":" .. crypt.base64encode(hmac)) + +send_package(fd, handshake .. ":" .. crypt.base64encode(hmac)) print(readpackage()) print("===>",send_request(text,0)) @@ -136,12 +168,12 @@ index = index + 1 print("connect again") local fd = assert(socket.connect("127.0.0.1", 8888)) -input = {} +last = "" local handshake = string.format("%s@%s#%s:%d", crypt.base64encode(token.user), crypt.base64encode(token.server),crypt.base64encode(subid) , index) local hmac = crypt.hmac64(crypt.hashkey(handshake), secret) -socket.send(fd, handshake .. ":" .. crypt.base64encode(hmac)) +send_package(fd, handshake .. ":" .. crypt.base64encode(hmac)) print(readpackage()) print("===>",send_request("fake",0)) -- request again (use last session 0, so the request message is fake) diff --git a/examples/simpledb.lua b/examples/simpledb.lua index a11fd8c5..3a7649e6 100644 --- a/examples/simpledb.lua +++ b/examples/simpledb.lua @@ -16,7 +16,11 @@ end skynet.start(function() skynet.dispatch("lua", function(session, address, cmd, ...) local f = command[string.upper(cmd)] - skynet.ret(skynet.pack(f(...))) + if f then + skynet.ret(skynet.pack(f(...))) + else + error(string.format("Unknown command %s", tostring(cmd))) + end end) skynet.register "SIMPLEDB" end) diff --git a/lualib-src/lua-clientsocket.c b/lualib-src/lua-clientsocket.c index 2676c267..89bfe1f8 100644 --- a/lualib-src/lua-clientsocket.c +++ b/lualib-src/lua-clientsocket.c @@ -75,47 +75,12 @@ lsend(lua_State *L) { size_t sz = 0; int fd = luaL_checkinteger(L,1); const char * msg = luaL_checklstring(L, 2, &sz); - uint8_t tmp[sz + 2]; - if (sz >= 0x10000) { - return luaL_error(L, "package too long %d (16bit limited)", (int)sz); - } - tmp[0] = (sz >> 8) & 0xff; - tmp[1] = sz & 0xff; - memcpy(tmp+2, msg, sz); - block_send(L, fd, (const char *)tmp, (int)sz+2); + block_send(L, fd, msg, (int)sz); return 0; } - -static int -unpack(lua_State *L, uint8_t *buffer, int sz, int n) { - int size = 0; - if (sz >= 2) { - size = buffer[0] << 8 | buffer[1]; - if (size > sz - 2) { - goto _block; - } - } else { - goto _block; - } - ++n; - lua_pushlstring(L, (const char *)buffer+2, size); - lua_rawseti(L, 3, n); - buffer += size + 2; - sz -= size + 2; - return unpack(L, buffer, sz, n); -_block: - lua_pushboolean(L, n==0 ? 0:1); - if (sz == 0) { - lua_pushnil(L); - } else { - lua_pushlstring(L, (const char *)buffer, sz); - } - return 2; -} - /* intger fd string last @@ -132,100 +97,26 @@ struct socket_buffer { }; static int -recv_socket(lua_State *L, char *tmp, struct socket_buffer *result) { +lrecv(lua_State *L) { int fd = luaL_checkinteger(L,1); - size_t sz = 0; - const char * last = lua_tolstring(L,2,&sz); - luaL_checktype(L, 3, LUA_TTABLE); - char * buffer; - int r = recv(fd, tmp, CACHE_SIZE, 0); + char buffer[CACHE_SIZE]; + int r = recv(fd, buffer, CACHE_SIZE, 0); if (r == 0) { + lua_pushliteral(L, ""); // close - return 0; + return 1; } if (r < 0) { if (errno == EAGAIN || errno == EINTR) { - lua_pushboolean(L, 0); - lua_pushvalue(L, 2); - return 2; + return 0; } luaL_error(L, "socket error: %s", strerror(errno)); } - if (sz + r <= CACHE_SIZE) { - buffer = tmp; - memmove(buffer + sz, buffer, r); - memcpy(buffer, last, sz); - } else { - buffer = lua_newuserdata(L, r + sz); - memcpy(buffer, last, sz); - memcpy(buffer + sz, tmp, r); - } - - int i; - int n = lua_rawlen(L, 3); - for (i=1;i<=n;i++) { - lua_pushnil(L); - lua_rawseti(L, 3, i); - } - result->buffer = buffer; - result->sz = r + sz; - return -1; + lua_pushlstring(L, buffer, r); + return 1; } -static int -lrecv(lua_State *L) { - struct socket_buffer sb; - char tmp[CACHE_SIZE]; - int ret = recv_socket(L, tmp, &sb); - if (ret < 0) { - return unpack(L, sb.buffer, sb.sz, 0); - } else { - return ret; - } -} - -static int -unpack_line(lua_State *L, uint8_t *buffer, int sz, int n) { - if (sz == 0) - goto _block; - if (buffer[0] == '\n') { - return unpack_line(L, buffer+1, sz-1, n); - } - int i; - for (i=1;i