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

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
Post Reply
User avatar
norubal
Party member
Posts: 137
Joined: Tue Jan 15, 2013 5:55 am

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

Post 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?
Attachments
client.love
(701 Bytes) Downloaded 91 times
server.lua
(1.41 KiB) Downloaded 81 times
Last edited by norubal on Fri Jul 14, 2023 1:04 am, edited 1 time in total.
Andlac028
Party member
Posts: 174
Joined: Fri Dec 14, 2018 2:27 pm
Location: Slovakia

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

Post 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)
User avatar
norubal
Party member
Posts: 137
Joined: Tue Jan 15, 2013 5:55 am

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

Post 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.
User avatar
dusoft
Party member
Posts: 655
Joined: Fri Nov 08, 2013 12:07 am
Location: Europe usually
Contact:

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

Post 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
Andlac028
Party member
Posts: 174
Joined: Fri Dec 14, 2018 2:27 pm
Location: Slovakia

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

Post 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
Post Reply

Who is online

Users browsing this forum: Ahrefs [Bot], Google [Bot] and 8 guests