Ahhoz, hogy Luában TCP/IP-t tudjunk használni, először is be kell töltenünk a socket library-t a
require("socket")
direktíva segítségével.
Ezután, mint bármilyen más nyelvben, először egy socketet kell kreálnunk a bind függvény hívásával:
server = assert (socket.bind ("*", port))
Itt, ha a port helyére 0-t írtunk, úgy a rendszer választ számunkra portot. Ebben az esetben az
ip, port = server:getsockname ()
függvény hívásával tudhatjuk meg, hogy az OS mely portot allokálta számunkra.
A settimeout(t) függvénnyel tudjuk megadni, hogy az adott műveleteknél (accept, connect, receive) mennyi legyen a maximális várakozási idő. Itt is a -1 az extremális érték, melynek hatására korlátlan ideig várakozik a program. Az accept függvény várakozik a bejövő kapcsolatokra, és amennyiben/amikor van ilyen, úgy visszatér a kliens objektummal. Ezután a receive függvénnyel tudunk üzenetet fogadni, melynek visszatérési értéke egy triple.
line, err, partial_line = tcp:receive()
Sikeres üzenet fogadás esetén a line ~= nil, míg az error == nil. Amennyiben a komunikáció során hiba lépett fel, úgy az az error változó értékében jelenik meg, azonban még ebben az esetben is lehet a partial_line változóban részleges üzenet. A lehetséges error értékek közül megkülönböztetett szerepet foglal el a 'timeout', ezt egyszerűen az
err == 'timeout'
-tal vizsgálhatjuk.
Kliens oldalon a kapcsolat létrejöttéhez a
tcp:connect(host, port)
függvényt szükséges meghívni.
Ezután már csak a kommunikáció végén a kapcsolat lezárása maradt hátra, melyet a close () függvény hívásával tehetünk meg.
Az alábbi példakód szemléltet egy lehetséges lefolyást.
server.lua
require("socket")
local message = "Hello Client!"
local server = nil
local port = 1234
function main ()
server = assert(socket.bind("*", port))
print("Please connect the client to localhost on port " .. port)
server:settimeout(-1)
local client = server:accept()
print ("A client has connected.")
local line, err = client:receive()
if not err then
print (" in << " .. line)
print (" out >> " .. message)
client:send(message .. "\n")
end
client:close()
end
main ()
client.lua
require("socket")
local message = "Hello Server!"
local host, port = "127.0.0.1", 1234
function main ()
local line, err, partial_line
local tcp = assert(socket.tcp())
tcp:connect(host, port)
print (" out >> " .. message)
tcp:send(message .. "\n")
line, err, partial_line = tcp:receive()
if not err then
print(" in << " .. (line or partial_line))
end
tcp:close()
end
main ()
Végül egy bonyolultabb beszélgető program, mely épít a Threading fejezetében bemutatottakra is:
client.lua
require("socket")
require("task")
local message = "Hello Server!"
local host, port = "127.0.0.1", 1234
local tcp = nil
local name = nil
function initTcpIp()
host, port = "127.0.0.1", 1234
tcp = assert(socket.tcp())
tcp:settimeout(0)
tcp:connect(host, port);
end
function initInputHandler ()
local tsk = task.create ("inputhandler.lua", {task.id()})
if tsk == -1 then
io.stdout:write( "-> Can't expand task list.\n" )
elseif tsk == -2 then
io.stdout:write( "-> Can't strdup file name.\n" )
elseif tsk == -3 then
io.stdout:write( "-> Can't create message queue.\n" )
elseif tsk == -4 then
io.stdout:write( "-> Can't create os thread.\n" )
elseif tsk == -11 then
io.stdout:write( "-> The library seems corrupt.\n" )
else
io.stdout:write( "-> Task ", tsk, " started.\n" )
end
end
function readInput()
local buf, _, _ = task.receive( -0 )
return buf
end
function main()
while name == nil do
print ("What is Your name?")
name = io.read()
end
initTcpIp()
initInputHandler()
-- authenticating
tcp:send(name .. '\n')
local line, err, partial_line
while true do
message = readInput()
if message ~= nil then
print (" me > " .. message)
tcp:send(message .. "\n");
end
line, err, partial_line = tcp:receive()
-- if there is no problem then status should be nill
-- status can also be "closed" or "timoout"
if not err then
print((line or partial_line))
elseif err ~= "timeout" then
print ("connection " .. err)
break
end
end
tcp:close()
end
main()
inputhandler.lua
require("task")
function startReader (parent)
while 1 do
message = io.read()
task.post(parent, message)
end
end
if arg[1] ~= nil then
startReader (arg[1])
end
server.lua
require("socket")
-- create a TCP socket and bind it to the local host, at any port
-- local server = assert(socket.bind("*", 0))
local message = "usage:\n\t\\s - select a user to chat with\n\t\\l - list of all available user"
local server = nil
local ip, port = nil, nil
local clientsAndCoros = {}
local members = {}
function handleClient(client)
local line, err
local partner = nil
local partnerSocket = nil
local name = nil
-- firs message should be the name of the user
while true do
name, err = client:receive()
if name ~= nil then
if name == "" then
client:send("Your user name can not be empty" .. "\n")
clientsAndCoros[client] = nil
client:close()
return
elseif members[name] == nil then
members[name] = client
print (name .. " has come online")
break
end
end
client:send("This username is already in use" .. "\n")
clientsAndCoros[client] = nil
client:close()
return
end
client:settimeout(0)
while 1 do
-- receive the line
line, err = client:receive()
-- if there was no error, send it back to the client
if not err then
--print (" in << " .. line)
if string.sub(line, 1,2) == "\\c" then
partner = string.sub(line, 4)
if partner == name then
client:send("You cannot connect to your self" .. "\n")
partner = nil
end
elseif string.sub(line, 1,2) == "\\l" then
for member_name, _ in pairs(members) do
if member_name ~= name then
client:send(member_name .. "\n")
end
end
else
if partner ~= nil and members[partner] ~= nil then
members[partner]:send(" " .. name .. " > " .. line .. "\n")
--partnerSocket = members[partner]
--partnerSocket:send(name .. "> " .. line .. "\n")
else
client:send("You do not have a partner or your partner has disconnected recently\n" .. message .. "\n")
end
end
elseif err ~= "timeout" then
break
end
coroutine.yield()
end
print ("connection " .. err)
clientsAndCoros[client] = nil
client:close()
members[name] = nil
print (name .. " has gone offline")
end
function initTcpIp()
server = assert(socket.bind("*", 1234))
ip, port = server:getsockname()
server:settimeout(0)
end
function main()
initTcpIp()
print("Please connect the client to localhost on port " .. port)
while 1 do
local client = server:accept()
if client ~= nil then
--print ("A client has connected")
local coro = coroutine.create(handleClient)
clientsAndCoros[client] = coro
end
for iClient ,iCoro in pairs (clientsAndCoros) do
coroutine.resume(iCoro, iClient)
end
local nConnection = 0
for iClient ,iCoro in pairs (clientsAndCoros) do
nConnection = nConnection + 1
end
--print ("nConnection: " .. nConnection)
end
end
main()
Bővebben:
luasocket reference