Page 1 of 1

[SOLVED]How can I check if remote socket is terminated?

Posted: Thu Jul 13, 2023 2:40 pm
by norubal
I'm trying to implement simple server-client application.

Server(It's a lua script but it won't work on love itself):

Code: Select all

socket = require("socket")

function newset()
    local reverse = {}
    local set = {}
    return setmetatable(set, {__index = {
        insert = function(set, value)
            if not reverse[value] then
                table.insert(set, value)
                reverse[value] = table.getn(set)
            end
        end,
        remove = function(set, value)
            local index = reverse[value]
            if index then
                reverse[value] = nil
                local top = table.remove(set)
                if top ~= value then
                    reverse[top] = index
                    set[index] = top
                end
            end
        end
    }})
end

-- set socket
server = socket.bind("*", 12345)
server:settimeout(0)

-- create new set
set = newset()
-- insert server socket to set

while true do
	local client = server:accept()
	-- accept new connection
	if client ~= nil then
		set:insert(client)
		print("New client connected!! ".. client:getpeername())
		client:send("Hello!\n")
	end
	
	-- recieve from client
	for a = 1, #set do
		local readdata, err = set[a]:receive()
		if err then
			print("Client disconnected: " .. set[a]:getpeername() .. " Reason: " .. err)
			set[a]:close()
			set:remove(set[a])
		else
			if readdata ~= nil then
				local peer = set[a]:getpeername()
				print("[" .. peer .. "]: " .. readdata)
			end
		end
	end
end
Client:

Code: Select all

local socket = require "socket"
local timer = 0

function love.load()
	client = socket.connect("127.0.0.1", 12345)
	if client == nil then
		print("Couldn't connect to server...")
	else
		client:settimeout(0)
		print("Connected to server! " .. client:getpeername())
	end
end

function love.update(dt)
	if client ~= nil then
		local data_recv, err = client:receive()
		if data_recv ~= nil then
			print("Server sent a data: " .. data_recv)
		else
			if err ~= "timeout" then
				print("Oops. Something happened: " .. err)
				client:close()
				client = nil
			end
		end
		
		-- once in a 3 secs, send "Hi!\n" to server
		timer = timer + dt
		if timer >= 3 then
			timer = timer - 3
			client:send("Hi!\n")
			print("Send data to server: Hi!")
		end
	end
end
It's working as I intended - server can handle client connections and disconnections. Client will send "Hi!\n" to server for every 3 seconds.

The problem is: when I terminate server script with Ctrl+C with proper interrupt, client displays "Oops. Something happened: closed" properly. But when I terminate server without proper interrupt(like killing server process directly), client doesn't recognize as server closed and trying to keep sending data for every 3 seconds - which I don't want to do.

I checked luasocket reference manual, but I don't see any function can check socket's status (check if socket is connected or disconencted) / ping other side to check if connection is available / etc. How can I check if connection is available or not?

Re: How can I check if remote socket is terminated?

Posted: Thu Jul 13, 2023 8:16 pm
by Andlac028
It is usually handled with ping packets - packets, that are sent at regular intervals from one side to another and pack (for example client sends ping and when server received it, it cas send pong back, so you can get how long it took to connect to the server and get response and if other side is allive).

If you use TCP, you can just send from one side and check what send returns (if it send whole message, only part of message or nothing)

Re: How can I check if remote socket is terminated?

Posted: Fri Jul 14, 2023 1:04 am
by norubal
Solved by adding small amount of code below to client side. Thank you for everyone who checked and tried to help.

Code: Select all

			local result = client:send("Hi!\n")
			if result ~= nil then
				print("Send data to server: Hi! ")
			else
				print("Oops. Something happened: Can't send data to server.")
				client:close()
				client = nil
			end
client:send() returns nil if something's wrong and couldn't send data to other side, so I could handle if there's any error.

Re: How can I check if remote socket is terminated?

Posted: Fri Jul 14, 2023 3:22 pm
by dusoft
norubal wrote: Fri Jul 14, 2023 1:04 am Solved by adding small amount of code below to client side. Thank you for everyone who checked and tried to help.

Code: Select all

			local result = client:send("Hi!\n")
			if result ~= nil then
				print("Send data to server: Hi! ")
			else
				print("Oops. Something happened: Can't send data to server.")
				client:close()
				client = nil
			end
client:send() returns nil if something's wrong and couldn't send data to other side, so I could handle if there's any error.
Probably *pcall* is better to handle exceptions in network communication:
https://www.lua.org/pil/8.4.html

Re: How can I check if remote socket is terminated?

Posted: Fri Jul 14, 2023 11:04 pm
by Andlac028
dusoft wrote: Fri Jul 14, 2023 3:22 pm
norubal wrote: Fri Jul 14, 2023 1:04 am Solved by adding small amount of code below to client side. Thank you for everyone who checked and tried to help.

Code: Select all

			local result = client:send("Hi!\n")
			if result ~= nil then
				print("Send data to server: Hi! ")
			else
				print("Oops. Something happened: Can't send data to server.")
				client:close()
				client = nil
			end
client:send() returns nil if something's wrong and couldn't send data to other side, so I could handle if there's any error.
Probably *pcall* is better to handle exceptions in network communication:
https://www.lua.org/pil/8.4.html
If I remember correctly, client:send only returns i - index of last byte send, or nil + error message, it does not throw error, so using pcall is useless