mirror of
https://github.com/lunarmodules/luasocket.git
synced 2024-12-26 04:28:20 +01:00
Changed send function.
This commit is contained in:
parent
e4e2223cff
commit
c8b402e004
4
FIX
4
FIX
@ -1,3 +1,7 @@
|
||||
UDP has a reasonable maximum datagram size
|
||||
receive accepts the prefix optional argument
|
||||
send doesn't support multiple arguments anymore
|
||||
send allows the selection of the substring to be sent
|
||||
fix bug that caused select return tables not to be associative on windows
|
||||
compiles with g++
|
||||
new sample unix domain support
|
||||
|
3
TODO
3
TODO
@ -1,4 +1,7 @@
|
||||
|
||||
fix manual for send and receive
|
||||
add thanks to mike
|
||||
|
||||
change sock:send to use indices just like string.sub?
|
||||
use mike's "don't set to blocking before closing unless needed" patch?
|
||||
take a look at DB's smtp patch
|
||||
|
@ -113,7 +113,7 @@ The core LuaSocket is almost entirely implemented in C. It is
|
||||
usually available as a dynamic library which the interpreter can load
|
||||
with the help of a loader module written in Lua.
|
||||
Beginning with version 2.0 and following the Lua 5.0 trend, all LuaSocket
|
||||
functionality is defined inside tables (or rather a namespaces). No global
|
||||
functionality is defined inside tables (or rather namespaces). No global
|
||||
variables are ever created.
|
||||
Namespaces are obtained with the <tt>require</tt> Lua function, which loads
|
||||
and initializes any required library and returns the namespace.
|
||||
|
35
doc/tcp.html
35
doc/tcp.html
@ -260,7 +260,7 @@ method returns <b><tt>nil</tt></b> followed by an error message.
|
||||
<!-- receive ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||
|
||||
<p class=name id=receive>
|
||||
client:<b>receive(</b>[pattern]<b>)</b>
|
||||
client:<b>receive(</b>[pattern [, prefix]]<b>)</b>
|
||||
</p>
|
||||
|
||||
<p class=description>
|
||||
@ -283,6 +283,11 @@ the returned line. This is the default pattern;
|
||||
of bytes from the socket.
|
||||
</ul>
|
||||
|
||||
<p class=parameters>
|
||||
<tt>Prefix</tt> is an optional string to be concatenated to the beginning
|
||||
of any received data before return.
|
||||
</p>
|
||||
|
||||
<p class=return>
|
||||
If successful, the method returns the received pattern. In case of error,
|
||||
the method returns <tt><b>nil</b></tt> followed by an error message which
|
||||
@ -305,18 +310,18 @@ too.
|
||||
<!-- send +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||
|
||||
<p class=name id=send>
|
||||
client:<b>send(</b>string<sub>1</sub> [,
|
||||
string<sub>2</sub>, ... string<sub>N</sub>]<b>)</b>
|
||||
client:<b>send(</b>data [, i [, j]]<b>)</b>
|
||||
</p>
|
||||
|
||||
<p class=description>
|
||||
Sends data through client object.
|
||||
Sends <tt>data</tt> through client object.
|
||||
</p>
|
||||
|
||||
<p class=parameters>
|
||||
All parameters should be strings. For small strings, it is always better to
|
||||
concatenate them in Lua (with the '<tt>..</tt>' operator) and pass the
|
||||
result to LuaSocket instead of passing several independent strings.
|
||||
<tt>Data</tt> is the string to be sent. The optional arguments
|
||||
<tt>i</tt> and <tt>j</tt> work exactly like the standard
|
||||
<tt>string.sub</tt> Lua function to allow the selection of a
|
||||
substring to be sent.
|
||||
</p>
|
||||
|
||||
<p class=return>
|
||||
@ -341,6 +346,22 @@ Alas, it wasn't returning <tt><b>nil</b></tt> in case of
|
||||
error. So it was changed again in beta.
|
||||
</p>
|
||||
|
||||
<p class=note>
|
||||
<b>Also important</b>:
|
||||
In order to better support non-blocking I/O and to discourage
|
||||
bad practice, the <tt>send</tt> method now only sends one string
|
||||
per call. The other optional arguments allow the user to select
|
||||
a substring to be sent in a much more efficient way than
|
||||
using <tt>string.sub</tt>.
|
||||
</p>
|
||||
|
||||
<p class=note>
|
||||
Note: Output is <em>not</em> buffered. For small strings,
|
||||
it is always better to concatenate them in Lua
|
||||
(with the '<tt>..</tt>' operator) and send the result in one call
|
||||
instead of calling the method several times.
|
||||
</p>
|
||||
|
||||
<!-- setoption ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||
|
||||
<p class=name id=setoption>
|
||||
|
23
src/buffer.c
23
src/buffer.c
@ -64,23 +64,24 @@ int buf_meth_getstats(lua_State *L, p_buf buf) {
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int buf_meth_send(lua_State *L, p_buf buf) {
|
||||
int top = lua_gettop(L);
|
||||
size_t total = 0;
|
||||
int arg, err = IO_DONE;
|
||||
p_tm tm = tm_markstart(buf->tm);
|
||||
for (arg = 2; arg <= top; arg++) { /* first arg is socket object */
|
||||
size_t sent, count;
|
||||
const char *data = luaL_optlstring(L, arg, NULL, &count);
|
||||
if (!data || err != IO_DONE) break;
|
||||
err = sendraw(buf, data, count, &sent);
|
||||
total += sent;
|
||||
}
|
||||
int err = IO_DONE;
|
||||
size_t size, sent;
|
||||
const char *data = luaL_checklstring(L, 2, &size);
|
||||
ssize_t start = (ssize_t) luaL_optnumber(L, 3, 1);
|
||||
ssize_t end = (ssize_t) luaL_optnumber(L, 4, -1);
|
||||
if (start < 0) start = size+start+1;
|
||||
if (end < 0) end = size+end+1;
|
||||
if (start < 1) start = 1;
|
||||
if (end > size) end = size;
|
||||
if (start <= end) err = sendraw(buf, data+start-1, end-start+1, &sent);
|
||||
/* check if there was an error */
|
||||
if (err != IO_DONE) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, buf->io->error(buf->io->ctx, err));
|
||||
lua_pushnumber(L, total);
|
||||
lua_pushnumber(L, sent);
|
||||
} else {
|
||||
lua_pushnumber(L, total);
|
||||
lua_pushnumber(L, sent);
|
||||
lua_pushnil(L);
|
||||
lua_pushnil(L);
|
||||
}
|
||||
|
@ -373,12 +373,10 @@ static const char *wstrerror(int err) {
|
||||
case WSANOTINITIALISED:
|
||||
return "Successful WSAStartup not yet performed";
|
||||
case WSAEDISCON: return "Graceful shutdown in progress";
|
||||
case WSATYPE_NOT_FOUND: return "Class type not found";
|
||||
case WSAHOST_NOT_FOUND: return "Host not found";
|
||||
case WSATRY_AGAIN: return "Nonauthoritative host not found";
|
||||
case WSANO_RECOVERY: return "Nonrecoverable name lookup error";
|
||||
case WSANO_DATA: return "Valid name, no data record of requested type";
|
||||
case WSASYSCALLFAILURE: return "System call failure";
|
||||
default: return "Unknown error";
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ function remote(...)
|
||||
s = string.gsub(s, "\n", ";")
|
||||
s = string.gsub(s, "%s+", " ")
|
||||
s = string.gsub(s, "^%s*", "")
|
||||
control:send(s, "\n")
|
||||
control:send(s .. "\n")
|
||||
control:receive()
|
||||
end
|
||||
|
||||
@ -120,7 +120,7 @@ function test_mixed(len)
|
||||
local bp1, bp2, bp3, bp4
|
||||
remote (string.format("str = data:receive(%d)",
|
||||
string.len(p1)+string.len(p2)+string.len(p3)+string.len(p4)))
|
||||
sent, err = data:send(p1, p2, p3, p4)
|
||||
sent, err = data:send(p1..p2..p3..p4)
|
||||
if err then fail(err) end
|
||||
remote "data:send(str); data:close()"
|
||||
bp1, err = data:receive()
|
||||
@ -144,9 +144,9 @@ function test_asciiline(len)
|
||||
str10 = string.rep("aZb.c#dAe?", math.floor(len/10))
|
||||
str = str .. str10
|
||||
remote "str = data:receive()"
|
||||
sent, err = data:send(str, "\n")
|
||||
sent, err = data:send(str.."\n")
|
||||
if err then fail(err) end
|
||||
remote "data:send(str, '\\n')"
|
||||
remote "data:send(str ..'\\n')"
|
||||
back, err = data:receive()
|
||||
if err then fail(err) end
|
||||
if back == str then pass("lines match")
|
||||
@ -162,9 +162,9 @@ function test_rawline(len)
|
||||
math.floor(len/10))
|
||||
str = str .. str10
|
||||
remote "str = data:receive()"
|
||||
sent, err = data:send(str, "\n")
|
||||
sent, err = data:send(str.."\n")
|
||||
if err then fail(err) end
|
||||
remote "data:send(str, '\\n')"
|
||||
remote "data:send(str..'\\n')"
|
||||
back, err = data:receive()
|
||||
if err then fail(err) end
|
||||
if back == str then pass("lines match")
|
||||
@ -457,7 +457,62 @@ function getstats_test()
|
||||
print("ok")
|
||||
end
|
||||
|
||||
|
||||
------------------------------------------------------------------------
|
||||
function test_nonblocking(size)
|
||||
reconnect()
|
||||
remote(string.format([[
|
||||
data:send(string.rep("a", %d))
|
||||
socket.sleep(0.5)
|
||||
data:send(string.rep("b", %d))
|
||||
]], size, size))
|
||||
local err = "timeout"
|
||||
local part = ""
|
||||
local str
|
||||
data:settimeout(0)
|
||||
while 1 do
|
||||
str, err, part = data:receive(2*size - string.len(part), part)
|
||||
if err ~= "timeout" then break end
|
||||
end
|
||||
assert(str == (string.rep("a", size) .. string.rep("b", size)))
|
||||
reconnect()
|
||||
remote(string.format([[
|
||||
str = data:receive(%d)
|
||||
socket.sleep(0.5)
|
||||
str = data:receive(%d, str)
|
||||
str = data:receive("*l", str)
|
||||
data:send(str)
|
||||
data:send("\n")
|
||||
]], size, size))
|
||||
data:settimeout(0)
|
||||
local sofar = 1
|
||||
while 1 do
|
||||
_, err, part = data:send(str, sofar)
|
||||
if err ~= "timeout" then break end
|
||||
sofar = sofar + part
|
||||
end
|
||||
data:send("\n")
|
||||
data:settimeout(-1)
|
||||
local back = data:receive()
|
||||
assert(back == str)
|
||||
print("ok")
|
||||
end
|
||||
|
||||
|
||||
------------------------------------------------------------------------
|
||||
test("non-blocking transfer")
|
||||
test_nonblocking(1)
|
||||
test_nonblocking(17)
|
||||
test_nonblocking(200)
|
||||
test_nonblocking(4091)
|
||||
test_nonblocking(80199)
|
||||
test_nonblocking(8000000)
|
||||
test_nonblocking(80199)
|
||||
test_nonblocking(4091)
|
||||
test_nonblocking(200)
|
||||
test_nonblocking(17)
|
||||
test_nonblocking(1)
|
||||
|
||||
test("method registration")
|
||||
test_methods(socket.tcp(), {
|
||||
"accept",
|
||||
@ -548,7 +603,6 @@ test_mixed(1)
|
||||
|
||||
|
||||
test("binary line")
|
||||
reconnect()
|
||||
test_rawline(1)
|
||||
test_rawline(17)
|
||||
test_rawline(200)
|
||||
@ -562,24 +616,6 @@ test_rawline(17)
|
||||
test_rawline(1)
|
||||
|
||||
test("raw transfer")
|
||||
reconnect()
|
||||
test_raw(1)
|
||||
test_raw(17)
|
||||
test_raw(200)
|
||||
test_raw(4091)
|
||||
test_raw(80199)
|
||||
test_raw(8000000)
|
||||
test_raw(80199)
|
||||
test_raw(4091)
|
||||
test_raw(200)
|
||||
test_raw(17)
|
||||
test_raw(1)
|
||||
|
||||
test("non-blocking transfer")
|
||||
reconnect()
|
||||
-- the value is not important, we only want
|
||||
-- to test non-blocking I/O anyways
|
||||
data:settimeout(200)
|
||||
test_raw(1)
|
||||
test_raw(17)
|
||||
test_raw(200)
|
||||
|
@ -1,29 +1,14 @@
|
||||
socket = require"socket"
|
||||
|
||||
host = host or "localhost"
|
||||
port = port or "8080"
|
||||
|
||||
server, error = socket.bind(host, port)
|
||||
if not server then print("server: " .. tostring(error)) os.exit() end
|
||||
ack = "\n"
|
||||
socket = require("socket");
|
||||
host = host or "localhost";
|
||||
port = port or "8080";
|
||||
server = assert(socket.bind(host, port));
|
||||
ack = "\n";
|
||||
while 1 do
|
||||
print("server: waiting for client connection...");
|
||||
control, error = server:accept()
|
||||
assert(control, error)
|
||||
-- control:setoption("nodelay", true)
|
||||
control = assert(server:accept());
|
||||
while 1 do
|
||||
command, error = control:receive()
|
||||
if error then
|
||||
control:close()
|
||||
print("server: closing connection...")
|
||||
break
|
||||
end
|
||||
sent, error = control:send(ack)
|
||||
if error then
|
||||
control:close()
|
||||
print("server: closing connection...")
|
||||
break
|
||||
end
|
||||
(loadstring(command))()
|
||||
command = assert(control:receive());
|
||||
assert(control:send(ack));
|
||||
(loadstring(command))();
|
||||
end
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user