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
Ld: Using -Rpath,$Origin Inside a Shared Library (Recursive)
Does Ldd Also Show Dependencies of Dependencies
Bash Script to Detect When My Usb Is Plugged in and to Then Sync It with a Directory
.Htaccess Not Working (Mod_Rewrite)
Two File Descriptors to Same File
Bash: How to Tokenize a String Variable
Why Does Zookeeper Not Use My Log4J.Properties File Log Directory
Linux Shared Library That Uses a Shared Library Undefined Symbol
How to Get Coordinates of Touchscreen Rawdata Using Linux
Change Default Console Loglevel During Boot Up
How to Compile Simple C Program in Linux Mint 15
How to Write Integer to Binary File Using Bash
How to Count the Number of Characters in a Bash Variable
What Does It Mean to Say "Linux Kernel Is Preemptive"
Why Does Ps O/P List the Grep Process After the Pipe
Cmake_Prefix_Path Doesn't Help Cmake in Finding Qt5
/Proc/$Pid/Maps Shows Pages with No Rwx Permissions on X86_64 Linux
How to Find Out Mount/Partition a Directory or File Is On? (Linux Server)