Talk to custom protocols using asynchronous TCP sockets
For UDP sockets see hs.socket.udp
hs.socket
is implemented with CocoaAsyncSocket. CocoaAsyncSocket's tagging features provide a handy way to implement custom protocols.
For example, you can easily implement a basic HTTP client as follows (though using hs.http
is recommended for the real world):
local TAG_HTTP_HEADER, TAG_HTTP_CONTENT = 1, 2 local body = "" local function httpCallback(data, tag) if tag == TAG_HTTP_HEADER then print(tag, "TAG_HTTP_HEADER"); print(data) local contentLength = data:match("\r\nContent%-Length: (%d+)\r\n") client:read(tonumber(contentLength), TAG_HTTP_CONTENT) elseif tag == TAG_HTTP_CONTENT then print(tag, "TAG_HTTP_CONTENT"); print(data) body = data end end client = hs.socket.new(httpCallback):connect("google.com", 80) client:write("GET /index.html HTTP/1.0\r\nHost: google.com\r\n\r\n") client:read("\r\n\r\n", TAG_HTTP_HEADER)
Resulting in the following console output (adjust log verbosity with hs.socket.setLogLevel()
) :
LuaSkin: (secondary thread): TCP socket connected LuaSkin: (secondary thread): Data written to TCP socket LuaSkin: (secondary thread): Data read from TCP socket 1 TAG_HTTP_HEADER HTTP/1.0 301 Moved Permanently Location: http://www.google.com/index.html Content-Type: text/html; charset=UTF-8 Date: Thu, 03 Mar 2016 08:38:02 GMT Expires: Sat, 02 Apr 2016 08:38:02 GMT Cache-Control: public, max-age=2592000 Server: gws Content-Length: 229 X-XSS-Protection: 1; mode=block X-Frame-Options: SAMEORIGIN LuaSkin: (secondary thread): Data read from TCP socket 2 TAG_HTTP_CONTENT <HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8"> <TITLE>301 Moved</TITLE></HEAD><BODY> <H1>301 Moved</H1> The document has moved <A HREF="http://www.google.com/index.html">here</A>. </BODY></HTML> LuaSkin: (secondary thread): TCP socket disconnected Socket closed by remote peer
Signature | hs.socket.timeout |
---|---|
Type | Variable |
Description | Timeout for the socket operations, in seconds. New [`hs.socket`](#new) objects will be created with this timeout value, but can individually change it with the [`setTimeout`](#setTimeout) method |
Source | extensions/socket/init.lua |
Signature | hs.socket.parseAddress(sockaddr) -> table or nil |
---|---|
Type | Function |
Description | Parses a binary socket address structure into a readable table |
Parameters |
|
Returns |
|
Notes |
|
Source | extensions/socket/internal.m |
Signature | hs.socket.new([fn]) -> hs.socket object |
---|---|
Type | Constructor |
Description | Creates an unconnected asynchronous TCP socket object |
Parameters |
|
Returns |
|
Source | extensions/socket/internal.m |
Signature | hs.socket.server(port|path[, fn]) -> hs.socket object |
---|---|
Type | Constructor |
Description | Creates and binds an [`hs.socket`](#new) instance to a port or path (Unix domain socket) for listening |
Parameters |
|
Returns |
|
Source | extensions/socket/init.lua |
Signature | hs.socket:connect({host, port}|path[, fn]) -> self or nil |
---|---|
Type | Method |
Description | Connects an unconnected [`hs.socket`](#new) instance |
Parameters |
|
Returns |
|
Notes |
|
Source | extensions/socket/internal.m |
Signature | hs.socket:connected() -> bool |
---|---|
Type | Method |
Description | Returns the connection status of the [`hs.socket`](#new) instance |
Parameters |
|
Returns |
|
Source | extensions/socket/internal.m |
Signature | hs.socket:connections() -> number |
---|---|
Type | Method |
Description | Returns the number of connections to the socket, which is at most 1 for default (non-listening) sockets |
Parameters |
|
Returns |
|
Source | extensions/socket/internal.m |
Signature | hs.socket:disconnect() -> self |
---|---|
Type | Method |
Description | Disconnects the [`hs.socket`](#new) instance, freeing it for reuse |
Parameters |
|
Returns |
|
Notes |
|
Source | extensions/socket/internal.m |
Signature | hs.socket:info() -> table |
---|---|
Type | Method |
Description | Returns information on the [`hs.socket`](#new) instance |
Parameters |
|
Returns |
|
Source | extensions/socket/internal.m |
Signature | hs.socket:listen(port|path) -> self or nil |
---|---|
Type | Method |
Description | Binds an unconnected [`hs.socket`](#new) instance to a port or path (Unix domain socket) for listening |
Parameters |
|
Returns |
|
Source | extensions/socket/internal.m |
Signature | hs.socket:read(delimiter[, tag]) -> self or nil |
---|---|
Type | Method |
Description | Read data from the socket. Results are passed to the [callback function](#setCallback), which must be set to use this method |
Parameters |
|
Returns |
|
Notes |
|
Source | extensions/socket/internal.m |
Signature | hs.socket:receive(delimiter[, tag]) -> self |
---|---|
Type | Method |
Description | Alias for [`hs.socket:read`](#read) |
Parameters | |
Returns | |
Source | extensions/socket/init.lua |
Signature | hs.socket:send(message[, tag]) -> self |
---|---|
Type | Method |
Description | Alias for [`hs.socket:write`](#write) |
Parameters | |
Returns | |
Source | extensions/socket/init.lua |
Signature | hs.socket:setCallback([fn]) -> self |
---|---|
Type | Method |
Description | Sets the read callback for the [`hs.socket`](#new) instance. Must be set to read data from the socket |
Parameters |
|
Returns |
|
Source | extensions/socket/internal.m |
Signature | hs.socket:setTimeout(timeout) -> self |
---|---|
Type | Method |
Description | Sets the timeout for the socket operations. If the timeout value is negative, the operations will not use a timeout, which is the default |
Parameters |
|
Returns |
|
Source | extensions/socket/internal.m |
Signature | hs.socket:startTLS([verify][, peerName]) -> self |
---|---|
Type | Method |
Description | Secures the socket with TLS. The socket will disconnect immediately if TLS negotiation fails |
Parameters |
|
Returns |
|
Notes |
|
Source | extensions/socket/internal.m |
Signature | hs.socket:write(message[, tag][, fn]) -> self |
---|---|
Type | Method |
Description | Write data to the socket |
Parameters |
|
Returns |
|
Notes |
|
Source | extensions/socket/internal.m |