www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Socket: Detect connection close

reply "nrgyzer" <nrgyzer gmail.com> writes:
Hi guys,

I'm experimenting with sockets and having trouble to detect when 
the remote side closes the connection. Here's my code:

// Client:
module client;

import std.socket;

void main()
{
	TcpSocket s = new TcpSocket();
	s.connect(new InternetAddress("localhost", 8080));
	SocketStream ss = new SocketStream(s);

	for (int i= 0; i < 10; i++)
	{
		ss.write(1);
		ss.flush();
	}
	ss.socket.shutdown(SocketShutdown.BOTH);
	ss.close();
}

// Server:
module server;

import std.sdio;
import std.socket;

void main()
{

	TcpSocket s = new TcpSocket(AddressFamily.INET);
	s.bind(new InternetAddress("localhost", 8080));
	s.blocking(false);
	s.listen(0);

	while(1)
	{
		try {
			Socket requestSocket = oSocket.accept();
			RequestThread rt = new RequestThread(requestSocket);
			rt.start();
		}
		catch (SocketAcceptException e)
		{
			Thread.yield();
		}
	}

	s.socket.shutdown(SocketShutdown.BOTH);
	s.close();

}

class RequestThread : Thread
{
	private {
		__gshared Socket s;

		void run()
		{
			ubyte[1] buffer;
			while(s.isAlive)
			{
				s.receive(buffer);
				writeln("receiving");
			}
			writeln("client closed connection");
		}

	}

	public this(Socket socket)
	{
		super(&run);
		s = socket;
	}
}

I know... dirty (really) dirty code, but it works , except that 
I'm in an endless loop and my server always prints "receiving". I 
never see "client closed connection" although the client sends 
only 10 int values. It seems that "s.isAlive" is always true. How 
can I detect when the client closes the connection (or how can I 
detect if the connection is broken)?

Thanks for any suggestions or ideas!
Mar 23 2014
next sibling parent reply "Casper =?UTF-8?B?RsOmcmdlbWFuZCI=?= <shorttail hotmail.com> writes:
In Java, the only way to know is to attempt to send something. I 
presume it's limited that way because the OS's don't provide more 
info, or because TCP itself does not tell if a connection has 
closed unless something is sent.

I could be wrong, but all my network code in other languages rely 
on sending stuff to register a closed connection. For connections 
that are open for a very long time with low throughput I send 
small packages regularly just to be sure it's still open.
Mar 23 2014
parent "Casper =?UTF-8?B?RsOmcmdlbWFuZCI=?= <shorttail hotmail.com> writes:
Also, SocketStream: http://dlang.org/phobos/std_socketstream.html

 Warning: This module is considered out-dated and not up to 
 Phobos' current standards. It will remain until we have a 
 suitable replacement, but be aware that it will not remain long 
 term.
I wouldn't write any code using it.
Mar 23 2014
prev sibling parent reply "Vladimir Panteleev" <vladimir thecybershadow.net> writes:
On Sunday, 23 March 2014 at 20:12:38 UTC, nrgyzer wrote:
 Hi guys,

 I'm experimenting with sockets and having trouble to detect 
 when the remote side closes the connection. Here's my code:

 // Client:
 module client;

 import std.socket;

 void main()
 {
 	TcpSocket s = new TcpSocket();
 	s.connect(new InternetAddress("localhost", 8080));
 	SocketStream ss = new SocketStream(s);

 	for (int i= 0; i < 10; i++)
 	{
 		ss.write(1);
 		ss.flush();
 	}
 	ss.socket.shutdown(SocketShutdown.BOTH);
 	ss.close();
 }

 // Server:
 module server;

 import std.sdio;
 import std.socket;

 void main()
 {

 	TcpSocket s = new TcpSocket(AddressFamily.INET);
 	s.bind(new InternetAddress("localhost", 8080));
 	s.blocking(false);
 	s.listen(0);

 	while(1)
 	{
 		try {
 			Socket requestSocket = oSocket.accept();
 			RequestThread rt = new RequestThread(requestSocket);
 			rt.start();
 		}
 		catch (SocketAcceptException e)
 		{
 			Thread.yield();
 		}
 	}

 	s.socket.shutdown(SocketShutdown.BOTH);
 	s.close();

 }

 class RequestThread : Thread
 {
 	private {
 		__gshared Socket s;

 		void run()
 		{
 			ubyte[1] buffer;
 			while(s.isAlive)
 			{
 				s.receive(buffer);
 				writeln("receiving");
 			}
 			writeln("client closed connection");
 		}

 	}

 	public this(Socket socket)
 	{
 		super(&run);
 		s = socket;
 	}
 }

 I know... dirty (really) dirty code, but it works , except that 
 I'm in an endless loop and my server always prints "receiving". 
 I never see "client closed connection" although the client 
 sends only 10 int values. It seems that "s.isAlive" is always 
 true. How can I detect when the client closes the connection 
 (or how can I detect if the connection is broken)?
You can determine when the connection was closed on the remote side by checking if s.receive returns an empty array.
Mar 23 2014
parent reply "nrgyzer" <nrgyzer gmail.com> writes:
On Monday, 24 March 2014 at 05:32:30 UTC, Vladimir Panteleev 
wrote:
 On Sunday, 23 March 2014 at 20:12:38 UTC, nrgyzer wrote:
 Hi guys,

 I'm experimenting with sockets and having trouble to detect 
 when the remote side closes the connection. Here's my code:

 // Client:
 module client;

 import std.socket;

 void main()
 {
 	TcpSocket s = new TcpSocket();
 	s.connect(new InternetAddress("localhost", 8080));
 	SocketStream ss = new SocketStream(s);

 	for (int i= 0; i < 10; i++)
 	{
 		ss.write(1);
 		ss.flush();
 	}
 	ss.socket.shutdown(SocketShutdown.BOTH);
 	ss.close();
 }

 // Server:
 module server;

 import std.sdio;
 import std.socket;

 void main()
 {

 	TcpSocket s = new TcpSocket(AddressFamily.INET);
 	s.bind(new InternetAddress("localhost", 8080));
 	s.blocking(false);
 	s.listen(0);

 	while(1)
 	{
 		try {
 			Socket requestSocket = oSocket.accept();
 			RequestThread rt = new RequestThread(requestSocket);
 			rt.start();
 		}
 		catch (SocketAcceptException e)
 		{
 			Thread.yield();
 		}
 	}

 	s.socket.shutdown(SocketShutdown.BOTH);
 	s.close();

 }

 class RequestThread : Thread
 {
 	private {
 		__gshared Socket s;

 		void run()
 		{
 			ubyte[1] buffer;
 			while(s.isAlive)
 			{
 				s.receive(buffer);
 				writeln("receiving");
 			}
 			writeln("client closed connection");
 		}

 	}

 	public this(Socket socket)
 	{
 		super(&run);
 		s = socket;
 	}
 }

 I know... dirty (really) dirty code, but it works , except 
 that I'm in an endless loop and my server always prints 
 "receiving". I never see "client closed connection" although 
 the client sends only 10 int values. It seems that "s.isAlive" 
 is always true. How can I detect when the client closes the 
 connection (or how can I detect if the connection is broken)?
You can determine when the connection was closed on the remote side by checking if s.receive returns an empty array.
Alright, that world work. But what about sending 10 Bytes, waiting some minutes (probably some hours) and sending 10 Bytes again. Is it possible to do this on the same Socket? My scenario is: I've one central server and multiple clients. The clients are connecting to the server and send (or request) some information. After that the clients are simply "sleeping" for an unknown time. For instance client 1 for 1 seconds, client 2 for 1 minute, client 3 for 1 hours and client 4 for 1 day. After that time they resend/request some more information from the server... my questions regarding this are: - When I client connects, the server creates a thread. How can I determine that I can terminate the thread because the connection is inactive (for instance because the client closed the connection or some connecting issues)? - How can the client check if the connection is alive? (If the connection isn't alive, I need to reconnect)
Mar 24 2014
parent "Vladimir Panteleev" <vladimir thecybershadow.net> writes:
On Monday, 24 March 2014 at 18:06:56 UTC, nrgyzer wrote:
 Alright, that world work. But what about sending 10 Bytes, 
 waiting some minutes (probably some hours) and sending 10 Bytes 
 again. Is it possible to do this on the same Socket?
Yes. Unless your socket is marked as non-blocking, the read operation will block until more data is available (or the connection gets closed).
 My scenario is: I've one central server and multiple clients. 
 The clients are connecting to the server and send (or request) 
 some information. After that the clients are simply "sleeping" 
 for an unknown time. For instance client 1 for 1 seconds, 
 client 2 for 1 minute, client 3 for 1 hours and client 4 for 1 
 day. After that time they resend/request some more information 
 from the server... my questions regarding this are:

 - When I client connects, the server creates a thread. How can 
 I determine that I can terminate the thread because the 
 connection is inactive (for instance because the client closed 
 the connection or some connecting issues)?
As mentioned previously, you know that the connection was closed cleanly on the remote side when receive returns an empty buffer.
 - How can the client check if the connection is alive? (If the 
 connection isn't alive, I need to reconnect)
You generally have to implement this yourself. Silence on the wire can mean two things: 1. No data is being sent; 2. Something is preventing data from being sent (lost packets, a peer was shut down or restarted, Internet routing changes, squirrel chewed through a wire). Generally network software implements "ping" packets that are sent occasionally (once every few seconds or minutes). If no "ping" packets are received throughout a certain interval, the connection is considered dead. TCP also has a "keepalive" option which does this for you, but it is an optional TCP feature and thus may or may not work.
Mar 24 2014