mirror of
https://github.com/lunarmodules/luasocket.git
synced 2024-12-26 20:38:22 +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
|
fix bug that caused select return tables not to be associative on windows
|
||||||
compiles with g++
|
compiles with g++
|
||||||
new sample unix domain support
|
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?
|
change sock:send to use indices just like string.sub?
|
||||||
use mike's "don't set to blocking before closing unless needed" patch?
|
use mike's "don't set to blocking before closing unless needed" patch?
|
||||||
take a look at DB's smtp 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
|
usually available as a dynamic library which the interpreter can load
|
||||||
with the help of a loader module written in Lua.
|
with the help of a loader module written in Lua.
|
||||||
Beginning with version 2.0 and following the Lua 5.0 trend, all LuaSocket
|
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.
|
variables are ever created.
|
||||||
Namespaces are obtained with the <tt>require</tt> Lua function, which loads
|
Namespaces are obtained with the <tt>require</tt> Lua function, which loads
|
||||||
and initializes any required library and returns the namespace.
|
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 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
<!-- receive ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
<p class=name id=receive>
|
<p class=name id=receive>
|
||||||
client:<b>receive(</b>[pattern]<b>)</b>
|
client:<b>receive(</b>[pattern [, prefix]]<b>)</b>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class=description>
|
<p class=description>
|
||||||
@ -283,6 +283,11 @@ the returned line. This is the default pattern;
|
|||||||
of bytes from the socket.
|
of bytes from the socket.
|
||||||
</ul>
|
</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>
|
<p class=return>
|
||||||
If successful, the method returns the received pattern. In case of error,
|
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
|
the method returns <tt><b>nil</b></tt> followed by an error message which
|
||||||
@ -305,18 +310,18 @@ too.
|
|||||||
<!-- send +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
<!-- send +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
<p class=name id=send>
|
<p class=name id=send>
|
||||||
client:<b>send(</b>string<sub>1</sub> [,
|
client:<b>send(</b>data [, i [, j]]<b>)</b>
|
||||||
string<sub>2</sub>, ... string<sub>N</sub>]<b>)</b>
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class=description>
|
<p class=description>
|
||||||
Sends data through client object.
|
Sends <tt>data</tt> through client object.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class=parameters>
|
<p class=parameters>
|
||||||
All parameters should be strings. For small strings, it is always better to
|
<tt>Data</tt> is the string to be sent. The optional arguments
|
||||||
concatenate them in Lua (with the '<tt>..</tt>' operator) and pass the
|
<tt>i</tt> and <tt>j</tt> work exactly like the standard
|
||||||
result to LuaSocket instead of passing several independent strings.
|
<tt>string.sub</tt> Lua function to allow the selection of a
|
||||||
|
substring to be sent.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class=return>
|
<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.
|
error. So it was changed again in beta.
|
||||||
</p>
|
</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 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
<!-- setoption ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
<p class=name id=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 buf_meth_send(lua_State *L, p_buf buf) {
|
||||||
int top = lua_gettop(L);
|
int top = lua_gettop(L);
|
||||||
size_t total = 0;
|
|
||||||
int arg, err = IO_DONE;
|
|
||||||
p_tm tm = tm_markstart(buf->tm);
|
p_tm tm = tm_markstart(buf->tm);
|
||||||
for (arg = 2; arg <= top; arg++) { /* first arg is socket object */
|
int err = IO_DONE;
|
||||||
size_t sent, count;
|
size_t size, sent;
|
||||||
const char *data = luaL_optlstring(L, arg, NULL, &count);
|
const char *data = luaL_checklstring(L, 2, &size);
|
||||||
if (!data || err != IO_DONE) break;
|
ssize_t start = (ssize_t) luaL_optnumber(L, 3, 1);
|
||||||
err = sendraw(buf, data, count, &sent);
|
ssize_t end = (ssize_t) luaL_optnumber(L, 4, -1);
|
||||||
total += sent;
|
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 */
|
/* check if there was an error */
|
||||||
if (err != IO_DONE) {
|
if (err != IO_DONE) {
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
lua_pushstring(L, buf->io->error(buf->io->ctx, err));
|
lua_pushstring(L, buf->io->error(buf->io->ctx, err));
|
||||||
lua_pushnumber(L, total);
|
lua_pushnumber(L, sent);
|
||||||
} else {
|
} else {
|
||||||
lua_pushnumber(L, total);
|
lua_pushnumber(L, sent);
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
}
|
}
|
||||||
|
@ -373,12 +373,10 @@ static const char *wstrerror(int err) {
|
|||||||
case WSANOTINITIALISED:
|
case WSANOTINITIALISED:
|
||||||
return "Successful WSAStartup not yet performed";
|
return "Successful WSAStartup not yet performed";
|
||||||
case WSAEDISCON: return "Graceful shutdown in progress";
|
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 WSAHOST_NOT_FOUND: return "Host not found";
|
||||||
case WSATRY_AGAIN: return "Nonauthoritative host not found";
|
case WSATRY_AGAIN: return "Nonauthoritative host not found";
|
||||||
case WSANO_RECOVERY: return "Nonrecoverable name lookup error";
|
case WSANO_RECOVERY: return "Nonrecoverable name lookup error";
|
||||||
case WSANO_DATA: return "Valid name, no data record of requested type";
|
case WSANO_DATA: return "Valid name, no data record of requested type";
|
||||||
case WSASYSCALLFAILURE: return "System call failure";
|
|
||||||
default: return "Unknown error";
|
default: return "Unknown error";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ function remote(...)
|
|||||||
s = string.gsub(s, "\n", ";")
|
s = string.gsub(s, "\n", ";")
|
||||||
s = string.gsub(s, "%s+", " ")
|
s = string.gsub(s, "%s+", " ")
|
||||||
s = string.gsub(s, "^%s*", "")
|
s = string.gsub(s, "^%s*", "")
|
||||||
control:send(s, "\n")
|
control:send(s .. "\n")
|
||||||
control:receive()
|
control:receive()
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -120,7 +120,7 @@ function test_mixed(len)
|
|||||||
local bp1, bp2, bp3, bp4
|
local bp1, bp2, bp3, bp4
|
||||||
remote (string.format("str = data:receive(%d)",
|
remote (string.format("str = data:receive(%d)",
|
||||||
string.len(p1)+string.len(p2)+string.len(p3)+string.len(p4)))
|
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
|
if err then fail(err) end
|
||||||
remote "data:send(str); data:close()"
|
remote "data:send(str); data:close()"
|
||||||
bp1, err = data:receive()
|
bp1, err = data:receive()
|
||||||
@ -144,9 +144,9 @@ function test_asciiline(len)
|
|||||||
str10 = string.rep("aZb.c#dAe?", math.floor(len/10))
|
str10 = string.rep("aZb.c#dAe?", math.floor(len/10))
|
||||||
str = str .. str10
|
str = str .. str10
|
||||||
remote "str = data:receive()"
|
remote "str = data:receive()"
|
||||||
sent, err = data:send(str, "\n")
|
sent, err = data:send(str.."\n")
|
||||||
if err then fail(err) end
|
if err then fail(err) end
|
||||||
remote "data:send(str, '\\n')"
|
remote "data:send(str ..'\\n')"
|
||||||
back, err = data:receive()
|
back, err = data:receive()
|
||||||
if err then fail(err) end
|
if err then fail(err) end
|
||||||
if back == str then pass("lines match")
|
if back == str then pass("lines match")
|
||||||
@ -162,9 +162,9 @@ function test_rawline(len)
|
|||||||
math.floor(len/10))
|
math.floor(len/10))
|
||||||
str = str .. str10
|
str = str .. str10
|
||||||
remote "str = data:receive()"
|
remote "str = data:receive()"
|
||||||
sent, err = data:send(str, "\n")
|
sent, err = data:send(str.."\n")
|
||||||
if err then fail(err) end
|
if err then fail(err) end
|
||||||
remote "data:send(str, '\\n')"
|
remote "data:send(str..'\\n')"
|
||||||
back, err = data:receive()
|
back, err = data:receive()
|
||||||
if err then fail(err) end
|
if err then fail(err) end
|
||||||
if back == str then pass("lines match")
|
if back == str then pass("lines match")
|
||||||
@ -457,7 +457,62 @@ function getstats_test()
|
|||||||
print("ok")
|
print("ok")
|
||||||
end
|
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("method registration")
|
||||||
test_methods(socket.tcp(), {
|
test_methods(socket.tcp(), {
|
||||||
"accept",
|
"accept",
|
||||||
@ -548,7 +603,6 @@ test_mixed(1)
|
|||||||
|
|
||||||
|
|
||||||
test("binary line")
|
test("binary line")
|
||||||
reconnect()
|
|
||||||
test_rawline(1)
|
test_rawline(1)
|
||||||
test_rawline(17)
|
test_rawline(17)
|
||||||
test_rawline(200)
|
test_rawline(200)
|
||||||
@ -562,24 +616,6 @@ test_rawline(17)
|
|||||||
test_rawline(1)
|
test_rawline(1)
|
||||||
|
|
||||||
test("raw transfer")
|
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(1)
|
||||||
test_raw(17)
|
test_raw(17)
|
||||||
test_raw(200)
|
test_raw(200)
|
||||||
|
@ -1,29 +1,14 @@
|
|||||||
socket = require"socket"
|
socket = require("socket");
|
||||||
|
host = host or "localhost";
|
||||||
host = host or "localhost"
|
port = port or "8080";
|
||||||
port = port or "8080"
|
server = assert(socket.bind(host, port));
|
||||||
|
ack = "\n";
|
||||||
server, error = socket.bind(host, port)
|
|
||||||
if not server then print("server: " .. tostring(error)) os.exit() end
|
|
||||||
ack = "\n"
|
|
||||||
while 1 do
|
while 1 do
|
||||||
print("server: waiting for client connection...");
|
print("server: waiting for client connection...");
|
||||||
control, error = server:accept()
|
control = assert(server:accept());
|
||||||
assert(control, error)
|
|
||||||
-- control:setoption("nodelay", true)
|
|
||||||
while 1 do
|
while 1 do
|
||||||
command, error = control:receive()
|
command = assert(control:receive());
|
||||||
if error then
|
assert(control:send(ack));
|
||||||
control:close()
|
(loadstring(command))();
|
||||||
print("server: closing connection...")
|
|
||||||
break
|
|
||||||
end
|
|
||||||
sent, error = control:send(ack)
|
|
||||||
if error then
|
|
||||||
control:close()
|
|
||||||
print("server: closing connection...")
|
|
||||||
break
|
|
||||||
end
|
|
||||||
(loadstring(command))()
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
Loading…
Reference in New Issue
Block a user