socket() not throwing an exception despite server not running - java

I have written a client to run on an android device (android 6) and when the server is up and running it connects, however when the server is down the socket() call should throw an exception however it doesn't.
I originally tried it using the NDK and ran into a very similar issue (Android NDK socket connect() returning 0 when it should fail whilst on 3g).
I am assuming this is a bug with android at this point but any insight into a solution or work around would be much appreciated.
The code in question:
public class Client implements Runnable{
private Socket socket;
private InetAddress IP;
private int port;
public Client(int port){
try {
this.IP = InetAddress.getByName(server ip);
}
catch(UnknownHostException e){
Log.d("App1", "Unknown Host, connection failed");
System.exit(1);
}
this.port = port;
Log.d("App1", "initialised");
}
#Override
public void run(){
try {
this.socket = new Socket(this.IP, this.port);
Log.d("FiX1", "Connected");
listen();
}
catch(IOException e){
Log.d("FiX1,","connection failed");
System.exit(1);
}
finally
{
try{
socket.close(); // dispose
}
catch(IOException e){
System.exit(1);
}
}
}
public void listen() {
try {
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
while (true) {
String cominginText = "";
try {
cominginText = in.readLine();
Log.d("FiX1",cominginText);
} catch (IOException e) {
//error ("System: " + "Connection to server lost!");
System.exit(1);
break;
}
}
} catch (IOException e) {
System.exit(1);
}
}
}

The best solution I could find was to manually send an acknowledgement from the server that a connection had been made, the client would retry the connection if it did not receive this message within a certain time after it claimed to have connected.

There is a difference between a TCP connection "close" vs "disconnect".
If you close the socket connection from server using socket.close() then you will get exception in client side, if you try to read from that connection or vice versa.
However, if one side just disappears(shut down the program) then the other side has no way of knowing that. So the other side will wait for response for read call.
The TCP protocol was designed to be reliable in hostile communication environments and it will not normally decide a connection is closed just because it has not heard from the other side for a while.

Related

How to reconnect to a Server automatilly when server availble in java sockets

I have java client server application. Server is running or may not be connected. but we need to connect with ip and port.
Socket s=new Socket(ip,port);
if it is connected, socket will be created, else it throws IOException. then i will set a status of that connection as not connected in an object.
if connected, i will send data as commands. It will respond to that command with data. We send commands with output stream and read responce with input-stream of the socket.
I need to automatically reconnect to the server when server is available (wired or wifi connection).
How to Use Multi threading here
ex:
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
public class ConnectionThread implements Runnable {
static class ConnectionStatus {
boolean connected = false;
public boolean isConnected() {
return connected;
}
public void setConnected(boolean connected) {
this.connected = connected;
}
}
ConnectionStatus status;
Socket socket;
String ip;
int port;
public ConnectionThread(ConnectionStatus status, String ip, int port) {
this.status = status;
this.ip = ip;
this.port = port;
}
public void connectAgain() throws IOException {
while (!status.isConnected()) {
socket = new Socket(ip, port);
status.setConnected(true);
}
}
public void run() {
try {
connectAgain();
} catch (IOException e) {
try {
Thread.sleep(1000);
connectAgain();
} catch (InterruptedException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
public static void main(String[] args) {
ConnectionStatus status = new ConnectionStatus();
status.setConnected(false);
ConnectionThread cthread = new ConnectionThread(status, "192.166.102.201", 1986);
Thread x = new Thread(cthread);
x.start();
System.out.println("Connected ..." + status.isConnected());
}
}
I need to send commands (data) only when connected to receive response.
I need to set the connected status to false when not connected
and to true when connected.
Based on connected status i will read from socket or write to socket steams.
I need to know when the connection is failed
and when the connection is available.
I think better to use propertychangelistener when connected property is changed.
is it right?
This loop really has no point.
while (!status.isConnected()) {
socket = new Socket(ip, port);
status.setConnected(true);
}
Whether it succeeds or fails it can never execute the loop more than once. It has exactly the same effect as just this:
socket = new Socket(ip, port);
status.setConnected(true);
The run will call this twice with a 1 second delay unless it doesn't throw an exception and succeeds. If you want it to keep trying until you connect, you need to catch the exception within the loop. eg
Socket s = new Socket();
SocketAddress sa = new InetSocketAddress("192.166.102.201", 1986);
while (!s.isConnected()) {
try {
s.connect(sa); // try the connection
} catch (IOException ex) {
// ignore we may have to try lots of times
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
// not sure how to handle this, maybe we should just give up.
}
}
}
Update: I had both the sleep and the connect in the same try block which meant it would never sleep but just keep the thread always busy. Moved the sleep to separate block.

When using ServerSockets and Sockets, the BufferedReader hangs and it appears the connection doesn't form properly

EDIT: I have corrected the mistake below in the code, by adding a line into the server code
I'm trying to write some socket code that will allow me to send data from one computer to another for a game (which for simplicity's sake, we can think of as tic-tac-toe, not much data needs to be sent, just a couple of numbers). In order to achieve this I have written two classes, Server and Client. At the moment I am testing through the localhost using port 1234, and I am only using one single instance of the program (though the same problem occurs when trying to use two instances).
Firstly here's the code, and then I can go into more depth about the problem, and what testing I've done to attempt to work out what is going wrong:
public class Server
{
private ServerSocket server;
private Socket socket;
private Client socketHandler;
private static final int DEFAULT_PORT = 1234;
public Server() { this(DEFAULT_PORT); }
public Server(int port)
{
Thread thread = new Thread()
{
public void run()
{
try
{
System.out.println("Attempting to Establish Connection");
server = new ServerSocket(port);
socket = server.accept();
socketHandler = new Client(port, socket); //THIS LINE ADDED
System.out.println("Server Online!");
}
catch (Exception e)
{
e.printStackTrace();
}
}
};
thread.setDaemon(true);
thread.start();
}
//ADJUSTED
Client getSocketHandler()
{
return socketHandler;
}
public void kill()
{
try
{
if (socket != null) socket.close();
if (server != null) server.close();
}
catch(IOException e)
{
e.printStackTrace();
}
finally
{
socket = null;
server = null;
}
}
}
public class Client
{
public static final int DEFAULT_PORT = 1234;
public static final String DEFAULT_HOST = "localhost";
private static final String THUMP_THUMP = "thump thump";
private static final int PULSE = 1000;
private int port;
private String ip;
private Socket socket;
private BufferedReader input = null;
private PrintWriter output = null;
boolean closed = true;
String data = "";
public Client() { this(DEFAULT_PORT, DEFAULT_HOST, null); }
public Client(int port) { this(port, DEFAULT_HOST, null); }
public Client(int port, String ip) { this(port, ip, null); }
public Client(int port, Socket server) { this(port, DEFAULT_HOST, server); }
public Client(String ip) { this(DEFAULT_PORT, ip, null); }
public Client(String ip, Socket server) { this(DEFAULT_PORT, ip, server); }
public Client(Socket server) { this(DEFAULT_PORT, DEFAULT_HOST, server); }
public Client(int port, String ip, Socket server)
{
socket = server;
this.ip = ip;
this.port = port;
Thread thread = new Thread()
{
public void run()
{
try
{
initialise(server);
String line;
startHeartbeat();
while (isClosed()) {} //first it is closed, lets wait for it to open before we start waiting for it to close!
System.out.println("We are about to listen!");
while (!isClosed())
{
System.out.println("pre-read"); //this line was used to determine that the code was hanging on the next line
line = input.readLine(); //offending line
System.out.println("post-read"); //this line was used to determine when the block was lifted
if (line != null)// || line != THUMP_THUMP)
{
System.out.println(line);
data += line + "\n";
}
}
System.out.println(data);
kill();
System.out.println("Connection Closed!");
}
catch (SocketException e)
{
e.printStackTrace();
System.out.println("Server closed!");
}
catch (Exception e)
{
e.printStackTrace();
}
}
};
thread.setDaemon(true);
thread.start();
}
private void initialise(Socket server)
{
try
{
if (server == null) socket = new Socket(ip, port);
input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
output = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
}
catch (IOException e) { e.printStackTrace(); }
}
public boolean post(String text)
{
synchronized(this)
{
output.println(text);
output.flush();
return !output.checkError();
}
}
public void kill()
{
try
{
if (input != null) input.close();
if (socket != null) socket.close();
}
catch(IOException e) { e.printStackTrace(); }
finally
{
input = null;
socket = null;
}
}
public void killOutputStream()
{
try
{
if (output != null) output.close();
}
catch (Exception e) { e.printStackTrace(); }
finally
{
output = null;
}
}
//////////////////////////////////
///////// Socket Control /////////
//////////////////////////////////
synchronized boolean isClosed()
{
return closed;
}
synchronized void setClosed(boolean b)
{
closed = b;
}
//We need to make sure that the socket is still online, to ensure the reading stops when the connection closes.
void startHeartbeat()
{
Thread heartbeat = new Thread()
{
public void run()
{
while (output != null)
{
setClosed(post(THUMP_THUMP) ? false : true); //post returns true on success
synchronized(this)
{
try
{
this.wait(PULSE);
}
catch (InterruptedException e) {}
}
}
setClosed(true);
}
};
heartbeat.setDaemon(true);
heartbeat.start();
}
}
The Problem
When the client is started (after having created the server) it fails to read any data sent through (or even the heartbeat), in fact the code does not go past line = input.readLine() in the reading thread (which is from now on called the offending line), except it seems, until the server is disconnected (see below).
Here is the order of regular testing:
Server() is called and the resulting Server is stored in the serverConnection variable then
Client(serverConnection != null ? serverConnection.getSocket() : null) is called and the new Client is stored in clientConnection.
Because we can test whether it is working using the heartbeat no other data needs to be sent, and the server is terminated by calling serverConnection.kill() and then clientConnection.killOutputStream() after letting some time elapse.
and this is the result:
Attempting to Establish Connection Server Online!
We are about to listen!
Connection Closed!
where the empty line represents the non null data received over the course of the connection, ie that there is none.
I expect this:
Attempting to Establish Connection
Server Online!
We are about to listen!
thump thump
thump thump
thump thump (and so on, every second)
Connection closed!
I spent time performing different tests by commenting out or changing the code slightly with the same testing format (except for the special case, which is number 6) and made these observations:
Observations
Only when the socket is closed and the output stream is closed, does the program move past the offending line.
When the readline() method starts to process (shortly before the heartbeat cuts it off) it detects nothing in the stream, not even THUMP_THUMP.
When the socket is closed, but the output stream is not, the readline() method starts to process, only to detect nothing, heartbeat cuts it off. No SocketException even though it would be expected.
If the socket is NOT closed, and only the output stream is closed, a SocketException is triggered, suggesting the socket is closed.
I used netstat -an in command prompt, and when the server is started the port 1234 is LISTENING. When the client connects, it is still LISTENING, implying that there is no connection.
I set up some python code to connect to itself over port 1234,
however I made a mistake in the python code, and as such the server
didn't close, and was still open. So I decided to connect the java
client to the server and see what happens. I did this by running
Client(null) which is the client code for the non-host. It
resulted in the port reading ESTABLISHED, and the python server was
echoing back the "thump thump", and the java code was successfully
reading it. No hanging, it worked perfectly.
This leads me to believe that the problem lies in the server code, as the python server was able to communicate sucessfully with the Java client, but the Java client is unable to communicate with the Java server.
Before performing this testing I had been concentrating on the Client code, believing that it was at fault. All the questions I have found here with similar symptoms (see here, here and here, among others) have turned up blank for me, having written in their solutions (most were due to the output stream not flushing, or the \n ommitted, which I have not failed to do, or the solution not fixing my problem, and so having been removed in favor of the heartbeat in this case). I originally based my code off of this article.
After 4 days of trying to figure out this problem I am at a loss for what to do... What am I missing here? Why is the Server code not working as I expect it to? If anybody needs any more clarification on my code then please ask!
As an after-note, the testing code is run through a simple minimalistic GUI written in javafx (not fxml though), whether that would be a problem or not I'm sure, I would think not, due to it working with the Python server. This code is compiled in Java 8
I'm a little confused about why you think it would go any furthur than input.readLine() considering there is no handling of inputs/outputs on the server side....
Client/Server connections are like a game of tennis, as one side serves the other must receive the ball and then serve it back(maybe with different information). Your server side must handle the input it recieves from the start heartbeat method, and then send you back a response. the input.readLine() function blocks the thread until it receives data from the other end, so yes the code stops there and waits for your server to send the "tennis ball" back. In the server class you should add an input and output stream that handle the heart beat inputs and send back a string of data to the client.
Server:
OutputStream os = socket.getOutputStream();
InputStream is = socket.getInputStream();
String response = "thump thump";
while(true){
is.read();
os.write(response.getBytes());
os.flush();
}
with this example, the client should remain unchanged and just add the above code to your server.

Server hangs when client disconnects

i am creating a multiple-client/server app whenever any client disconnects from
my server it just hangs.
how can i set any condition that will tell me print some message whenever
any client disconnects from the server
here is my server code
class ServerThread implements Runnable {
public void run() {
Socket socket = null;
try {
System.out.println("server starting.......");
serverSocket = new ServerSocket(SERVERPORT);
} catch (IOException e) {
e.printStackTrace();
}
while (!Thread.currentThread().isInterrupted()) {
try {
System.out.println("Ready to accept.......");
socket = serverSocket.accept();
System.out.println(" client Connected with ip address =" +socket.getRemoteSocketAddress().toString());
CommunicationThread commThread = new CommunicationThread(socket);
new Thread(commThread).start();
} catch (IOException e) {
e.printStackTrace();
System.out.println("catch block");
}
}
}
}
class CommunicationThread implements Runnable {
private Socket clientSocket;
private BufferedReader input;
public CommunicationThread(Socket clientSocket) {
this.clientSocket = clientSocket;
try {
this.input = new BufferedReader(new InputStreamReader(this.clientSocket.getInputStream()));
} catch (IOException e) {
e.printStackTrace();
}
}
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
String read = input.readLine();
updateConversationHandler.post(new updateUIThread(read));
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
any help will be appreciated
It's not clear whether you mean disconnect because the conversation was over (ie: everything completed successfully) or the disconnect is because of some network problems (or the client canceled the request).
If it's the first case, then it's easy: the protocol you are using (your own, or http, or whatever) is in charge of defining how to determine that a conversation was over. If that situation arises, then you just close the socket.
If it's the second case, then you'd have to have an algorithm in place to determine whether or not the connection must be closed. For instance, by implementing a timeout, or a slow-read threshold. Take a look at the Socket's javadoc for instructions on how to set a timeout.
It's also worth noting that it's fine to create your own servers when you want to practice or learn something, but you'd be better off using an existing solution, like vert.x or a slimmed down version of Wildfly, for instance. The overhead of such servers is very low, nowadays, while still providing very robust networking capabilities.

TCP Hole Punching and setReuseAddress() on Linux

I am working on a Java client/server application that involves P2P communication over TCP. I'm trying to implement TCP Hole Punching as described here: http://www.brynosaurus.com/pub/net/p2pnat/#sec-tcp. This requires simultaneously listening on and attempting to establish an outgoing connection using the same local TCP port. Apparently, this should work if the SO_REUSEADDR socket option is used, which I am setting via the setReuseAddress() method in Java. However, this is not working as I expected. Here is some test code:
import java.io.IOException;
import java.net.*;
public class Test {
public static void main(String args[]) {
new Thread() {
public void run() {
try {
ServerSocket ss = new ServerSocket();
ss.setReuseAddress(true);
ss.bind(new InetSocketAddress(7077));
ss.accept();
} catch (Exception e) {
System.out.println("ServerSocket exception: " + e.getMessage());
}
}
}.start();
Socket s;
while (true) {
s = new Socket();
try {
s.setReuseAddress(true);
s.bind(new InetSocketAddress(7077));
s.connect(new InetSocketAddress("192.168.0.103", 7077));
break;
} catch (Exception e) {
System.out.println("Socket exception: " + e.getMessage());
try { s.close(); } catch (IOException e1) { }
try { Thread.sleep(1000); } catch (InterruptedException e1) { }
}
}
}
}
This works as expected in Windows 7: the ServerSocket listens on port 7077 in its own thread and the Socket repeatedly attempts to connect to 192.168.0.103:7077. However, under Linux (Ubuntu) only the first Socket connection attempt works, and subsequent attempts get the "Address already in use" BindException. Shouldn't I be able to establish an outgoing connection from a TCP source port that I'm also listening on simultaneously, and to reuse the local port number immediately after closing the socket, since I have the SO_REUSEADDR option enabled?
In Linux, both sockets need to set SO_REUSEADDR socket option. Thus, if we want two sockets, sock1 and sock2 to be bound ot the same port, then s2 would be able to reuse the port/address only if both sock1 and sock2 set SO_REUSEADDR.
You are never closing your client socket, unless there is an exception, making the point of SO_REUSEADDR a no-op.
....
s = new Socket();
try {
// ...
} catch (Exception e) {
System.out.println("Socket exception: " + e.getMessage());
// remove try block from here
try { Thread.sleep(1000); } catch (InterruptedException e1) { }
} finally {
try { s.close(); } catch (IOException e1) { }
}
....
In the above, I moved the closing of the socket to a newly created finally block so it is always executed, even if you break out the global while loop.
Since the socket is now closed under all conditions, the SO_REUSEADDR will use correctly now.

How to detect when a client has disconnected from a server

I have a program running on a server (Server A) which listens on one port for an external connection (from an external server, B), then listens on another port for an internal connection on the same server (Server A). It then passes data from the internal to external connection and back again.
I want to know if there is a way I can detect that the client external was disconnected. I just need one external connection at a time, but I would like to be able to accept a new one if the external client reboots or something like that.
This socket level stuff is all fairly new to me, so if there is a better way of going about this, I'm all ears. The one stipulation is that the client running on Server B must be the one to initiate the connection and the connection must live for as long as possible.
public void handleConnection() {
System.out.println("Waiting for client message...");
try {
SSLSocket extSocket = (SSLSocket) this.externalServerSocket.accept();
ObjectInputStream externalOis = new ObjectInputStream(extSocket.getInputStream());
ObjectOutputStream externalOos = new ObjectOutputStream(extSocket.getOutputStream());
System.out.println("Client connection establisthed");
// Loop here to accept all internal connections
while (true) {
SSLSocket internalSocket = (SSLSocket) this.internalServerSocket.accept();
new ConnectionHandler(externalOis, externalOos, internalSocket);
}
} catch (IOException e) {
System.err.println(e.getMessage());
return;
}
}
class ConnectionHandler implements Runnable {
private SSLSocket internalSocket;
private ObjectOutputStream internalOos;
private ObjectInputStream internalOis;
private ObjectInputStream externalOis;
private ObjectOutputStream externalOos;
public ConnectionHandler(ObjectInputStream externalOis,
ObjectOutputStream externalOos, SSLSocket internalSocket) {
this.internalSocket = internalSocket;
try {
this.internalOis = new ObjectInputStream(this.internalSocket.getInputStream());
this.internalOos = new ObjectOutputStream(this.internalSocket.getOutputStream());
this.externalOis = externalOis;
this.externalOos = externalOos;
} catch (IOException e) {
System.err.println(e.getMessage());
}
new Thread(this).start();
}
#Override
public void run() {
try
{
// process data
Object o = internalOis.readObject();
externalOos.writeObject(o);
Object o2 = externalOis.readObject();
internalOos.writeObject(02);
internalOos.close();
internalOis.close();
this.internalSocket.close();
} catch (IOException e) {
System.err.println(e.getMessage());
} catch (ClassNotFoundException e) {
System.err.println(e.getMessage());
}
}
}
If the client disconnects, readObject() will throw EOFException, and write() will throw an IOException: connection reset. That's all you need.

Categories