lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


2008/11/10 Sam Roberts <vieuxtech@gmail.com>:
> LuaSocket doesn't have an obvious way to read whatever data is
> available from a socket, if it isn't line delimited or of a known
> size. I found a way, but it seems unnecessarily obscure.
>
> For a project I'm working on, when a socket selects as receivable, I
> want whatever data is available, and I push into another object. I
> don't have any knowledge of how much might be there, and it's binary
> data so using *l is out of the question.
>
> Anyhow, I implemented the following, but I've some questions:
>
> 1 - is this a good way to do it? It seems to work, but also seems a hack.
>
> 2 - why is partial not nil if there is no partial data? It's always
> "", even if emsg isn't "timeout".
>
> 3 - I'd like to replace the standard receive with mine, but every
> client socket seems to get a different metatable. Can I get to the
> table with LuaSocket's client TCP methods, and replace it's receive
> with mine?
>
> 4 - any chance of making "*f" ("frame") a standard part of LuaSocket?
>
>
> --[[-
> - data, emsg, partial = client:receive(pattern[, prefix])
> - data, emsg, partial = client:receive("*f"[, size])
>
> If pattern is not "*f", is identical to client:receive().
>
> Otherwise, return as much data as is available, up to size bytes.  If size is
> not specified, it defaults to 4096. This is useful for dealing with a TCP
> stream without knowing the protocol. I.e., transparent proxying of TCP data as
> it arrives.
>
> This pattern requires setting client's timeout to 0, for non-blocking behaviour.
> ]]
> function receive(client, pattern, prefix)
>  if pattern ~= "*f" then
>    return client:receive(pattern, prefix)
>  end
>
>  local size = assert(tonumber(prefix or 4096))
>  local data, emsg, partial = client:receive(size)
>  if  not data and partial ~= "" then
>    return partial
>  else
>    return data, emsg
>  end
> end

I think you can simply use the "*a" pattern to do what you asked for.
It works just like the code you proposed, except it's not limited to a
fixed amount of bytes and it properly handles the prefix parameter
(which you don't). For example:

client:settimeout(0)

function receive(socket, pattern, prefix)
  if string.match(pattern, "^%*f") then
    local data, emsg, partial = socket:receive("*a", prefix)
    if  not data and emsg=='timeout' then
      return partial
    else
      return data, emsg
    end
  else
    return socket:receive(pattern, prefix)
  end
end