Skip to content

Commit

Permalink
Merge b42f5f7 into a0faba0
Browse files Browse the repository at this point in the history
  • Loading branch information
Tieske committed Sep 16, 2022
2 parents a0faba0 + b42f5f7 commit c3472a6
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 13 deletions.
9 changes: 7 additions & 2 deletions docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -100,13 +100,18 @@ <h2><a name="dependencies"></a>Dependencies</h2>
<h2><a name="history"></a>History</h2>

<dl class="history">
<dt><strong>Copas 4.2.x</strong> [unreleased]</dt>
<dt><strong>Copas 4.3.x</strong> [unreleased]</dt>
<dd><ul>
<li>Fix: when the loop is idle, do an occasional GC to clean out any lingering
non-closed sockets. This could prevent the loop from exiting.</li>
<li>Fix: in debug mode very large data is now truncated when displayed.</li>
<li>Fix: order of <code>copas.addnamedthread</code> args.</li>
<li>Fix: the receive methods could starve other threads on high-throughput.</li>
<li>Change: order of <code>copas.addnamedthread</code> args.</li>
<li>Fix: <code>copas.recievepartial</code> could return early with no data received
if the `prefix` parameter was specified.</li>
<li>Change: renamed <code>copas.receivePartial</code> to <code>copas.receivepartial</code>.</li>
<li>Added: <code>sock:receivepartial</code> to better process streaming TCP data.</li>
<li>fix: <code>copas.receivepartial</code> is now documented.</li>
</ul></dd>

<dt><strong>Copas 4.2.0</strong> [06/Sep/2022]</dt>
Expand Down
35 changes: 29 additions & 6 deletions docs/reference.html
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,27 @@ <h3>Non-blocking data exchange and timer/sleep functions</h3>

<dt><strong><code>sock:receive(...)</code></strong></dt>
<dd>Non-blocking equivalent to the LuaSocket method (after <code>copas.wrap</code>).
Please see <code>copas.receivepartial</code> for differences with LuaSocket, especially
when using the <code>"*a"</code> pattern.
</dd>

<dt><strong><code>sock:receivepartial(...)</code></strong></dt>
<dd>This method is the same as the <code>receive</code> method, the difference being
that this method will return on any data received, even if the specified pattern was not
yet satisfied.<br/>
<br/>
When using delimited formats or known byte-size (pattern is <code>"*l"</code> or a number)
the regular <code>receive</code> method will usually be fine. But when reading a stream with
the <code>"*a"</code> pattern the <code>receivepartial</code> method should be used.<br/>
<br/>
The reason for this is the difference in timeouts between Copas and LuaSocket. The Copas
timeout will apply on each underlying socket read/write operation. So on every chunk received
Copas will reset the timeout. So if reading pattern <code>"*a"</code> with a 10 second timeout,
and the sender sends a stream of data (unlimited size), in 1kb chunks, with 5 seconds intervals,
then there will never be a timeout when using <code>receive</code>, and hence the call would
never return.<br/>
If using <code>receivepartial</code> with the <code>"*a"</code>
pattern, the (repeated) call would return the 1kb chunks, with a <code>"timeout"</code> error.
</dd>

<dt><strong><code>sock:send(...)</code></strong></dt>
Expand Down Expand Up @@ -636,7 +657,7 @@ <h3>Low level Copas functions</h3>
<dt><strong><code>copas.flush(skt)</code></strong><br /></dt>
<dd>(deprecated)</dd>

<dt><strong><code>copas.receive(skt [, pattern])</code></strong> (TCP) or<br />
<dt><strong><code>copas.receive(skt [, pattern[, prefix]])</code></strong> (TCP) or<br />
<strong><code>copas.receive(size)</code></strong> (UDP)
</dt>
<dd>Reads data from a client socket according to a pattern just like LuaSocket
Expand All @@ -648,6 +669,11 @@ <h3>Low level Copas functions</h3>
optional again.
</dd>

<dt><strong><code>copas.receivepartial(skt [, pattern[, prefix]])</code></strong>
</dt>
<dd>The same as <code>receive</code>, except that this method will return on
any data received. See <code>sock:receivepartial</code> for details.</dd>

<dt><strong><code>copas.receivefrom(skt [, size])</code></strong></dt>
<dd>Reads data from a UDP socket just like LuaSocket
<code>socket:receivefrom()</code>. The Copas version does not block and allows
Expand All @@ -663,16 +689,13 @@ <h3>Low level Copas functions</h3>
Note: only for TCP, UDP send doesn't block, hence doesn't require this function to be used.
</dd>

<dt><strong><code>copas.sendto(skt, datagram, ip, port)</code></strong></dt>
<dd>(deprecated, since UDP sending doesn't block)</dd>

<dt><strong><code>copas.settimeout(skt, [timeout])</code></strong></dt>
<dd>Sets the timeout (in seconds) for a socket. A negative timout or absent timeout (<code>nil</code>)
will wait indefinitely.<br/>
<strong>Important:</strong> this behaviour is the same as LuaSocket, but different from
<code>copas.settimeouts</code>, where <code>nil</code> means 'do not change' the timeout.<br/>
If a timeout is hit, the operation will return <code>nil + "timeout"</code>.
Timeouts are applied on: <code>receive, receivefrom, receivePartial, send, connect, dohandshake</code>.<br />
Timeouts are applied on: <code>receive, receivefrom, receivepartial, send, connect, dohandshake</code>.<br />
See <code>copas.useSocketTimeoutErrors()</code> below for alternative error messages.
</dd>

Expand All @@ -682,7 +705,7 @@ <h3>Low level Copas functions</h3>
<strong>Important:</strong> this behaviour is different from
<code>copas.settimeout</code>, where <code>nil</code> means 'wait indefinitely'.<br/>
If a timeout is hit, the operation will return <code>nil + "timeout"</code>.
Timeouts are applied on: <code>receive, receivefrom, receivePartial, send, connect, dohandshake</code>.<br />
Timeouts are applied on: <code>receive, receivefrom, receivepartial, send, connect, dohandshake</code>.<br />
See <code>copas.useSocketTimeoutErrors()</code> below for alternative error messages.
</dd>

Expand Down
12 changes: 9 additions & 3 deletions src/copas.lua
Original file line number Diff line number Diff line change
Expand Up @@ -549,9 +549,10 @@ end

-- same as above but with special treatment when reading chunks,
-- unblocks on any data received.
function copas.receivePartial(client, pattern, part)
function copas.receivepartial(client, pattern, part)
local s, err
pattern = pattern or "*l"
local orig_size = #(part or "")
local current_log = _reading_log
sto_timeout(client, "read")

Expand All @@ -563,7 +564,7 @@ function copas.receivePartial(client, pattern, part)
copas.sleep(0)
end

if s or (type(pattern) == "number" and part ~= "" and part ~= nil) then
if s or (type(part) == "string" and #part > orig_size) then
current_log[client] = nil
sto_timeout()
return s, err, part
Expand Down Expand Up @@ -591,6 +592,7 @@ function copas.receivePartial(client, pattern, part)
end
until false
end
copas.receivePartial = copas.receivepartial -- compat: receivePartial is deprecated

-- sends data to a client. The operation is buffered and
-- yields to the writing set on timeouts
Expand Down Expand Up @@ -829,11 +831,15 @@ local _skt_mt_tcp = {

receive = function (self, pattern, prefix)
if user_timeouts_receive[self.socket] == 0 then
return copas.receivePartial(self.socket, pattern, prefix)
return copas.receivepartial(self.socket, pattern, prefix)
end
return copas.receive(self.socket, pattern, prefix)
end,

receivepartial = function (self, pattern, prefix)
return copas.receivepartial(self.socket, pattern, prefix)
end,

flush = function (self)
return copas.flush(self.socket)
end,
Expand Down
4 changes: 2 additions & 2 deletions tests/largetransfer.lua
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
-- tests large transmissions, sending and receiving
-- uses `receive` and `receivePartial`
-- uses `receive` and `receivepartial`
-- Does send the same string twice simultaneously
--
-- Test should;
Expand Down Expand Up @@ -32,7 +32,7 @@ local function runtest()

local s2 = socket.bind('*', 49501)
copas.addserver(s2, copas.handler(function(skt)
skt:settimeout(0) -- set, uses the `receivePartial` method
skt:settimeout(0) -- set, uses the `receivepartial` method
copas.setsocketname("Server 49501", skt)
copas.setthreadname("Server 49501")
local res, err, part = skt:receive('*a')
Expand Down

0 comments on commit c3472a6

Please sign in to comment.