I have created a TCP client using Apache Mina. I have added a while loop to constantly check the liveness of the port. Once the connection is up on the server side, the loop is broken and the connection is made. i get the session from future and use it to communicate.
Is there a better way to do this. instead of loop can i ask the connection to wait till its up.
while(true){
try {
ConnectFuture future = ioConnector.connect(new InetSocketAddress(Port),
new TriggerReceiverHandler(), SOCKET_CONFIG);
System.out.println("Message Receiver started and listening on port "+ Port);
Thread.sleep(1000);
session = future.getSession();
if(session != null)
break;
} catch (InterruptedException e) {
e.printStackTrace();
}catch(Exception ce){
if(ce.getCause() instanceof ConnectException)
System.out.println("Retrying connection");
}
}
Another question is, If the server is down and I want the server to keep waiting for the connection till its up, what should i do?
The answer is, As of now its not possible, as the connection state is known only when we attempt to connect. One modification is instead of the Thread.sleep(1000); we can add future.join() in version 1.0+ or add a listener for the future in case of 2.0+
Related
I have some java code that looks similar to this:
private void startServer() throws IOException {
URLClassLoader classloader = null;
System.out.println("Opening server socket for listening on " + PORT_NUMBER);
try {
server = new ServerSocket(PORT_NUMBER);
server.setSoTimeout(10000);
connected = true;
System.out.println("Server is now listening on port " + PORT_NUMBER);
} catch (IOException e) {
System.err.println("Could not start server on port " + PORT_NUMBER);
e.printStackTrace();
connected = false;
}
while (connected) {
// Incoming request handler socket.
Socket socket = null;
try {
System.out.println("Waiting for client connection...");
// Block waiting for an incoming connection.
socket = server.accept();
if (socket == null) continue;
...and so on and so forth. When I call server.close() later on (I don't get any different behavior if I call socket.close() first), I don't get any errors, but netstat shows that the port is still being listened on. Should calling ServerSocket.close() be sufficient enough to free up the port on this system?
I am programming for a Java 1.4.2 microedition runtime. It is also worthy to note that I have this method being run in another thread, and I am trying to close the socket from its parent thread.
EDIT Here is the line from netstat, though I can assure you it is still being listened on, since if I start the Xlet again I get an exception with that port number.
tcp 0 0 *.2349 *.* LISTEN
There are several things to consider. One of them is described by the following quotation from JavaDoc of ServerSocket
public void setReuseAddress(boolean on)
throws SocketException
Enable/disable the
SO_REUSEADDR socket option. When a TCP connection is closed the
connection may remain in a timeout state for a period of time after
the connection is closed (typically known as the TIME_WAIT state or
2MSL wait state). For applications using a well known socket address
or port it may not be possible to bind a socket to the required
SocketAddress if there is a connection in the timeout state involving
the socket address or port.
So it is kind of OK that the OS can still show that there is something going on after you close() the server socket. But if you going to open/close a server socket on the same port frequently you might hit a problem.
I found the same problem in this post, but i think it wasn't solved.
i'm going to be brief, this is my code:
try {
Socket pacConx = new Socket(ip, Integer.parseInt(port));
DataInputStream dataIn = new DataInputStream(pacConx.getInputStream());
DataOutputStream dataOut = new DataOutputStream(pacConx.getOutputStream());
while(){...}
} catch (IOException e) {
logger.fatal("error", e);
}finally{
if (dataIn != null) {
dataIn.close();
}
if (dataOut != null) {
dataOut.close();
}
if (pacConx != null) {
pacConx.close();
}
}
First, i connect to the server using the code above, and it succeed.
But, when i try to REconnect to the same server and port after a while, i cannot reconnect.
Apparently the first socket is still "alive" in the serverSide.
is the a solution to my peoblem ?
Is there a way that i can close the other "alive" socket ?
Try
...
dataOut.flush();
dataOut.close();
...
Paste error message or/and full stack trace.
You need to initiate an orderly disconnect. After calling flush on the streams, and before calling close on the socket, add this:
pacConx.shutdownInput();
pacConx.shutdownOutput();
That tells the remote end you're finished and allows it to dismantle the port without waiting to make sure there isn't data still in transit.
For about 2-4 minutes after you close the socket it will hang in "CLOSE_WAIT" state on the server. This is a normal part of the TCP/IP protocol to handle delayed packets still wandering around in the network.
This should be handled by your server code. Is it unbinding its listen socket while handling a request and trying to re-establish it after the close? If so, it should either leave the listen up during processing or re-establish it with a SO_REUSEADDR option.
Basically I want to create a rock solid server.
while (keepRunning.get()) {
try {
Socket clientSocket = serverSocket.accept();
... spawn a new thread to handle the client ...
} catch (IOException e) {
e.printStackTrace();
// NOW WHAT?
}
}
In the IOException block, what to do? Is the Server socket at fault so it need to be recreated? For example wait a few seconds and then
serverSocket = ServerSocketFactory.getDefault().createServerSocket(MY_PORT);
However if the server socket is still OK, then it is a pity to close it and kill all previously accepted connections that are still communicating.
EDIT: After some answers, here my attempt to deal with the IOException. Would the implementation be guaranteeing keeping the server up and only re-create server socket when only necessary?
while (keepRunning.get()) {
try {
Socket clientSocket = serverSocket.accept();
... spawn a new thread to handle the client ...
bindExceptionCounter = 0;
} catch (IOException e) {
e.printStackTrace();
recreateServerSocket();
}
}
private void recreateServerSocket() {
while (keepRunning) {
try {
logger.info("Try to re-create Server Socket");
ServerSocket socket = ServerSocketFactory.getDefault().createServerSocket(RateTableServer.RATE_EVENT_SERVER_PORT);
// No exception thrown, then use the new socket.
serverSocket = socket;
break;
} catch (BindException e) {
logger.info("BindException indicates that the server socket is still good.", e);
bindExceptionCounter++;
if (bindExceptionCounter < 5) {
break;
}
} catch (IOException e) {
logger.warn("Problem to re-create Server Socket", e);
e.printStackTrace();
try {
Thread.sleep(30000);
} catch (InterruptedException ie) {
logger.warn(ie);
}
}
}
}
If in doubt, you could try re-creating the server socket, using the same port. If the socket has been closed, then the creation will succeed and you can continue processing new connections. The old connections are gone, but that's outside of your control since the socket was closed. If the socket was not closed, then creating a new instance will fail since the port is still in use, which you can just ignore - i.e. don't replace the current server socket reference.
In general, clients should also assume that connections will be broken and that reconnection is necessary. In other words, it's not just the server that has to be robust - clients should also anticipate connection errors and reconnect.
You can get an IOException on an accept() if the server socket is closed (by you) or you run out of resources, e.g. file handles. Either way, there is not much you can do about it. If the serverSocket is closed (you can test for this) you probably had a good reason to do this. If you run out of resources, you will either have to increase your resource limit, which requires a restart of your application, or you have a resource leak.
Make sure you differentiate between different IOExceptions you might receive. Is it an exception on creating a connection? Is it an exception once a connection has already been established?
The only code you gave is for accept()ing. Generally speaking, an IOException usually means an error on any layer on the physical network.
Probably the best fallback behavior you can implement is to wait for a certain time quantum, and then try to reconnect. Assume you most possibly will not be able to reconnect, since you have lost network connection for more than a temporary period. Make sure you handle this gracefully. As #mdma mentioned, this must be supported by your clients as well.
However if the server socket is still
OK, then it is a pity to close it and
kill all previously accepted
connections that are still
communicating.
Please note that closing the server socket will NOT close previously accepted connections. As soon as a connection has been accepted it lives a separate, joyful life at a different port.
I hope you can help. Im fairly new to progamming and Im playing around with java Sockets.
The problem is the code below. for some reason commSocket = new Socket(hostName, portNumber); is returning true even when it has not connected with the server (server not implemented yet!). Any ideas regarding this situation?
For hostName Im passing my local machine IP and for port a manually selected port.
public void networkConnect(String hostName, int portNumber){
try {
networkConnected = false;
netMessage = "Attempting Connection";
NetworkMessage networkMessage = new NetworkMessage(networkConnected, netMessage);
commSocket = new Socket(hostName, portNumber);
// this returns true!!
System.out.println(commSocket.isConnected());
networkConnected = true;
netMessage = "Connected: ";
System.out.println("hellooo");
} catch (UnknownHostException e){
System.out.println(e.getMessage());
} catch (IOException e){
System.out.println(e.getMessage());
}
}
Many thanks.
EDIT: new Socket(.., ..); is blocking isnt it? i thought in that case if that was processed without exceptions then we have a true connection?
EDIT: I played around with anti virus and now it is working!
Had that exact same situation a few days ago on a corporate computer, and searched for it for hours.
Check your antivirus, some antivirus (like E*** N**32) use live TCP scanning that make a connection succeed even if nothing is listening on the target port but will reset it later when you try to read/write from the socket.
Add this to your code:
commSocket.getOutputStream().write(0);
commSocket.getInputStream().read();
If you get a SocketException now, you should really consider to change your antivirus.
Alternatively, set a breakpoint in your application right after creating the socket, and then use netstat -ano (on Windows) to check which process id is associated with the other endpoint of your socket (which should be on your machine if you connect to localhost).
I would suggest you to disable your antivirus, but in some cases even that does not help to unload their broken live TCP scanning driver...
The Socket constructor connects right away and will throw an IOException if it doesn't succeed. So apparently you have connected successfully to a server (this could be one you didn't make yourself).
I'm accepting a connection from a client and then passing that connected socket off to another object, however, that socket needs to be non-blocking. I'm trying to use getChannel().configureBlocking(false) but that does not seem to be working. It needs to be non-blocking because this the method below is called every 100ms. Is there some other way that I should be making this non-blocking? Thanks for any help!
public void checkForClients() {
DataOutputStream out;
DataInputStream in;
Socket connection;
InetAddress tempIP;
String IP;
try {
connection = serverSocket.accept();
connection.getChannel().configureBlocking(false);
System.err.println("after connection made");
in = new DataInputStream(connection.getInputStream());
out = new DataOutputStream(connection.getOutputStream());
tempIP = connection.getInetAddress();
IP = tempIP.toString();
System.err.println("after ip string");
// create a new user ex nihilo
connectedUsers.add(new ConnectedUser(IP, null, connection, in, out));
System.err.println("after add user");
} catch (SocketTimeoutException e) {
System.err.println("accept timeout - continuing execution");
} catch (IOException e) {
System.err.println("socket accept failed");
}
}
Two things:
Why aren't you using a ServerSocket if you're listening for connections?
If you want to accept multiple clients you want to use a loop.
The basic structure of a multi-client server is:
while (true) {
// accept connections
// spawn thread to deal with that connection
}
If the issue is blocking on the accept() call, well that's what accept() does: it blocks waiting for a connection. If that's an issue I suggest you have a separate thread to accept connections.
See Writing the Server Side of a Socket.
I would expect your code to block on the accept call, never getting to the configureBlocking call.
I typically spin off a separate thread for each socket connection, and let it block until a connection is actually made/accepted This allows the main thread to continue unblocked while it is waiting for client connections.
If you're looking for non-blocking sokets, my suggestion is to use Selectors and ServerSocketChannels with the NIO package.
http://java.sun.com/j2se/1.4.2/docs/guide/nio/
If the typical blocking socket doesn't give you the availability you need (a connection every 100ms does seem tight). You should look at a non-blocking socket. Here is a tutorial. You can also look at Apache MINA to make this easier.
One approach is to use an I/O loop (event loop) in a single threaded environment. Take a look at Deft web server for inspiration. (Especially the start() method in IOLoop)