reconnect

This commit is contained in:
云风
2012-08-15 11:42:32 +08:00
parent ed7e0da860
commit e7539a07b6
5 changed files with 99 additions and 63 deletions

View File

@@ -68,7 +68,7 @@ _read_queue(struct connection_pool * pool, int timeout) {
void * void *
connection_poll(struct connection_pool * pool, int timeout) { connection_poll(struct connection_pool * pool, int timeout) {
if (pool->queue_head >= pool->queue_len) { if (pool->queue_head >= pool->queue_len) {
if (_read_queue(pool, timeout) == -1) { if (_read_queue(pool, timeout) <= 0) {
return NULL; return NULL;
} }
} }

View File

@@ -10,6 +10,7 @@
#include <arpa/inet.h> #include <arpa/inet.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <errno.h> #include <errno.h>
#include <unistd.h>
#include <lua.h> #include <lua.h>
#include <lauxlib.h> #include <lauxlib.h>
@@ -36,6 +37,13 @@ _open(lua_State *L) {
return 1; return 1;
} }
static int
_close(lua_State *L) {
int fd = luaL_checkinteger(L,1);
close(fd);
return 0;
}
static int static int
_write(lua_State *L) { _write(lua_State *L) {
int fd = luaL_checkinteger(L,1); int fd = luaL_checkinteger(L,1);
@@ -101,21 +109,36 @@ _push(lua_State *L) {
buf = lua_touserdata(L,2); buf = lua_touserdata(L,2);
size = luaL_checkinteger(L,3); size = luaL_checkinteger(L,3);
} }
buffer->read = 0; int old_size = buffer->size - buffer->read;
if (size + buffer->size > buffer->cap) { if (size + old_size > buffer->cap) {
if (buffer->cap == 0) { if (buffer->cap == 0) {
lua_rawgetp(L, LUA_REGISTRYINDEX, _delete); lua_rawgetp(L, LUA_REGISTRYINDEX, _delete);
lua_setmetatable(L, 1); lua_setmetatable(L, 1);
} }
buffer->buffer = realloc(buffer->buffer, buffer->size + size); if (buffer->read == 0) {
buffer->buffer = realloc(buffer->buffer, size+old_size);
memcpy(buffer->buffer + old_size , buf , size);
buffer->size += size;
} else {
char * new_buffer = malloc(size + old_size);
memcpy(new_buffer, buffer->buffer + buffer->read, old_size);
memcpy(new_buffer + old_size , buf, size);
free(buffer->buffer);
buffer->buffer = new_buffer;
buffer->read = 0;
buffer->size = old_size + size;
}
} else if (buffer->size + size > buffer->cap) {
memmove(buffer->buffer, buffer->buffer + buffer->read, old_size);
memcpy(buffer->buffer + old_size, buf, size);
buffer->read = 0;
buffer->size = old_size + size;
} else {
memcpy(buffer->buffer + buffer->size, buf, size); memcpy(buffer->buffer + buffer->size, buf, size);
buffer->size += size; buffer->size += size;
buffer->cap = buffer->size;
return 0;
} }
memcpy(buffer->buffer+buffer->size, buf, size);
buffer->size += size;
return 0; return 0;
} }
@@ -150,29 +173,16 @@ _readline(lua_State *L) {
return 0; return 0;
} }
static int
_yield(lua_State *L) {
luaL_checktype(L,1,LUA_TUSERDATA);
struct buffer * buffer = lua_touserdata(L,1);
if (buffer->read) {
int size = buffer->size - buffer->read;
memmove(buffer->buffer, buffer->buffer + buffer->read, size);
buffer->size -= buffer->read;
buffer->read = 0;
}
return 0;
}
int int
luaopen_socket_c(lua_State *L) { luaopen_socket_c(lua_State *L) {
luaL_Reg l[] = { luaL_Reg l[] = {
{ "open", _open }, { "open", _open },
{ "close", _close },
{ "write", _write }, { "write", _write },
{ "new", _new }, { "new", _new },
{ "push", _push }, { "push", _push },
{ "read", _read }, { "read", _read },
{ "readline", _readline }, { "readline", _readline },
{ "yield", _yield },
{ NULL, NULL }, { NULL, NULL },
}; };
luaL_checkversion(L); luaL_checkversion(L);

View File

@@ -5,6 +5,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <unistd.h>
#include <assert.h> #include <assert.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@@ -114,6 +115,7 @@ _poll(struct connection_server * server) {
continue; continue;
} }
if (size == 0) { if (size == 0) {
connection_del(server->pool, c->fd);
free(buffer); free(buffer);
skynet_send(server->ctx, NULL, c->addr, 0x7fffffff, NULL, 0, DONTCOPY); skynet_send(server->ctx, NULL, c->addr, 0x7fffffff, NULL, 0, DONTCOPY);
} else { } else {

View File

@@ -9,14 +9,15 @@ function socket.connect(addr)
local ip, port = string.match(addr,"([^:]+):(.+)") local ip, port = string.match(addr,"([^:]+):(.+)")
port = tonumber(port) port = tonumber(port)
fd = c.open(ip,port) fd = c.open(ip,port)
if fd == nil then
return true
end
skynet.send(".connection","ADD "..fd.." "..skynet.self()) skynet.send(".connection","ADD "..fd.." "..skynet.self())
object = c.new() object = c.new()
end end
function socket.push(msg,sz) function socket.push(msg,sz)
if msg == nil then if msg then
socket.close()
else
c.push(object, msg, sz) c.push(object, msg, sz)
end end
end end
@@ -33,13 +34,12 @@ function socket.write(...)
c.write(fd, ...) c.write(fd, ...)
end end
function socket.yield()
c.yield(object)
end
function socket.close() function socket.close()
skynet.send(".connection","DEL "..fd) if fd then
fd = nil c.close(fd)
skynet.send(".connection","DEL "..fd)
fd = nil
end
end end
return socket return socket

View File

@@ -24,13 +24,6 @@ local function select_db(id)
assert(result and ok == "OK") assert(result and ok == "OK")
end end
local function init()
socket.connect(redis_server)
if redis_db then
select_db(redis_db)
end
end
local request_queue = { head = 1, tail = 1 } local request_queue = { head = 1, tail = 1 }
local function push_request_queue(reply) local function push_request_queue(reply)
@@ -51,6 +44,26 @@ local function response(...)
skynet.send(reply[2],reply[1],skynet.pack(...)) skynet.send(reply[2],reply[1],skynet.pack(...))
end end
local function readline(sep)
while true do
local line = socket.readline(sep)
if line then
return line
end
coroutine.yield()
end
end
local function readbytes(bytes)
while true do
local block = socket.read(bytes)
if block then
return block
end
coroutine.yield()
end
end
local redcmd = {} local redcmd = {}
redcmd[42] = function(data) -- '*' redcmd[42] = function(data) -- '*'
@@ -61,15 +74,9 @@ redcmd[42] = function(data) -- '*'
end end
local bulk = {} local bulk = {}
for i = 1,n do for i = 1,n do
local line = socket.readline "\r\n" local line = readline "\r\n"
if line == nil then
return "BLOCK"
end
local bytes = tonumber(string.sub(line,2) + 2) local bytes = tonumber(string.sub(line,2) + 2)
local data = socket.read(bytes) local data = readbytes(bytes)
if data == nil then
return "BLOCK"
end
table.insert(bulk, string.sub(data,1,-3)) table.insert(bulk, string.sub(data,1,-3))
end end
response(true, bulk) response(true, bulk)
@@ -81,10 +88,7 @@ redcmd[36] = function(data) -- '$'
response(true,nil) response(true,nil)
return return
end end
local firstline = socket.read(bytes+2) local firstline = readbytes(bytes+2)
if firstline == nil then
return "BLOCK"
end
response(true,string.sub(firstline,1,-3)) response(true,string.sub(firstline,1,-3))
end end
@@ -101,31 +105,51 @@ redcmd[58] = function(data) -- ':'
end end
local function split_package() local function split_package()
local result = socket.readline "\r\n" while true do
if result == nil then local result = readline "\r\n"
return local firstchar = string.byte(result)
local data = string.sub(result,2)
local f = redcmd[firstchar]
assert(f)
f(data)
end end
local firstchar = string.byte(result) end
local data = string.sub(result,2)
local f = redcmd[firstchar] local function init()
assert(f) while socket.connect(redis_server) do
if f(data) then print("Connect failed : "..redis_server)
return skynet.sleep(1000)
end end
socket.yield() if redis_db then
return true select_db(redis_db)
end
end
local split_co = coroutine.create(split_package)
local function reconnect()
init()
for i = request_queue.head, request_queue.tail-1 do
local request = request_queue[i]
socket.write(request[3])
end
split_co = coroutine.create(split_package)
end end
skynet.filter( skynet.filter(
function(session, address , msg, sz) function(session, address , msg, sz)
if session == 0x7fffffff then if session == 0x7fffffff then
if msg == nil then
skynet.timeout(0, reconnect)
return
end
socket.push(msg,sz) socket.push(msg,sz)
while split_package() do end coroutine.resume(split_co)
elseif session < 0 then elseif session < 0 then
local message = { skynet.unpack(msg,sz) } local message = { skynet.unpack(msg,sz) }
local cmd = compose_message(message) local cmd = compose_message(message)
socket.write(cmd) socket.write(cmd)
push_request_queue { -session , address } push_request_queue { -session , address, cmd }
else else
return session, address, msg , sz return session, address, msg , sz
end end