Skip to content

Instantly share code, notes, and snippets.

@creationix
Last active August 29, 2015 14:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save creationix/39b811c796b2bfccff52 to your computer and use it in GitHub Desktop.
Save creationix/39b811c796b2bfccff52 to your computer and use it in GitHub Desktop.
luv docs

LibUV in Lua

The luv project provides access to the multi-platform support library libuv to lua code. It was primariliy developed for the luvit project as the uv builtin module, but can be used in other lua environments.

TCP Echo Server Example

Here is a small example showing a TCP echo server:

local uv = require('uv')

local server = uv.new_tcp()
server:bind("127.0.0.1", 1337)
server:listen(128, function (err)
  assert(not err, err)
  local client = uv.new_tcp()
  server:accept(client)
  client:read_start(function (err, chunk)
    assert(not err, err)
    if chunk then
      client:write(chunk)
    else
      client:shutdown()
      client:close()
    end
  end)
end)
print("TCP server listening at 127.0.0.1 port 1337")
uv.run()

Methods vs Functions

As a quick note, libuv is a C library and as such, there are no such things as methods. The luv bindings allow calling the libuv functions as either functions or methods. For example, calling server:bind(host, port) is equivalent to calling uv.tcp_bind(server, host, port). All wrapped uv types in lua have method shortcuts where is makes sense. Some are even renamed shorter like the tcp_ prefix that removed in method form. Under the hood it's the exact same C function.

Table Of Contents

The rest of the docs are organized by libuv type. There is some hierarchy as most types are considered handles and some are considered streams.

uv_loop_t — Event loop

The event loop is the central part of libuv’s functionality. It takes care of polling for i/o and scheduling callbacks to be run based on different sources of events.

In luv, there is an implicit uv loop for every lua state that loads the library. You can use this library in an multithreaded environment as long as each thread has it's own lua state with corresponsding own uv loop.

uv.loop_close()

Closes all internal loop resources. This function must only be called once the loop has finished its execution or it will raise a UV_EBUSY error.

uv.run([mode])

optional mode defaults to "default"

This function runs the event loop. It will act differently depending on the specified mode:

  • "default": Runs the event loop until there are no more active and referenced handles or requests. Always returns false.

  • "once": Poll for i/o once. Note that this function blocks if there are no pending callbacks. Returns false when done (no active handles or requests left), or true if more callbacks are expected (meaning you should run the event loop again sometime in the future).

  • "nowait": Poll for i/o once but don’t block if there are no pending callbacks. Returns false if done (no active handles or requests left), or true if more callbacks are expected (meaning you should run the event loop again sometime in the future).

Luvit will implicitly call uv.run() after loading user code, but if you use the luv bindings directly, you need to call this after registering your initial set of event callbacks to start the event loop.

uv.loop_alive()

Returns true if there are active handles or request in the loop.

uv.stop()

Stop the event loop, causing uv_run() to end as soon as possible. This will happen not sooner than the next loop iteration. If this function was called before blocking for i/o, the loop won’t block for i/o on this iteration.

uv.backend_fd()

Get backend file descriptor. Only kqueue, epoll and event ports are supported.

This can be used in conjunction with uv_run("nowait") to poll in one thread and run the event loop’s callbacks in another.

Note: Embedding a kqueue fd in another kqueue pollset doesn’t work on all platforms. It’s not an error to add the fd but it never generates events.

uv.backend_timeout()

Get the poll timeout. The return value is in milliseconds, or -1 for no timeout.

uv.now()

Return the current timestamp in milliseconds. The timestamp is cached at the start of the event loop tick, see uv.update_time() for details and rationale.

The timestamp increases monotonically from some arbitrary point in time. Don’t make assumptions about the starting point, you will only get disappointed.

Note: Use uv.hrtime() if you need sub-millisecond granularity.

uv.update_time()

Update the event loop’s concept of “now”. Libuv caches the current time at the start of the event loop tick in order to reduce the number of time-related system calls.

You won’t normally need to call this function unless you have callbacks that block the event loop for longer periods of time, where “longer” is somewhat subjective but probably on the order of a millisecond or more.

uv.walk(callback)

Walk the list of handles: callback will be executed with the handle.

-- Example usage of uv.walk to close all handles that aren't already closing.
uv.walk(function (handle)
  if not handle:is_closing() then
    handle:close()
  end
end)

uv_handle_t — Base handle

uv.is_active(handle)

method form handle:is_active()

uv.is_closing(handle)

method form handle:is_closing()

uv.close(handle, callback)

method form handle:close(callback)

uv.ref(handle)

method form handle:ref()

uv.unref(handle)

method form handle:unref()

uv.has_ref(handle)

method form handle:has_ref()

uv.send_buffer_size(handle, size)

method form handle:send_buffer_size(size)

uv.recv_buffer_size(handle, size)

method form handle:recv_buffer_size(size)

uv.fileno(handle)

method form handle:fileno()

uv_timer_t — Timer handle

uv_prepare_t — Prepare handle

uv_check_t — Check handle

uv_idle_t — Idle handle

uv_async_t — Async handle

uv_poll_t — Poll handle

uv_signal_t — Signal handle

uv_process_t — Process handle

uv_stream_t — Stream handle

Stream handles provide an abstraction of a duplex communication channel. uv_stream_t is an abstract type, libuv provides 3 stream implementations in the form of uv_tcp_t, uv_pipe_t and uv_tty_t.

uv.shutdown(stream, callback) -> req

(method form stream:shutdown(callback) -> req)

uv.listen(stream, backlog, callback)

(method form stream:listen(backlog, callback))

uv.accept(stream, client_stream)

(method form stream:accept(client_stream))

uv.read_start(stream, callback)

(method form stream:read_start(callback))

uv.read_stop(stream)

(method form stream:read_stop())

uv.write(stream, data, callback)

(method form stream:write(data, callback))

uv.write2(stream, data, handle, callback)

(method form stream:write2(data, handle, callback))

uv.try_write(stream, data)

(method form stream:try_write(data))

uv.is_readable(stream)

(method form stream:is_readable())

uv.is_writable(stream)

(method form stream:is_writable())

uv.stream_set_blocking(stream, blocking)

(method form stream:set_blocking(blocking))

uv_tcp_t — TCP handle

TCP handles are used to represent both TCP streams and servers.

uv_tcp_t is a ‘subclass’ of uv_stream_t.

uv.new_tcp() -> tcp

uv.tcp_open(tcp, sock)

(method form tcp:open(sock))

uv.tcp_nodelay(tcp, enable)

(method form tcp:nodelay(enable))

uv.tcp_keepalive(tcp, enable)

(method form tcp:keepalive(enable))

uv.tcp_simultaneous_accepts(tcp, enable)

(method form tcp:simultaneous_accepts(enable))

uv.tcp_bind(tcp, host, port)

(method form tcp:bind(host, port))

uv.tcp_getpeername(tcp)

(method form tcp:getpeername())

uv.tcp_getsockname(tcp)

(method form tcp:getsockname())

uv.tcp_connect(tcp, host, port, callback) -> req

(method form tcp:connect(host, port, callback) -> req)

uv.tcp_write_queue_size(tcp) -> size

(method form tcp:write_queue_size() -> size)

uv_pipe_t — Pipe handle

uv_tty_t — TTY handle

uv_udp_t — UDP handle

uv_fs_event_t — FS Event handle

uv_fs_poll_t — FS Poll handle

Filesystem operations

DNS utility functions

Miscellaneous utilities

TODO: move to right section

UV handle operations

All handle types in the uv module provide these base operations.

close()

All handle types provided by the uv module can be closed using the close(handle, callback) function or the <handle>:close(callback) method.

close() arguments

The handle argument specifies the handle to close. If using the close() method this argument is omitted.

The optional callback argument allows the user to provide a function to be ran after the close operation completes.

close() return value

The close() function always returns nil, it will raise an error if the handle specified is already being closed.

close() examples

local uv = require('uv')

local socket = uv.new_tcp()
socket:close()
local uv = require('uv')

local socket = uv.new_pipe(false)
uv.close(socket, function() print("pipe closed") end)

Streaming handle operations

Streaming handles are used to abstract duplex communication channels such as TCP Sockets, piping sockets and tty interfaces.

shutdown()

Streaming handles can be disconnected by using the shutdown(handle, callback) function or the <streaming handle>:shutdown(callback) method on streaming handle objects.

shutdown() arguments

The handle argument specifies the handle to disconnect. If using the shutdown() method this argument is omitted.

The optional callback argument allows the user to provide a function to be ran after the shutdown operation completes.

shutdown() return value

shutdown() returns the uv_shutdown_t request associated with the underlying shutdown operation.

TCP handle operations

The TCP handle type is used for both client and server TCP sockets.

The Streaming and UV Handle operations are available to TCP socket handles.

new_tcp()

TCP sockets are created using the new_tcp() function.

new_tcp() return value

tcp_new() will return a newly initialized TCP socket handle. A Lua error will be thrown for initialization failures.

new_tcp() example
local uv = require('uv')
local tcp_handle = uv.new_tcp()

tcp_bind()

TCP sockets can be bound to ports via the tcp_bind(tcp_handle, host, port, options) function or the <tcp_handle>:bind(host, port, options) method.

tcp_bind() arguments

The handle argument is the initialized TCP socket to bind to the address. If using the bind() method on a tcp_handle object this argument is omitted.

The host argument takes a string for the interface to bind on, it supports IPv4 and IPv6 addresses.

The port argument takes an integer to use as the port to bind on.

The options argument is optional. It is a table that can be used to utilize extra functionality for binding. Currently the only supported option is ipv6only, which if set will force binding using IPv6.

tcp_bind() return value

tcp_bind() operations will return 0 for successful operations. A Lua error will be thrown for binding failures.

tcp_bind() examples
local uv = require('uv')
local server = uv.new_tcp()
server:bind('127.0.0.1', 8080)
local uv = require('uv')
local server = uv.new_tcp()
uv.tcp_bind(server, '::1', 8080, {ipv6only=true})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment