How to correctly detect closed TCP connection

Hi,
I have been trying to implement a simple TCP server that sends periodically data to a created connection. Based on the manual I can implement a minimal working example as follows:

function write_data(sock)
    while isopen(sock)
        write(sock,"hello\n")
        sleep(1)
    end
    println("socket closed")
end

errormonitor(@async begin
           server = listen(2001)
           while true
               sock = accept(server)
               println("Accepted connection")
               errormonitor(@async write_data(sock))
           end
       end)

This works as expected. When I connect from different process, different language, it correctly accepts the connection and starts transmitting the data.

The problem I am having is when I close the connection from the different process (in julia close(sock)) the isopen(sock) still returns true thus the data are being still transmitted. This seems to be a wanted behaviour.

I have read upon the need to use eof(sock) and tried to rewrite the function writing the data as

function write_data(sock)
    while isopen(sock) && !eof(sock)
        write(sock,"hello\n")
        sleep(1)
    end
    println("socket closed")
end

But then it does not send anything as the call to eof(sock) is blocking and the other end does not transmit anything.

What is the correct way to handle remote connection drop in such a loop where I want to only transmit data while the connection is active? Is there something such as non blocking eof?

Thank you

2 Likes

One possible solution I have figured out is to use Channel to asynchronously wait on the eof.

function is_socket_eof(channel::Channel, sock)
    put!(channel, eof(sock))
end

function is_socket_closed(sock, eof_monitor::Channel)
    return !isopen(sock) || (isready(eof_monitor) && take!(eof_monitor))
end

function write_data(sock)
    eof_monitor = Channel((ch) -> is_socket_eof(ch, sock))
    while !is_socket_closed(sock, eof_monitor)
        write(sock,"hello\n")
        sleep(1)
    end
    println("socket closed")
end

This seems to correctly detect if the socket was closed remotely.

I am unsure why I do have to put the !isopen(sock) to the is_socket_closed function. Without it, I have found out that the condition in the while !is_socket_closed(...) would result to true and yet ‘isopen(sock)’ would be false resulting in an error when writing to the socket. Maybe something connected with the asynchronicity which I don’t fully understand yet.

If someone would have an idea for better solution, it would be appreciated.

3 Likes

I found another way which doesn’t block and seems to work: isreadable(sock). It returns true while the socket is open and false when it’s closed by the other end.

2 Likes