My socket keeps closing after socket.connect times out - java

This is driving me insane!
I'm trying to implement TCP holepunching and as part of this I have a socket trying to connect continuously.
For some reason, after the first mobileSocket2.connect call times out, the second time a socket closed exception comes up. I have no idea why. As far as I can tell, a connection timeout shouldn't close the socket. so why does it say socket closed the second loop?
I bind a socket to the same local IP address and local port earlier on but close that socket.
Any help would be greatly appreciated.
Socket mobileSocket2 = new Socket();
try {
System.out.println("105");
mobileSocket2.setReuseAddress(true);
System.out.println("109");
mobileSocket2.setSoTimeout(50);
mobileSocket2.bind(new InetSocketAddress(myIPAddress.getHostAddress(), myPort));
System.out.println("bound");
}
catch (Exception e) {
System.out.println("caught 104: " + e.toString());
}
while(true){
Thread.sleep(5000);
try{
System.out.println("124");
mobileSocket2.connect(new InetSocketAddress(mobileAddress.getHostAddress(), mobilePort));
System.out.println("connection made: " + mobileSocket);
}
catch(Exception e){
System.out.println("exception 2 caught " + e.toString());
}
}

Your code is invalid.
You can't reconnect a connected Socket. When the connect succeeds you need to add a break statement.
You can't reuse a Socket when a connect() has failed. You have to close it and create a new one.

Either reopen the socket when the first exception is caught, or set the timeout to 0, which the javadoc says it is interpreted as 'infinite'. I didn't look at the Socket and SocketImpl code, but I'm fairly confident that, since Socket is a Closeable (and also an AutoCloseable), the implementation is along the lines of
public void connect(InetAddress address, int port) throws IOException {
try {
// connect to the other endpoint
} catch(/*any relevant exception*/) {
throw new IOException(/* ... */);
} finally {
this.close();
}
}

Related

Continuously connecting to a server via a Socket until a connection is established

I have a client that I want to try to continuously connect to a server until a connection is established (i.e. until I start the server).
clientSocket = new Socket();
while (!clientSocket.isConnected()) {
try {
clientSocket.connect(new InetSocketAddress(serverAddress, serverPort));
} catch (IOException e) {
e.printStackTrace();
}
// sleep prevents a billion SocketExceptions from being printed,
// and hopefully stops the server from thinking it's getting DOS'd
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
After the first attempt, I get a ConnectionException; expected, since there is nothing to connect to. After that, however, I start getting SocketException: Socket closed which doesn't make sense to me since clientSocket.isClosed() always returns false, before and after the connect() call.
How should I change my code to get the functionality I need?
You can't reconnect a Socket, even if the connect attempt failed. You have to close it and create a new one.

Java message is sent to a closed socket

I have a client program that sends messages typed in console to the server. Following some advices, I introduced a check for a closed socket with Socket.checkError(). Nevertheless, for some reason it indicates error only after second failed attempt to send a message.
My code:
BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in));
while (true)
try (
Socket clientSocket = new Socket(hostname, port);
PrintWriter socketOut = new PrintWriter(clientSocket.getOutputStream(), true);
) {
String input;
while ((input=stdIn.readLine())!=null) {
socketOut.println(input);
if (socketOut.checkError()) {
System.out.println("Got socket error");
break;
}
}
} catch (IOException e) {
try {
Thread.sleep(5000);
} catch (InterruptedException e1) {}
}
I shut down (manually) my server side after receiving 'message1'. Therefore, I expect to get the error while trying to send the very next message. Nevertheless it occurs only one message after:
message1
message2
message3
Got socket error
Can anyone explain this behavior and advise me a method to get notification right on the first attempt to send a message in void?
Following some advices, I introduced a check for a closed socket with Socket.checkError().
There is no such method. Clearly you are referring to PrintWriter.checkError().
Nevertheless, for some reason it indicates error only after second failed attempt to send a message.
The reason is that there is both a socket send buffer at the sender and a socket receive buffer at the receiver, and that sending is asynchronous: it therefore isn't possible for the first send to detect an error.
Can anyone explain this behavior and advise me a method to get notification right on the first attempt to send a message in void?
There isn't one. That's the nature of TCP. What you are attempting indicates an application protocol error, and the answer lies in the realm of the application protocol as well: don't have the peer close the socket while this end could still be sending data, OR don't allow this end to send data after the peer has indicated, via the application protocol, that it won't be reading any more data.
Don't use PrintWriter over the network. It suppresses the actual exception. Use BufferedWriter and the write() and newLine() methods.
In ths java library there is no method to check if connection is opened or not. Method like isConnected() and isClosed() check only one side of the connection (where you invoked the method).
From javadoc:
Note: Closing a socket doesn't clear its connection state, which means
this method will return true for a closed socket (see isClosed()) if
it was successfuly connected prior to being closed.
To check if the connection has been really closed simply invoke the read() method (or equivalent) and check if it returns -1.
Note: also if isConnected will work as you like (giving false if the other side of the socket closed the connection or if there is a network problem or similar) the sequence:
if (socket.isConnected()) {
int x = socked.read();
}
will not grant that the x has a value different from -1 or throws an IOException, because the connection could be closed after the isConnected test and before the read operation.
The following code to show how any kind of check on the socket cannot guarantee that a subsequent read will give a valid result.
// Return true because socket communication is enabled
if (myFunctionToCheckIfSocketIsOpen(socket)) {
// Here the peer closed the socket or the network shutdown
// This read will give -1 or throws IOException also if the previous check returned true
int x = socket.read();
}
From the answer of #Davide Lorenzo MARINO I got the idea of employing read(). The only problem that it is blocking. However, one can always run it in another thread, which would modify a class global variable, when read() finally returns -1:
static boolean socketIsAlive;
...
BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in));
while (true)
try (
Socket clientSocket = new Socket(hostname, port);
PrintWriter socketOut = new PrintWriter(clientSocket.getOutputStream(), true);
) {
socketIsAlive=true;
new ConnectionChecker(clientSocket).start();
String input;
while (true) {
if ((input=stdIn.readLine())!=null)
socketOut.println(input);
if (!socketIsAlive) {
System.out.println("Got socket error");
break;
}
}
} catch (IOException e) {
try {
Thread.sleep(5000);
} catch (InterruptedException e1) {}
}
}
...
static public class ConnectionChecker extends Thread{
Socket socket;
public ConnectionChecker(Socket socket) {
this.socket=socket;
}
#Override
public void run() {
try {
if (socket.getInputStream().read()==-1)
socketIsAlive=false;
} catch (IOException e) {}
}
}

Android client - Java server, Socket won't throw exception

I'm trying to connect my Android APP to a Java server that I've made for it.
I have a problem, the server works good and the APP works fine too when connected to the server.
The problem comes when I close the server and try to connect to it. The suppose is that the Socket.connect() would throw an exception that I would catch, but this exception is not thrown.
I don't know what I'm doing bad, I paste my code here for you to read and maybe somone can help me. Thanks for all mates :D
Connection attributes:
static Socket s;
static DataOutputStream output;
static boolean connected;
The method who needs the connection:
public void enviarDatos(int r, int g, int b){
connect();
if(connected){
panel.setText(panel.getText() + "\nEnviando datos...");
try {
output.writeUTF(r + "," + g + "," + b);
} catch (Exception e) {
panel.setText("Error: " + e.getMessage());
}
disconnect();
}
}
The methods to connect and disconnect are there:
public void connect(){
try {
s = new Socket();
int timeout = 1000;
s.connect(new InetSocketAddress(SERVER_ADDRESS, SERVER_PORT), timeout);
output = new DataOutputStream(s.getOutputStream());
connected = true;
panel.setText("Conexion exitosa.");
} catch (Exception e) {
connected = false;
panel.setText("Error: " + e.getMessage());
}
}
public void disconnect(){
try{
output.close();
s.close();
connected = false;
} catch(Exception e){
panel.setText("Error: " + e.getMessage());
}
}
The first connect() method is different from the one you posted in the large code block where you present both the methods. It's pretty unclear which one you are using to connect. Try adding the int timeout parameter to the connect() like this:
int timeout = 1000; // 1s timeout
s.connect(new InetSocketAddress(SERVER_ADDRESS, SERVER_PORT), timeout);
This should make connect throw an IOException after the timeout expires.
Hope this solves your problem.
I see one potential issue in "disconnect". I think you're trying to close the socket when the output stream is still opened. In this case, the socket may not close properly which may cause issues in reopening. Although you should see an exception being thrown during closing.
In disconnect(), can you try closing output first before closing the socket?
public void disconnect(){
try{
output.close();
s.close();
connected = false;
} catch(Exception e){
panel.setText("Error: " + e.getMessage());
}
}
I don't have the context of this problem, but that's one potential issue I saw. Hopefully it helps.

Socket programming. Program creating 2 connections instead of just 1

I am building a client/server application, for some socket programming exercise.
Below is construction + run method of my server class. The server awaits a respond from the client, which in this case is just a string.
The problem is that it seems to make two connections when the client respond. From my print statements i can see that all the code in the run method is run twice, and then the first line once again.
Why would dateServer.accept(); accept a connection for only one client request?
public Server() throws Exception {
dateServer = new ServerSocket(3001);
System.out.println("Server lytter på port 3000.");
this.start();
}
public void run() {
while (true) {
try {
System.out.println("waiting for client to request");
Socket client = dateServer.accept();
System.out.println("connection established");
Connect c = new Connect(client);
clients.add(c);
this.sleep(5000);
} catch (Exception e) {
}
}
}
--EDIT--
Client code that talks to server (Message is a simple "wrapper" class"):
System.out.println("Write to server:");
String name = scanner.nextLine();
Message message = new Message(name, null);
oos.writeObject(message);
oos.flush();
If all the prints happen twice there must have been two connections. The first line prints again after that because you're in a loop.
NB:
Never ignore exceptions: especially IOExceptions.
The sleep is completely pointless. accept() will block while there are no incoming connections. You are literally wasting time here.

Checking if a ClientSocket has disconnected in java hangs

This is a follow up to:
this question
Basically, I have a server loop that manages a connection to one solitary client. At one point in the loop, if a ClientSocket exists it attempts a read to check if the client is still connected:
if (bufferedReader.read() == -1) {
logger.info("CONNECTION TERMINATED!");
clientSocket.close();
setUpSocket(); // sets up the server to reconnect to the client
} else {
sendHeartBeat(); // Send a heartbeat to the client
}
The problem is, that once a socket has been created the application will hang on the read, I assume waiting for data that will never come, since the client never sends to the server. Before this was OK, because this correctly handled disconnects (the read would eventually fail when the client disconnected) and the loop would attempt reestablish the connection. However, I now have added the above sendHeartBeat() method, which periodically lets the client know the server is still up. If the read is holding the thread then the heartbeats never happen!
So, I assume I am testing if the connection is still up incorrectly. I could, as a quick hack, run the bufferedReader.read() in a seperate thread, but then I'll have all sorts of concurrency issues that I really don't want to deal with.
So the question is a few fold:
Am I checking for a client disconnect correctly?
If not, how should I do it?
If I am doing it correctly how I do I get the read to not hold the process hostage? Or is threading the only way?
When you create your socket, first set a timeout:
private int timeout = 10000;
private int maxTimeout = 25000;
clientSocket.setSoTimeout(timeout);
With this, if a read times out you'll get java.net.SocketTimeoutException (which you have to catch). Thus, you could do something like this, assuming you've previously set the SO_TIMEOUT as shown above, and assuming that the heartbeat will always get a response from the remote system:
volatile long lastReadTime;
try {
bufferedReader.read();
lastReadTime = System.currentTimeMillis();
} catch (SocketTimeoutException e) {
if (!isConnectionAlive()) {
logger.info("CONNECTION TERMINATED!");
clientSocket.close();
setUpSocket(); //sets up the server to reconnect to the client
} else {
sendHeartBeat(); //Send a heartbeat to the client
}
}
public boolean isConnectionAlive() {
return System.currentTimeMillis() - lastReadTime < maxTimeout;
}
A common way of handling this is setting the timeout to some number (say 10 seconds) and then keeping track of the last time you successfully read from the socket. If 2.5 times your timeout have elapsed, then give up on the client and close the socket (thus sending a FIN packet to the other side, just in case).
If the heartbeat will not get any response from the remote system, but is just a way of ultimately generating an IOException earlier when the connection has fallen down, then you could do this (assuming that the sendHeartBeat itself will not throw an IOException):
try {
if (bufferedReader.read() == -1) {
logger.info("CONNECTION TERMINATED with EOF!");
resetConnection();
}
} catch (SocketTimeoutException e) {
// This just means our read timed out ... the socket is still good
sendHeartBeat(); //Send a heartbeat to the client
} catch (IOException e) {
logger.info("CONNECTION TERMINATED with Exception " + e.getMessage());
resetConnection();
}
....
private void resetConnection() {
clientSocket.close();
setUpSocket(); //sets up the server to reconnect to the client
}
You are checking correctly, you can should add a try catch with IOException in case it occurs.
There is a way to avoid threading, you can use a Selector with a non-bloking socket.
public void initialize(){
//create selector
Selector selector = Selector.open();
ServerSocketChannel acceptSocket = ServerSocketChannel.open();
acceptSocket.configureBlocking(false);
String bindIp = "127.0.0.1";
int bindPort = 80;
acceptSocket.socket().bind(new InetSocketAddress(bindIp, bindPort));
//register socket in selector for ACCEPT operation
acceptSocket.register(selector, SelectionKey.OP_ACCEPT);
this.selector = selector;
this.serverSocketChannel = serverSocketChannel;
}
public void serverStuff() {
selector.select(maxMillisecondsToWait);
Set<SelectionKey> selectedKeys = selector.selectedKeys();
if( selectedKeys.size() > 0 )
{
if( key.isAcceptable() ){
//you can accept a new connection
SocketChannel clientSk = serverSocketChannel.accept();
clientSk.configureBlocking(false);
//register your SocketChannel in the selector for READ operations
clientSk.register(selector, SelectionKey.OP_READ);
} else if( key.isReadable() ){
//you can read from your socket.
//it will return you -1 if the connection has been closed
}
}
if( shouldSendHeartBeat() ){
SendHeartBeat
}
}
You should add error checking in your disconnection detection. Sometimes an IOException may be thrown when the connection to the other end is lost.
I am afraid that threading is unavoidable here. If you don't want to block the execution of your code, you need to create a separate thread.

Categories

Resources