Async Connect and Disconnect with Epoll (Linux)

Detect remote disconnect (half-close) when using asynchronous sockets in C/C++

The solution to this problem is to use poll() as defined in sys/poll.h. poll() will set the POLLHUP bit in a pollfd struct if a FIN has been received on the socket:

#include <sys/poll.h>

...

pollfd ufds[1];
ufds[0].fd = socketFd;
ufds[0].events = POLLIN;
int pollRes = poll(ufds, 1, 0);
if (pollRes == 1) {
if (ufds[0].revents & POLLHUP) {
std::cout << "Got FIN, closing socket." << std::endl;
shutdown(socketFd, SHUT_RDWR);
close(socketFd);
...
}
}

Erlang catch disconnect client

I presume u are using vanilla gen_tcp to implement your server.
In which case, acceptor process (the process you pass the Socket to) will receive a {tcp_closed, Socket} message when the socket is closed from the client end.

sample code from the erlang gen_tcp documentation.


start(LPort) ->
case gen_tcp:listen(LPort,[{active, false},{packet,2}]) of
{ok, ListenSock} ->
spawn(fun() -> server(LS) end);
{error,Reason} ->
{error,Reason}
end.

server(LS) ->
case gen_tcp:accept(LS) of
{ok,S} ->
loop(S),
server(LS);
Other ->
io:format("accept returned ~w - goodbye!~n",[Other]),
ok
end.

loop(S) ->
inet:setopts(S,[{active,once}]),
receive
{tcp,S,Data} ->
Answer = do_something_with(Data),
gen_tcp:send(S,Answer),
loop(S);
{tcp_closed,S} ->
io:format("Socket ~w closed [~w]~n",[S,self()]),
ok
end.

Using select() for non-blocking sockets to connect always returns 1

What do you expect select() to return? Consider that select() is normally used to wait for multiple file descriptors - if you were connecting two, how would you know which one succeeded/failed based purely on the return value of select? You wouldn't, obviously.

Which is why select() just tells you which file descriptors have changed in some way, and you're supposed to determine independently what that was. In the case of connect(), you should call getsockopt() to retrieve the result of the connection attempt. See this answer where I explain how to do a non-blocking connect().

How to wait on a error/close event for a socket with asyncio?

Your test program is flawed. A call to c.close() doesn't emulate the socket being closed by the other end, it closes your own file descriptor and makes it inaccessible. You can think of close(fd) as breaking the link between the number fd and the underlying OS resource. After that reading and polling fd becomes meaningless because the number no longer refers to anything. As a result, epoll() can't and won't report a closed file descriptor as "readable".

The way to test the condition you want to test is by having the other end close the connection. The easiest way to do that is by spawning another process or thread as a mock server. For example:

import asyncio, threading, socket, time

def start_mock_server():
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(('localhost', 10000))
s.listen(1)
def serve():
conn, addr = s.accept()
time.sleep(1)
conn.close()
s.close()
threading.Thread(target=serve).start()

async def main():
loop = asyncio.get_running_loop()
start_mock_server()

c = socket.create_connection(('localhost', 10000))
c.setblocking(0)

ev = asyncio.Event()
loop.add_reader(c.fileno(), ev.set)

print("waiting...")
await ev.wait()
print("done")

asyncio.run(main())


Related Topics



Leave a reply



Submit