mirror of
https://github.com/cloudwu/skynet.git
synced 2026-07-22 02:53:09 +00:00
simplify clientsocket lib
This commit is contained in:
@@ -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)
|
||||
-----------
|
||||
|
||||
@@ -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 = {}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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<sz;i++) {
|
||||
if (buffer[i] == '\n') {
|
||||
++n;
|
||||
lua_pushlstring(L, (const char *)buffer, i);
|
||||
lua_rawseti(L, 3, n);
|
||||
buffer += i + 1;
|
||||
sz -= i + 1;
|
||||
return unpack_line(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;
|
||||
}
|
||||
|
||||
static int
|
||||
lreadline(lua_State *L) {
|
||||
struct socket_buffer sb;
|
||||
char tmp[CACHE_SIZE];
|
||||
int ret = recv_socket(L, tmp, &sb);
|
||||
if (ret < 0) {
|
||||
return unpack_line(L, sb.buffer, sb.sz, 0);
|
||||
} else {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
lusleep(lua_State *L) {
|
||||
int n = luaL_checknumber(L, 1);
|
||||
@@ -295,18 +186,6 @@ lreadstdin(lua_State *L) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
lwriteline(lua_State *L) {
|
||||
size_t sz = 0;
|
||||
int fd = luaL_checkinteger(L,1);
|
||||
const char * msg = luaL_checklstring(L, 2, &sz);
|
||||
block_send(L, fd, msg, sz);
|
||||
char nl[1] = { '\n' };
|
||||
block_send(L, fd, nl, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
luaopen_clientsocket(lua_State *L) {
|
||||
luaL_checkversion(L);
|
||||
@@ -316,8 +195,6 @@ luaopen_clientsocket(lua_State *L) {
|
||||
{ "send", lsend },
|
||||
{ "close", lclose },
|
||||
{ "usleep", lusleep },
|
||||
{ "readline", lreadline },
|
||||
{ "writeline", lwriteline },
|
||||
{ NULL, NULL },
|
||||
};
|
||||
luaL_newlib(L, l);
|
||||
|
||||
@@ -32,8 +32,18 @@ Success:
|
||||
200 base64(subid)
|
||||
]]
|
||||
|
||||
local socket_error = {}
|
||||
local function assert_socket(v, fd)
|
||||
if v then
|
||||
return v
|
||||
else
|
||||
skynet.error(string.format("auth failed: socket (fd = %d) closed", fd))
|
||||
error(socket_error)
|
||||
end
|
||||
end
|
||||
|
||||
local function write(fd, text)
|
||||
assert(socket.write(fd, text), "socket error")
|
||||
assert_socket(socket.write(fd, text), fd)
|
||||
end
|
||||
|
||||
local function launch_slave(auth_handler)
|
||||
@@ -48,7 +58,7 @@ local function launch_slave(auth_handler)
|
||||
local challenge = crypt.randomkey()
|
||||
write(fd, crypt.base64encode(challenge).."\n")
|
||||
|
||||
local handshake = assert(socket.readline(fd), "socket closed")
|
||||
local handshake = assert_socket(socket.readline(fd), fd)
|
||||
local clientkey = crypt.base64decode(handshake)
|
||||
if #clientkey ~= 8 then
|
||||
error "Invalid client key"
|
||||
@@ -58,7 +68,7 @@ local function launch_slave(auth_handler)
|
||||
|
||||
local secret = crypt.dhsecret(clientkey, serverkey)
|
||||
|
||||
local response = assert(socket.readline(fd), "socket closed")
|
||||
local response = assert_socket(socket.readline(fd), fd)
|
||||
local hmac = crypt.hmac64(challenge, secret)
|
||||
|
||||
if hmac ~= crypt.base64decode(response) then
|
||||
@@ -66,7 +76,7 @@ local function launch_slave(auth_handler)
|
||||
error "challenge failed"
|
||||
end
|
||||
|
||||
local etoken = assert(socket.readline(fd), "socket closed")
|
||||
local etoken = assert_socket(socket.readline(fd),fd)
|
||||
|
||||
local token = crypt.desdecode(secret, crypt.base64decode(etoken))
|
||||
|
||||
@@ -76,8 +86,16 @@ local function launch_slave(auth_handler)
|
||||
return ok, server, uid, secret
|
||||
end
|
||||
|
||||
local function ret_pack(ok, err, ...)
|
||||
if ok then
|
||||
skynet.ret(skynet.pack(err, ...))
|
||||
elseif err ~= socket_error then
|
||||
error(err)
|
||||
end
|
||||
end
|
||||
|
||||
skynet.dispatch("lua", function(_,_,...)
|
||||
skynet.ret(skynet.pack(auth(...)))
|
||||
ret_pack(pcall(auth, ...))
|
||||
end)
|
||||
end
|
||||
|
||||
@@ -146,7 +164,9 @@ local function launch_master(conf)
|
||||
end
|
||||
local ok, err = pcall(accept, conf, s, fd, addr)
|
||||
if not ok then
|
||||
skynet.error(string.format("invalid client (fd = %d) error = %s", fd, err))
|
||||
if err ~= socket_error then
|
||||
skynet.error(string.format("invalid client (fd = %d) error = %s", fd, err))
|
||||
end
|
||||
end
|
||||
socket.close(fd)
|
||||
end)
|
||||
|
||||
Reference in New Issue
Block a user