A line between two programs
A web request (The web and the internet) asks a question and gets one answer. A socket is a lasting two-way connection: both ends can write whenever they like, for as long as it stays open. Chat programs, multiplayer games and devices on a network all talk this way.
One program is the server: it listens on a port, a number from 1 to 65535 on its computer. The other is the client: it connects to the server's address and port. Once connected, the two are equal. In this lesson's examples one script plays both parts, on this computer (127.0.0.1), so they run anywhere.
The server: accept connections
accept connections on port starts listening. Each time a client connects, the message you name arrives with the new connection's id, which is the client's address and port, and is how you write to it, read from it and close it:
on startServer
accept connections on port 47123 with message "newClient"
if the result is not empty then answer "Could not listen:" && the result
end startServer
on newClient pSocket
-- pSocket is the connection, such as 127.0.0.1:52344
write "Welcome!" & return to socket pSocket
end newClient
on stopServer
close socket 47123
end stopServer
Closing the port stops the listening; connections already made stay open until they are closed too. Use a port above 1024 (lower ones need special permission), and one no other program on the computer uses.
The client: open socket
open socket to the address and port connects, and the message you name arrives once the connection is made. Nothing should be written before it does.
Writing and reading with messages
write ... to socket sends data. read from socket takes data that has arrived: until return for a line, or for a number of bytes. With with message, the read returns at once, and the message arrives with the data when it has all come, so the program never stops to wait for the other end. Here a client says hello and a server answers in capitals:
on newClient pSocket
put "server: someone connected"
read from socket pSocket until return with message "serverGotLine"
end newClient
on serverGotLine pSocket, pData
put "server got:" && line 1 of pData
write toUpper(pData) to socket pSocket
end serverGotLine
on connected pSocket
put "client: connected"
write "hello" & return to socket pSocket
read from socket pSocket until return with message "clientGotLine"
end connected
on clientGotLine pSocket, pData
put "client got:" && line 1 of pData
close socket pSocket
close socket 47123
end clientGotLine
accept connections on port 47123 with message "newClient"
open socket to "127.0.0.1:47123" with message "connected"
put "both ends are getting ready"
both ends are getting ready server: someone connected client: connected server got: hello client got: HELLO
Follow the order of the lines: nothing happens during the script itself but setting things up. Everything after the first line happens in messages, as the data travels. That is the shape of every socket program: a handler for each thing that can arrive.
When things go wrong
Networks fail: the server is not there, the other end goes away, nothing arrives. The engine reports each with a message to the object that opened the socket: socketError with the socket and what went wrong, socketClosed when the other end closes, and socketTimeout when a read has waited longer than the socketTimeoutInterval:
on socketError pSocket, pError
put "could not use" && pSocket & ":" && pError
end socketError
on socketClosed pSocket
put pSocket && "was closed by the other end"
end socketClosed
open socket to "127.0.0.1:1" with message "connected"
put "trying a port where nobody listens"
trying a port where nobody listens could not use 127.0.0.1:1: Error 111 reading socket
the openSockets lists the connections and ports still open, a line each: check it to make sure a program closes what it opens.
A protocol of your own
The two ends must agree how a message ends, or the reader cannot tell one from the next: this agreement is a protocol. The simplest is a line each, as above, which suits text that has no line breaks in it. For anything else (text with returns, pictures, files) send the length first, and read exactly that many bytes:
-- each message: its length as 4 bytes, then the bytes
command sendMessage pSocket, pText
local tData
put textEncode(pText, "UTF-8") into tData
write binaryEncode("N", the number of bytes of tData) & tData to socket pSocket
end sendMessage
command listenFor pSocket
read from socket pSocket for 4 bytes with message "gotLength"
end listenFor
on gotLength pSocket, pData
local tLength
get binaryDecode("N", pData, tLength)
read from socket pSocket for tLength bytes with message "gotMessage"
end gotLength
on gotMessage pSocket, pData
put textDecode(pData, "UTF-8") after field "Chat"
listenFor pSocket
end gotMessage
Try it yourself
Write a calculator server: it reads lines such as add 2 3 or times 4 5, answers each with the result, and keeps reading. The client sends both questions, one after the other as each answer arrives, puts the answers, then closes.
Show a solution
local sQuestions
on newClient pSocket
read from socket pSocket until return with message "serverGotLine"
end newClient
on serverGotLine pSocket, pData
switch word 1 of pData
case "add"
write word 2 of pData + word 3 of pData & return to socket pSocket
break
case "times"
write word 2 of pData * word 3 of pData & return to socket pSocket
break
default
write "unknown" & return to socket pSocket
end switch
read from socket pSocket until return with message "serverGotLine"
end serverGotLine
on connected pSocket
askNext pSocket
end connected
on askNext pSocket
if sQuestions is empty then
close socket pSocket
close socket 47124
exit askNext
end if
put line 1 of sQuestions into tQuestion
delete line 1 of sQuestions
put tQuestion && "is ..."
write tQuestion & return to socket pSocket
read from socket pSocket until return with message "clientGotAnswer"
end askNext
on clientGotAnswer pSocket, pData
put "... " & line 1 of pData
askNext pSocket
end clientGotAnswer
put "add 2 3" & return & "times 4 5" into sQuestions
accept connections on port 47124 with message "newClient"
open socket to "127.0.0.1:47124" with message "connected"
add 2 3 is ... ... 5 times 4 5 is ... ... 20
Words in this lesson
accept connectionsopen socketwrite to socketread from socketclose socketthe openSocketssocketErrorsocketClosedsocketTimeoutopen secure socketEach one finds every lesson that uses it. The Dictionary has the whole story of each, with its syntax and more examples.