W3cubDocs

/Hammerspoon

hs.socket.udp

Talk to custom protocols using asynchronous UDP sockets.

For TCP sockets see hs.socket.

You can do a lot of neat trivial and non-trivial things with these. A simple ping ponger:

function ping(data, addr)
  print(data)
  addr = hs.socket.parseAddress(addr)
  hs.timer.doAfter(1, function()
    client:send("ping", addr.host, addr.port)
  end)
end

function pong(data, addr)
  print(data)
  addr = hs.socket.parseAddress(addr)
  hs.timer.doAfter(1, function()
    server:send("pong", addr.host, addr.port)
  end)
end

server = hs.socket.udp.server(9001, pong):receive()
client = hs.socket.udp.new(ping):send("ping", "localhost", 9001):receive()

Resulting in the following endless exchange:

20:26:56    LuaSkin: (secondary thread): Data written to UDP socket
            LuaSkin: (secondary thread): Data read from UDP socket
ping
20:26:57    LuaSkin: (secondary thread): Data written to UDP socket
            LuaSkin: (secondary thread): Data read from UDP socket
pong
20:26:58    LuaSkin: (secondary thread): Data written to UDP socket
            LuaSkin: (secondary thread): Data read from UDP socket
ping
20:26:59    LuaSkin: (secondary thread): Data written to UDP socket
            LuaSkin: (secondary thread): Data read from UDP socket
pong
...

You can do some silly things with a callback factory and enabling broadcasting:

local function callbackMaker(name)
  local fun = function(data, addr)
    addr = hs.socket.parseAddress(addr)
    print(name.." received data:\n"..data.."\nfrom host: "..addr.host.." port: "..addr.port)
  end
  return fun
end

local listeners = {}
local port = 9001

for i=1,3 do
  table.insert(listeners, hs.socket.udp.new(callbackMaker("listener "..i)):reusePort():listen(port):receive())
end

broadcaster = hs.socket.udp.new():broadcast()
broadcaster:send("hello!", "255.255.255.255", port)

Since neither IPv4 nor IPv6 have been disabled, the broadcast is received on both protocols ('dual-stack' IPv6 addresses shown):

listener 2 received data:
hello!
from host: ::ffff:192.168.0.3 port: 53057
listener 1 received data:
hello!
from host: ::ffff:192.168.0.3 port: 53057
listener 3 received data:
hello!
from host: ::ffff:192.168.0.3 port: 53057
listener 1 received data:
hello!
from host: 192.168.0.3 port: 53057
listener 3 received data:
hello!
from host: 192.168.0.3 port: 53057
listener 2 received data:
hello!
from host: 192.168.0.3 port: 53057

API Overview

API Documentation

Variables

timeout
Signature hs.socket.udp.timeout
Type Variable
Description

Timeout for the socket operations, in seconds.

Notes
  • New hs.socket.udp objects will be created with this timeout value, but can individually change it with the hs.socket.udp:setTimeout method.

  • If the timeout value is negative, the operations will not use a timeout. The default value is -1.

Source extensions/socket/socket.lua line 173

Functions

parseAddress
Signature hs.socket.udp.parseAddress(sockaddr) -> table or nil
Type Function
Description

Alias for hs.socket.parseAddress

Parameters
Returns
Source extensions/socket/socket.lua line 184

Constructors

new
Signature hs.socket.udp.new([fn]) -> hs.socket.udp object
Type Constructor
Description

Creates an unconnected asynchronous UDP socket object.

Parameters
  • fn - An optional callback function for reading data from the socket, settable here for convenience.
Returns
Source extensions/socket/libsocket_udp.m line 111
server
Signature hs.socket.udp.server(port[, fn]) -> hs.socket.udp object
Type Constructor
Description

Creates a UDP socket, and binds it to a port for listening.

Parameters
  • port - A port number [0-65535]. Ports [1-1023] are privileged. Port 0 allows the OS to select any available port.
  • fn - An optional callback function for reading data from the socket, settable here for convenience.
Returns
Source extensions/socket/socket.lua line 208

Methods

broadcast
Signature hs.socket.udp:broadcast([flag]) -> self or nil
Type Method
Description

Enables broadcasting on the underlying socket.

Parameters
  • flag - An optional boolean: true to enable broadcasting, false to disable it. Defaults to true.
Returns
Notes
  • By default, the underlying socket in the OS will not allow you to send broadcast messages.
  • In order to send broadcast messages, you need to enable this functionality in the socket.
  • A broadcast is a UDP message to addresses like "192.168.255.255" or "255.255.255.255" that is delivered to every host on the network.
  • The reason this is generally disabled by default (by the OS) is to prevent accidental broadcast messages from flooding the network.
Source extensions/socket/libsocket_udp.m line 418
close
Signature hs.socket.udp:close() -> self
Type Method
Description

Immediately closes the socket, freeing it for reuse. Any pending send operations are discarded.

Parameters
  • None
Returns
Source extensions/socket/libsocket_udp.m line 222
closed
Signature hs.socket.udp:closed() -> bool
Type Method
Description

Returns the closed status of the socket.

Parameters
  • None
Returns
  • true if the socket is closed, otherwise false.
Notes
  • UDP sockets are typically meant to be connectionless.
  • Sending a packet anywhere, regardless of whether or not the destination receives it, opens the socket until it is explicitly closed.
  • An active listening socket will not be closed, but will not be 'connected' unless the hs.socket.udp:connect method has been called.
Source extensions/socket/libsocket_udp.m line 675
connect
Signature hs.socket.udp:connect(host, port[, fn]) -> self or nil
Type Method
Description

Connects an unconnected socket.

Parameters
  • host - A string containing the hostname or IP address.
  • port - A port number [1-65535].
  • fn - An optional single-use callback function to execute after establishing the connection. The callback receives no parameters.
Returns
Notes
  • By design, UDP is a connectionless protocol, and connecting is not needed.
  • Choosing to connect to a specific host/port has the following effect:
    • You will only be able to send data to the connected host/port;
    • You will only be able to receive data from the connected host/port;
    • You will receive ICMP messages that come from the connected host/port, such as "connection refused".
  • The actual process of connecting a UDP socket does not result in any communication on the socket, it simply changes the internal state of the socket.
  • You cannot bind a socket for listening after it has been connected.
  • You can only connect a socket once.
Source extensions/socket/libsocket_udp.m line 145
connected
Signature hs.socket.udp:connected() -> bool
Type Method
Description

Returns the connection status of the socket.

Parameters
  • None
Returns
  • true if connected, otherwise false.
Notes
  • UDP sockets are typically meant to be connectionless.
  • This method will only return true if the hs.socket.udp:connect method has been explicitly called.
Source extensions/socket/libsocket_udp.m line 652
enableIPv
Signature hs.socket.udp:enableIPv(version[, flag]) -> self or nil
Type Method
Description

Enables or disables IPv4 or IPv6 on the underlying socket. By default, both are enabled.

Parameters
  • version - A number containing the IP version (4 or 6) to enable or disable.
  • flag - A boolean: true to enable the chosen IP version, false to disable it. Defaults to true.
Returns
Notes
  • Must be called before binding the socket. If you want to create an IPv6-only server, do something like:
    • hs.socket.udp.new(callback):enableIPv(4, false):listen(port):receive()
  • The convenience constructor hs.socket.server will automatically bind the socket and requires closing and relistening to use this method.
Source extensions/socket/libsocket_udp.m line 486
info
Signature hs.socket.udp:info() -> table
Type Method
Description

Returns information about the socket.

Parameters
  • None
Returns
  • A table containing the following keys:
    • connectedAddress - string (sockaddr struct)
    • connectedHost - string
    • connectedPort - number
    • isClosed - boolean
    • isConnected - boolean
    • isIPv4 - boolean
    • isIPv4Enabled - boolean
    • isIPv4Preferred - boolean
    • isIPv6 - boolean
    • isIPv6Enabled - boolean
    • isIPv6Preferred - boolean
    • isIPVersionNeutral - boolean
    • localAddress - string (sockaddr struct)
    • localAddress_IPv4 - string (sockaddr struct)
    • localAddress_IPv6 - string (sockaddr struct)
    • localHost - string
    • localHost_IPv4 - string
    • localHost_IPv6 - string
    • localPort - number
    • localPort_IPv4 - number
    • localPort_IPv6 - number
    • maxReceiveIPv4BufferSize - number
    • maxReceiveIPv6BufferSize - number
    • timeout - number
    • userData - string
Source extensions/socket/libsocket_udp.m line 699
listen
Signature hs.socket.udp:listen(port) -> self or nil
Type Method
Description

Binds an unconnected socket to a port for listening.

Parameters
  • port - A port number [0-65535]. Ports [1-1023] are privileged. Port 0 allows the OS to select any available port.
Returns
Source extensions/socket/libsocket_udp.m line 192
pause
Signature hs.socket.udp:pause() -> self
Type Method
Description

Suspends reading of packets from the socket.

Parameters
  • None
Returns
Notes
  • Call one of the receive methods to resume.
Source extensions/socket/libsocket_udp.m line 243
preferIPv
Signature hs.socket.udp:preferIPv([version]) -> self
Type Method
Description

Sets the preferred IP version: IPv4, IPv6, or neutral (first to resolve).

Parameters
  • version - An optional number containing the IP version to prefer. Anything but 4 or 6 else sets the default neutral behavior.
Returns
Notes
  • If a DNS lookup returns only IPv4 results, the socket will automatically use IPv4.
  • If a DNS lookup returns only IPv6 results, the socket will automatically use IPv6.
  • If a DNS lookup returns both IPv4 and IPv6 results, then the protocol used depends on the configured preference.
Source extensions/socket/libsocket_udp.m line 523
read
Signature hs.socket.udp:read(delimiter[, tag]) -> self
Type Method
Description

Alias for hs.socket.udp:receive

Parameters
Returns
Source extensions/socket/socket.lua line 237
readOne
Signature hs.socket.udp:readOne(delimiter[, tag]) -> self
Type Method
Description

Alias for hs.socket.udp:receiveOne

Parameters
Returns
Source extensions/socket/socket.lua line 243
receive
Signature hs.socket.udp:receive([fn]) -> self or nil
Type Method
Description

Reads packets from the socket as they arrive.

Parameters
Returns
Notes
  • Results are passed to the callback function, which must be set to use this method.
  • There are two modes of operation for receiving packets: one-at-a-time & continuous.
  • In one-at-a-time mode, you call receiveOne every time you are ready process an incoming UDP packet.
  • Receiving packets one-at-a-time may be better suited for implementing certain state machine code where your state machine may not always be ready to process incoming packets.
  • In continuous mode, the callback is invoked immediately every time incoming udp packets are received.
  • Receiving packets continuously is better suited to real-time streaming applications.
  • You may switch back and forth between one-at-a-time mode and continuous mode.
  • If the socket is currently in one-at-a-time mode, calling this method will switch it to continuous mode.
Source extensions/socket/libsocket_udp.m line 295
receiveOne
Signature hs.socket.udp:receiveOne([fn]) -> self or nil
Type Method
Description

Reads a single packet from the socket.

Parameters
Returns
Notes
  • Results are passed to the callback function, which must be set to use this method.
  • There are two modes of operation for receiving packets: one-at-a-time & continuous.
  • In one-at-a-time mode, you call receiveOne every time you are ready process an incoming UDP packet.
  • Receiving packets one-at-a-time may be better suited for implementing certain state machine code where your state machine may not always be ready to process incoming packets.
  • In continuous mode, the callback is invoked immediately every time incoming udp packets are received.
  • Receiving packets continuously is better suited to real-time streaming applications.
  • You may switch back and forth between one-at-a-time mode and continuous mode.
  • If the socket is currently in continuous mode, calling this method will switch it to one-at-a-time mode
Source extensions/socket/libsocket_udp.m line 321
reusePort
Signature hs.socket.udp:reusePort([flag]) -> self or nil
Type Method
Description

Enables port reuse on the socket.

Parameters
  • flag - An optional boolean: true to enable port reuse, false to disable it. Defaults to true.
Returns
Notes
  • By default, only one socket can be bound to a given IP address & port at a time.
  • To enable multiple processes to simultaneously bind to the same address & port, you need to enable this functionality in the socket.
  • All processes that wish to use the address & port simultaneously must all enable reuse port on the socket bound to that port.
  • Must be called before binding the socket.
Source extensions/socket/libsocket_udp.m line 452
send
Signature hs.socket.udp:send(message[, host, port][, tag, fn]) -> self
Type Method
Description

Sends a packet to the destination address.

Parameters
  • message - A string containing data to be sent on the socket.
  • host - A string containing the hostname or IP address.
  • port - A port number [1-65535].
  • tag - An optional integer to assist with labeling writes.
  • fn - An optional single-use callback function to execute after sending the packet. The callback receives the tag parameter provided here.
Returns
Notes
  • For non-connected sockets, the remote destination is specified for each packet.
  • If the socket has been explicitly connected with connect, only the message parameter and an optional tag and/or write callback can be supplied.
  • Recall that connecting is optional for a UDP socket.
  • For connected sockets, data can only be sent to the connected address.
Source extensions/socket/libsocket_udp.m line 347
setBufferSize
Signature hs.socket.udp:setBufferSize(size[, version]) -> self
Type Method
Description

Sets the maximum size of the buffer that will be allocated for receive operations.

Parameters
  • size - An number containing the receive buffer size in bytes.
  • version - An optional number containing the IP version for which to set the buffer size. Anything but 4 or 6 else sets the same size for both.
Returns
Notes
  • The default maximum size is 9216 bytes.
  • The theoretical maximum size of any IPv4 UDP packet is UINT16_MAX = 65535.
  • The theoretical maximum size of any IPv6 UDP packet is UINT32_MAX = 4294967295.
  • Since the OS notifies us of the size of each received UDP packet, the actual allocated buffer size for each packet is exact.
  • In practice the size of UDP packets is generally much smaller than the max. Most protocols will send and receive packets of only a few bytes, or will set a limit on the size of packets to prevent fragmentation in the IP layer.
  • If you set the buffer size too small, the sockets API in the OS will silently discard any extra data.
Source extensions/socket/libsocket_udp.m line 555
setCallback
Signature hs.socket.udp:setCallback([fn]) -> self
Type Method
Description

Sets the read callback for the socket.

Parameters
  • fn - An optional callback function to process data read from the socket. nil or no argument clears the callback. The callback receives 2 parameters:
    • data - The data read from the socket as a string.
    • sockaddr - The sending address as a binary socket address structure. See parseAddress.
Returns
Notes
  • A callback must be set in order to read data from the socket.
Source extensions/socket/libsocket_udp.m line 597
setTimeout
Signature hs.socket.udp:setTimeout(timeout) -> self
Type Method
Description

Sets the timeout for the socket operations.

Parameters
  • timeout - A number containing the timeout duration, in seconds.
Returns
Notes
  • If the timeout value is negative, the operations will not use a timeout, which is the default.
Source extensions/socket/libsocket_udp.m line 628
write
Signature hs.socket.udp:write(message[, tag]) -> self
Type Method
Description

Alias for hs.socket.udp:send

Parameters
Returns
Source extensions/socket/socket.lua line 249

© 2014–2017 Hammerspoon contributors
Licensed under the MIT License.
https://www.hammerspoon.org/docs/hs.socket.udp.html