ObjectInputStream hangs both server and client even after flushing - java

I've written a basic TCP chat in Java and when testing locally (i.e. localhost) it's been working fine. I can connect, type messages to myself and receive without issues. I can connect and disconnect several times a second.
However, when trying to connect through my router's external IP for whatever reason it hangs when trying to initialize the ObjectInputStream on not only the Client side, but also Server side. So I'm guessing it's something to do with my Router firewall, on which I added a firewall rule. I did only create a firewall rule for the specific port 1777 where I make my connection, is it possible that the data sent when flushing ObjectOutputStream is sent on another port? Which wouldn't make sense I guess considering the socket is bound to a specific port.
I am flushing after initializing the ObjectOutputStream and I am creating that before creating the ObjectInputStream, on both sides. What doesn't make sense to me is that it allows for a connection to be made.
I guess code may be irrelevant in this case, but here it is anyway:
This Thread is run at all times, and waits for connections then starts a new Thread for handling the connecting client:
public void run() {
while (connected) {
try (ServerSocket serverSocket = new ServerSocket(port)) {
Socket socket = serverSocket.accept();
new ClientHandler(socket);
} catch (IOException e) {
...
}
}
}
Constructor of ClientHandler class:
public ClientHandler(Socket socket) throws IOException {
outputStream = new ObjectOutputStream(socket.getOutputStream());
outputStream.flush();
inputStream = new ObjectInputStream(socket.getInputStream());
welcomeClient();
start(); // Start listening for messages.
}
This is where the ClientHandler Thread hangs.
Here is Client side code:
// Get IP, port and stuff
socket = new Socket(ip, port);
outputStream = new ObjectOutputStream(socket.getOutputStream());
outputStream.flush();
inputStream = new ObjectInputStream(socket.getInputStream());
// Write a couple objects and read some objects.
They both hang on "inputStream = new ObjectInputStream(socket.getInputStream());"
What could be the problem? I can also connect through my local IP, which makes me think it's still an outbound->inbound firewall issue for whatever reason.

Related

How to always call the same ServerSocket via WebService?

I would like ideas about a problem here, let me explain the situation, I have a endpoint with "java.net.ServerSocket", this service will be triggered the first time via webservice, (when this endpoint is called the clientSocket will be waiting for a connection)
private ServerSocket serverSocket;
private Socket clientSocket;
#GET
#Path("/conect")
public String conect() throws IOException {
serverSocket = new ServerSocket(3242);
clientSocket = serverSocket.accept(); // I need to save this connection to use on all other calls to any other endpoint
...
...
When the connection is made with the client so I need to leave this clientSocket always open, I need to save this clientSocket to be used in other calls by the webservice. Below I show an example of using an endpoint to record the user's presence.
#GET
#Path("/register-presence/{userId}")
public String registerPresence(#PathVariable("userId") Long userId){
...
...
OutputStream output = clientSocket.getOutputStream(); // I need to use the clientSocket here
PrintWriter writer = new PrintWriter(output, true);
writer.println("lUHXGbLOUaO4JczgkI2oXHTmuu/1Z0OYKQz6nYKyxw5xymw= ");
writer.flush();
return "ok";
}
This system I'm mounting will use this clientSocket to perform various actions when calls are made to some endpoints.
The main problem is that I need to make the connection, and after connected I need to save this connection performed to be used other times by the webService.
The connection saved to clientSocket must be available for as long as the connection is active. And the ClientSocket will be used in all the various calls that will be made by several different devices. This is the problem i do not know how to solve hehe. Any ideas?

manage socket connection in Java over tcp

I wrote a client which basically just open a socket and send content over the connection. ( the content follows the Http protocol)
The problem I'm facing regards to the question - how and when should i close the connection.
The issue is that the connection sometime closes too early ("FIN" is sent to the server before the server answered).
in this case the server's answer is lost.
I tried to use Thread.sleep before closing the connection but nothing seems to affect the time between the content is sent and the "FIN" message is sent. (viewed in Wireshark)
The answer sometimes arrive and sometimes not ( race condition).
How can i delay the "FIN" message so i won't miss the server's response?
i added the relevant class. The relevant function is sendContentOverSocket
public class SocketClient {
private String hostName;
private int portNumber;
private Socket ConnectionSocket;
public void init(String hostName, int portNumber){
this.hostName = hostName;
this.portNumber = portNumber;
this.ConnectionSocket=createSocketConnection();
}
private Socket createSocketConnection() {
Socket socket = null;
try {
socket = new Socket(this.hostName, this.portNumber);
return socket;
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return socket;
}
public void sendContentOverSocket(String content) {
try {
PrintWriter out = new PrintWriter(
ConnectionSocket.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(
ConnectionSocket.getInputStream()));
out.print(content);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
out.close();
in.close();
ConnectionSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
TCP works with a concept called a half close.
When you close the socket that is an indication that you are not going to send anymore.
In your explanation I see "FIN is sent to the server before the server answered", if you are the client, that would mean that you have performed a close on the socket.
If you expect a result from a server within a certain time frame you need some kind of timing mechanism, possibly making use of select in combination with a timeout.
If the server closes his end of the connection, you detect this by receiving bytes in receive. Usually this means that you have to close the socket too.
So in conclusion there is 3 reasons for you to close the socket :
the server closes his end of the socket basically saying i am not going to send anymore
you have waited for a while and you are tired of waiting and decide to close the socket yourself.
any other error conditions but usually they all appear like receiving 0 bytes or a negative number.
You should close the connection after you've read the response, of course. Difficult to see the mystery here. No sleeps. If you don't read the response (a) you can't know whether the request succeeded or failed, and (b) the server is liable into encounter an exception as well.
Your code is poor quality. All those methods should propagate exceptions instead of catching them internally and returning null.
In case of Java 7, since all three classes, i.e. Socket, PrintWriter, BufferedReader, implement AutoCloseable and based on the fact, that you want to close socket right after you invoke sendContentOverSocket(String content) try to use the following code:
public class SocketClient {
private String hostName;
private int portNumber;
public void init(String hostName, int portNumber) {
this.hostName = hostName;
this.portNumber = portNumber;
}
public void sendContentOverSocket(String content) {
try (Socket socket = new Socket(this.hostName, this.portNumber);
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()))) {
out.print(content);
} catch(IOException e) {
//Appropriate exception handler
}
}
}
In this case Java will close all resources properly by itself.
If you use Java 6 or earlier try to use try-finally block instead:
solved.
i now understand how it works.
what i was missing in the client is the attempt to read from the input Stream.
When you try to read
while ((inputFromServer = in.readLine()) != null)
the client waits for input. The only thing that will break this loop is the server closing the connection.
after that happens you can safely close the connection on the client side. No need to delay the FIN and such...

Test two clients directly connecting on the same IP and port

My two clients have to communicate directly with each other. Both of them has ServerSocket and Socket, too. I can demonstrate it with this code snippet:
final ServerSocket serverSocket = new ServerSocket(12345);
new Thread(new Runnable() {
#Override
public void run() {
try {
Socket clientSocket = serverSocket.accept();
System.out.println(clientSocket.getInputStream().read());
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
Socket clientSocket = new Socket(InetAddress.getLocalHost(), 12345);
clientSocket.getOutputStream().write(1);
clientSocket.getOutputStream().flush();
It works OK, but i cannot test them, if they are on the same IP (for example on localhost), because the client will connect to itself. My question is, how can i test or rewrite this, to test two client connecting to each other on the same IP and port?
Make the port number configurable via a command line argument, property file or some other way. For the client side you'll need to provide port number of the other instance.

java closing a serversocket and opening up the port

I'm creating a Java based server.
I'm using a server socket to accept incoming messages.
However at some point within my program I want the server socket to listen to another port.
I close the server socket. And start a new one with my new port. Everything is fine.
However when I change the server socket to the previous port again, it gives me an error.
I've read things that the server socket stays a while in a timed-out state after I closed it.
So here is my question:
Can I circumvent this timed-out state of the server socket and make my port available again after I closed it and want to listen to the same port again?
EDIT: my function to make and listen to a server socket & my function to invalidate a server socket and create a new one right after
public void makeServerSocketWithPort(int portnr) throws IOException, Exception
{
server = new ServerSocket(portnr);
server.setReuseAddress(true);
while(!portchanged)
{
Socket sock = server.accept();
System.out.println(server.getLocalPort());
System.out.println(sock.getLocalPort());
handler = new Requesthandler(sock); //should be in a thread
System.out.println(server.getLocalPort());
System.out.println(sock.getLocalPort());
}
}
public void invalidateRequestHandler(int newPort)
{
if(server != null)
{
portchanged = true;
try {
server.close();
} catch (IOException ex) {
Logger.getLogger(Controlserver.class.getName()).log(Level.SEVERE, null, ex);
}
}
portchanged = false;
makeServerSocketWithPort(newPort);
}
Error StackTrace:
Exception in thread "main" java.net.SocketException: Socket closed
at java.net.PlainSocketImpl.socketAccept(Native Method)
at java.net.PlainSocketImpl.accept(PlainSocketImpl.java:408)
at java.net.ServerSocket.implAccept(ServerSocket.java:462)
at java.net.ServerSocket.accept(ServerSocket.java:430)
at stuff.Controlserver.makeServerSocketWithPort(Controlserver.java:63)
at stuff.Main.main(Main.java:44)
EDIT:
a second try to fix it to no avail:
public void makeServerSocketWithPort(int portnr, boolean invalidated) throws IOException, Exception
{
if(!invalidated)
{
server = new ServerSocket();
server.setReuseAddress(true);
server.bind(new InetSocketAddress(portnr));
portchanged = false;
}
else
{
//TODO: invalidate the old requestHandler
if(server != null)
{
try
{
server.close();
server = null;
}
catch (IOException ex)
{
Logger.getLogger(Controlserver.class.getName()).log(Level.SEVERE, null, ex);
}
}
if(server.isClosed())
{
System.out.println("closed biatch!");
}
else
{
System.out.println("surprise moddafakkaaaaa!!!");
}
//---------------------------------------------
//then make new requestHandler with new port
portchanged = true;
}
while(!portchanged)
{
if(server != null && !server.isClosed() && !invalidated)
{
Socket sock = server.accept();
System.out.println(server.getLocalPort());
System.out.println(sock.getLocalPort());
System.out.println("test");
handler = new Requesthandler(sock); //should be in a thread
handler.start();
System.out.println("ja harm");
System.out.println(server.getLocalPort());
System.out.println(sock.getLocalPort());
}
else
{
portchanged = true;
}
}
if(portchanged)
{
portchanged = false;
makeServerSocketWithPort(portnr, false);
}
}
Again this works fine normally. I can navigate through my html pages. When I change my port number via one of the webpages it is properly stored and changed in my storage xml files.
But when I changed my socket and navigate immediately to a page through that socket, it says it is closed and is not working until i restart my application.
I'm still looking for a way to circumvent this restart.
Well I solved the mystery.
Thing was I just needed to reconstruct my classes a bit to support the threading a bit better. Instead of closing the socket and then making a new thread I started a new thread and then closed the socket. After a bit of fiddling it appeared to work just fine.
This is the normal Server socket behavior by OS. The OS keeps the port open in WAIT_TIMEOUT state. To get around this, try using ServerSocket.setReuseAddress(boolean on). This will enable/disable the SO_REUSEADDR socket option. Check here for Documentation.
Quoting the javadoc of method setReuseAddress
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.
Enabling SO_REUSEADDR prior to binding the socket using
bind(SocketAddress) allows the socket to be bound even though a
previous connection is in a timeout state.
Use TCPview to see all the opened ports in your system. You can close those ports which are in use.

LocateRegistry.createRegistry

I need an RMI registry that makes the service accessible from outside my machine, while still being able to refuse a connection based on the IP of the client. The following code makes the registry only accessible from my machine, but never gets into the "RMIClientSocketFactory" code:
LocateRegistry.createRegistry(uri.getPort(), new RMIClientSocketFactory() {
#Override
public Socket createSocket(String host, int port) throws IOException {
System.out.println("RMIServerSocketFactory().createSocket()");
InetAddress addr = InetAddress.getByName(host);
if (addr.equals(InetAddress.getLocalHost())) {
return new Socket(addr, port);
} else {
throw new IOException("remote socket bind forbidden.");
}
}
}, new RMIServerSocketFactory() {
#Override
public ServerSocket createServerSocket(int port) throws IOException {
System.out.println("RMIServerSocketFactory().createServerSocket()");
return new ServerSocket(port, 0, InetAddress.getByName("127.0.0.1"));
}
});
So it runs "RMIServerSocketFactory" and binds on the loopback, but never verifies the client IP.
Any help is welcome, thank you very much!
The client socket factory is not what you need.
What you need is the ServerSocket to reject connections from unwanted IPs. The easiest way to achieve this is to create a subclass of ServerSocket which overrides the accept() method to immediately close connections from unwanted IPs and throw an exception.
However there are better, low level ways to control network access, I don't think your application doubling as a firewall (which is essentially what you need) is a particularly good idea.

Categories

Resources