Java Threadpool TCP Server (Port keeps changing!!) - java

Good Day,
I was taking a look at this tutorial to do a TCP Threadpool server.
http://tutorials.jenkov.com/java-multithreaded-servers/thread-pooled-server.html
It works great for listening/RECEIVING to clients and processing, and returning a response. There is a class inside that I pass in WorkerRunnable into, and that basically prints out the remote socket address (who it was sent from)
public void run(){
synchronized(this){
this.runningThread = Thread.currentThread();
}
openServerSocket();
while(! isStopped()){
Socket clientSocket = null;
try {
clientSocket = this.serverSocket.accept();
} catch (IOException e) {
if(isStopped()) {
System.out.println("Server Stopped.") ;
return;
}
throw new RuntimeException(
"Error accepting client connection", e);
}
this.threadPool.execute(
new WorkerRunnable(clientSocket,
"Thread Pooled Server"));
}
this.threadPool.shutdown();
System.out.println("Server Stopped.") ;
}
The problem is. The remote address is supposed to stay fixed (I am working within my own home wifi router). However, the IP address of the sender stays the same, but the port keeps changing!!
This is a big problem for me..as I need to be able to return a response to the user for future tasks and I actually save this address to use again to send data. When I ran this in a single TCP thread..it stayed fixed (the port).
Why does the threadpool cause the TCP remote address port to keep changing?

With TCP, the client socket port is most of the time (almost 99%, except for specific protocols) randomly chosen. But to you don't have to know it, the only thing you have to do is to keep the clientSocket reference to write back data to the client. If you want to send data to the other host after that the connection is closed, you have to start a ServerSocket on both sides with a fixed port.

Even if you test from same machine the client port will be random by default. I am not sure if there is any way to set the client source port. However, if you use netstat or capture the packet you can be sure the source port is different for every connection.

Related

Java server connect to other server using sockets

I have a project where I have to build a system where multiples server communicate between each other to respond to clients.
I can make the client communicate with the server but I'm having problems on making the servers start a connection between them.
In the code below you can see that I have a list with the ip's of all the server. For each ip the current server tries to connect with the other server. You can also see that the server wait's for connections, in these case, connections from the other servers.
#Override
public void run() {
// Trying to connect with server
for (String serverIp : servers) {
System.out.println("Trying to connect with " + serverIp);
try {
Socket clientSocket = new Socket(serverIp, this.port);
this.clientPool.submit(new ClientThread(clientSocket, this.streamHandler));
} catch (Exception e) {
System.out.println("Error");
}
System.out.println("Connected with " + serverIp);
}
// Receiving connections from other servers
// In these case we call client to the other server
try (ServerSocket serverSocket = new ServerSocket(port)) {
System.out.println("Waiting for clients to connect...");
while (true) {
Socket clientSocket = serverSocket.accept();
this.clientPool.submit(new ClientThread(clientSocket, this.streamHandler));
}
// serverSocket.close();
} catch (IOException e) {
Configuration.printError("Error starting server", e);
}
}
The problem is that the server needs to try to connect with the other servers and wait for connections from the other servers. And after receiving a new connection it needs to stop trying to connect to the correspondent server or if the server have success trying to connect with the other server, it needs to stop receiving new connections from that server.
Any suggestions on how to implement this with sockets?
It seems like you try to do this in steps, first all servers try to connect to the others, but no server have started to accept connections yet. And after the clientSocket has connected to servers, you then start to accept connections. It sounds like this can lead to a deadlock.
You know that each server must accept connections from other servers. You also know that each server need to initiate connections to the other servers.
You must either accept connections and initiated connections in two different threads, or you should use an asynchronous/event driven model and manage an event loop.
And after receiving a new connection it needs to stop trying to connect to the correspondent server or if the server have success trying to connect with the other server, it needs to stop receiving new connections from that server.
Here you want to avoid a race. This is easiest to do if each server wait X time before trying to connect to the other servers. This X should be a random delay from startup. E.g. server A waits 5 seconds before connecting, server B waits 1 second, and server C waits 13 seconds before connecting. But server B and C will not initiated any connections since server A already have established connections to those servers.

How do I make a client-server Java application to send messages on one port but receive them on another?

I am currently trying to make an application that will send messages to a server using one port, but will receive messages on another port. However, based on tutorials I have followed, it looks like the act of connecting to the server is where ports come into play and my client is receiving and sending messages on the same port. How do I make it so it sends on one port but receives on the other?
Here is the code that I think is relevant from the client side (I put some stuff that seems unrelated because I think they are things that would be altered by receiving on one port but sending on another, and ignore the comment about replacing inetaddress, that is just me working on implementing this in a gui):
public void startRunning(){
try{
connectToServer();
setupStreams();
whileChatting();
}catch(EOFException eofException){
showMessage("\n Client terminated connection");
}catch(IOException ioException){
ioException.printStackTrace();
}finally{
closeStuff();
}
}
//connect to server
private void connectToServer() throws IOException{
showMessage("Attempting connection... \n");
connection = new Socket(InetAddress.getByName(serverIP), 480);//replace serverIP with ipTextField.getText or set serverIP to equal ipTextField.getText? Same with port number.
showMessage("Connected to: " + connection.getInetAddress().getHostName() );
}
//set up streams to send and receive messages
private void setupStreams() throws IOException{
output = new ObjectOutputStream(connection.getOutputStream());
output.flush();
input = new ObjectInputStream(connection.getInputStream());
showMessage("\n Streams are good! \n");
}
//while talking with server
private void whileChatting() throws IOException{
ableToType(true);
do{
try{
message = (String) input.readObject();
showMessage("\n" + message);
}catch(ClassNotFoundException classNotfoundException){
showMessage("\n Don't know that object type");
}
}while(!message.equals("SERVER - END"));
}
//send messages to server
private void sendMessage(String message){
try{
output.writeObject("CLIENT - " + message);
output.flush();
showMessage("\nCLIENT - " + message);
}catch(IOException ioException){
messageWindow.append("\n something messed up ");
}
}
//change/update message window
private void showMessage(final String m){
SwingUtilities.invokeLater(
new Runnable(){
public void run(){
messageWindow.append(m);
}
}
);
}
EDIT/UPDATE: To help clarify some things, here is some more information. The device that sends the first message is connected to a sensor, and it sends information when that sensor detects something to the other device. The receiving device sends a message back on a different port telling the original sending device how to respond. Lets name these two devices the "reporter-action taker" and the "decision maker-commander".
If you want to use TCP/IP sockets you can't use a a socket to send and another to read. That's not what they are for.
If you use a centralized distributed algorithm (server/client communication) you have to set the server to listen on a single socket port with the ServerSocket class: then the server tries to accept clients through that socket.
Example:
ServerSocket listener = new ServerSocket(Port)
While (true) {
new Clienthandler(listener.accept());
}
The server will listen on that port, and when a client tries to connect to that port if it is accepted the server launches its handler. On this handler constructor the Socket object used on the client is received on an argument and can then be used to get the writers and the readers. The reader on this handler class will be the writer on the client class and vice-versa, maybe that's what you were looking for.
Your question about using two ports in this manner is a bit strange. You state that you have a client and a server and that they should communicate on different ports.
Just to clarify picture the server as a hanging rack for jackets with several hooks in a row. Each port the server listened on represents a hook. When it comes to the client server relationship the client or jacket knows where to find its hook, however the hook is blind and have no idea where to find jackets.
Now, the client selects a port or a hook and connects to it. The connection is like a pipeline with two pipes. One for the client to deliver data to the server with and the other to send data from the server back to the client. When the connection is established data can be transferred both ways. This means that we only need one port open on the server to send data both from the client to the server and in the opposite direction.
The reason for only having one open port open on the server for the clients to connect to is that holding an open port for connections is hard to do on a regular client computer. The normal desktop user will be behind several firewalls blocking incoming connections. If that wasn't the case the client would probably be hacked senseless from malicious viruses.
Moving on with the two port solution we could not call this a client server connection per say. It would be more like a peer to peer connection or something like that. But if this is what you want to do, the application connecting first would have to start by telling the other application what ip and port to use for connecting back, it should probably also want to give some kind of token that are to be used to pair the new incoming connection when connecting back.
You should take note that making such an implementation is not a good idea most of the time as it complicates things a whole lot for simple data transfer between a client and server application.

Bind - Address Already in Use

So i'm setting up a VoIP software and my connection thread to another peer has a UDP socket (to send audio) and a tcp socket for signaling/text. Now, to bypass firewalls and NAT, i need to use a TCP Hole punching technique, meaning i need to try and connect from this side of the call, which will open up holes in the firewall and NAT, and then i await a connection on the same port and the other peer should be able to connect to me.
try {
// UDP Socket
DatagramSocket callSocket = new DatagramSocket(null);
callSocket.setReuseAddress(true);
callSocket.bind(new InetSocketAddress(myIP, 0));
//Send/receive a few packets on callSocket
// Addresses to use
InetSocketAddress myAddress = new InetSocketAddress(myIP, callSocket.getLocalPort());
InetSocketAddress targetAddress = new InetSocketAddress(InetAddress.getByName("192.168.1.1"), 6800);
// TCP Hole Punch
Socket tcpSocket = new Socket();
tcpSocket.setReuseAddress(true);
tcpSocket.bind(myAddress);
try {
tcpSocket.connect(targetAddress, 50);
// this never connects. it's just meant to open a hole in a firewall
} catch (SocketTimeoutException ignore) {
System.out.println("Timeout!");
}
tcpSocket.close();
// Open up TCP socket
ServerSocket tcpTempSocket = new ServerSocket();
tcpTempSocket.setReuseAddress(true);
tcpTempSocket.bind(myAddress);
// accept connection and do stuff
} catch (Exception ex) {
ex.printStackTrace();
}
When i get to the 3rd and final bind, i get the "Bind Exception: Address already in use". I googled it up and read that the previous socket could still be hanging on something and wasn't closing, etc.
EDIT: this only happens in some computers. On others, it binds everything without an issue
EDIT: using "netstat", i can see that the connection is being hung up on "SYN_SENT" state on the computer where the bind goes wrong
Anyone have any tips on why this happens or how to i go around it?
Ok, so. The answer is... You can't go around it. This is an OS feature, which makes tcp connections get hung up on this port. On some computers it may take 5seconds to clear. On others, it may take over 2minutes.
Now, what i've done to get around this was... well, the only thing i could think of. When the program starts, it checks whether it supports tcp hole punching, or other ways of bypassing firewalls. The peers, when establishing the call, will trade parameters based on what they can do and, from a given priority list, choose a method they both support.
In my case, on my computer, TCP Hole Punch works. In my mum's laptop it doesn't, and i resorted to other techniques (UDP Hole Punch, UPnP, SOCKS, etc etc)

What will happen to a TCP/UDP serversocket when I switch wifi network?

what will happen to the serversocket in my app when I suddenly change the wifi network? I guess it will shut down since my device will get a new IP, at least in TCP, is the UDP MulticastSocket prone to this as well? And how to end the previous Server socket thread and start a new one when the network changes? One solution is using time outs, another is using a flag that will indicate whether the infinite loop should end or not but since listening to a socket is a blocking function it will produce an exception/error anyways.
Any thoughts will be appreciated! :)
EDIT: sample of my server thread.
ServerSocket ss = new ServerSocket(4445);
while(true){
Socket socket = ss.accept();
ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
Object obj = in.readObject();
Log.i("TAG", "Received: " + obj.toString());
in.close();
socket.close();
}
TCPIP connection will break. So client would have to connect again.
UDP will be ok provided your IP does not change after reconnection. Of course if you transmit UDP its not going to make a difference for that machine.
You should get an exception in case of TCPIP which you can handle.
UDP sockets that are not bound to the address will remain open, as they are stateless. TCP listening sockets not bound to the address will remain open as well.
Conntected TCP sockets may be severed (RST) or just linger until a timeout hits.
It is a little known fact that IP mandates it that a device by default will accept packets directed to any address it has configured on any interface, no matter on which interface the packet arrives. If this were not so, routing would be broken. One can use packet filters to filter out packets with non-matching addresses depending on the interface.

Why do sockets not die when server dies? Why does a socket die when server is alive?

I try to play with sockets a bit. For that I wrote very simple "client" and "server" applications.
Client:
import java.net.*;
public class client {
public static void main(String[] args) throws Exception {
InetAddress localhost = InetAddress.getLocalHost();
System.out.println("before");
Socket clientSideSocket = null;
try {
clientSideSocket = new Socket(localhost,12345,localhost,54321);
} catch (ConnectException e) {
System.out.println("Connection Refused");
}
System.out.println("after");
if (clientSideSocket != null) {
clientSideSocket.close();
}
}
}
Server:
import java.net.*;
public class server {
public static void main(String[] args) throws Exception {
ServerSocket listener = new ServerSocket(12345);
while (true) {
Socket serverSideSocket = listener.accept();
System.out.println("A client-request is accepted.");
}
}
}
And I found a behavior that I cannot explain:
I start a server, than I start a client. Connection is successfully established (client stops running and server is running). Then I close the server and start it again in a second. After that I start a client and it writes "Connection Refused". It seems to me that the server "remember" the old connection and does not want to open the second connection twice. But I do not understand how it is possible. Because I killed the previous server and started a new one!
I do not start the server immediately after the previous one was killed (I wait like 20 seconds). In this case the server "forget" the socket from the previous server and accepts the request from the client.
I start the server and then I start the client. Connection is established (server writes: "A client-request is accepted"). Then I wait a minute and start the client again. And server (which was running the whole time) accept the request again! Why? The server should not accept the request from the same client-IP and client-port but it does!
When you close the server , the OS will keep the socket alive for a while so it can tell the client the connection has been closed. This involves timeouts and retransmissions which can take some time. You might find some info here and here. If you want your server to be able to immediately rebind the same socket, call setReuseAddress(true) on it, though it might be the client sockets that's in a TIME_WAIT state.
The socket is no longer in TIME_WAIT state, and can be reused again by any program.
Your client code just connects, closes the socket and then exits. As far as the server/OS tcp stack is concerned, these are different connections - it's fine to reuse the source port as long as any prior connection have been torn down. (Note that the OS might not tear down all of the housekeeping of the connection immediately after you call .close() or your program exits, there's some time delay involved so it can be sure all packets have been sent/received)
It is likely the operating system has not yet shutdown the sockets, try the netstat command (should work on Windows or Unix/Linux). If you run it immediately after you close client or server you should still the socket in "TIME_WAIT" "CLOSE_WAIT" or something similar. You wont be able to reuse those ports until they are fully closed.
Per Question #3: Many clients can connect to a server attached to a single port. Apache runs on port 80 but that doesn't mean only one person can view your website at a time. Also you are closing your client socket before you're opening a new one.

Categories

Resources