How to always call the same ServerSocket via WebService? - java

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?

Related

Detect first client thread to register in server

A simple version of my server code can be depicted as...
public class Server implements Runnable {
static boolean isFirstClient=false;
...
...
public void run(){
ServerSocket ss=new ServerSocket(port);
while(true){
Socket s= ss.accept();
if(!isFirstClient){
isFirstClient=true;
new ClientHandler(s,true);
}
else{
new ClientHandler(s,false);
}
}
}
...
...
}
Where client handler handles the client and second parameter in the ClientHandler determines whether its the first client or not and sends the packet accordingly to the client. (I wrote a different functionality for first client to register in the server and response from server determines the first Client.)
public class Client implements Runnable(){
boolean iamFirst=false;
public void run(){
InetAddress ip = InetAddress.getByName("localhost");
Socket soc = new Socket(ip, port);
...
// response from server is stored in responsePacket.
...
iamFirst=responsePacket.isFirst();
if(iamFirst){
...
...
}
else{
...
...
}
}
}
But because of large number of clients running at the same time and also use of static variable to detect first client in server it results in running more than 1 client threads as 'firstClient'.
Can anyone suggest the best way to distinguish the first client to register in server keeping in fact that huge number of clients start at the same time?
(Note: I don't want to use sleep() function in the code to seperate one client from other client to simulate a practical scenario.)
You can make isFirstClient volatile; this makes sure all threads see the latest value of the variable.
Another approach would be to synchronise the method where you accept the clients; but since you do that in a loop it would make no sense in this case.

ObjectInputStream hangs both server and client even after flushing

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.

Java chat Server with Thread Pool

I'm trying to develop a java chat server using thread pool, but i don't know how to handle incoming message from clients. i've think to save every socket connection in a hashmap and add the task to the queue of thread pool.. but how the server can know when he's receveing a message from a client without instantiate a bufferedreader?
You dont need to initialize a buffered reader for each one of your sockets. You can look through and check if there is data waiting to be read.
for(Socket socket : socketsList)
if(socket.getInputStream().available() > 0) {
// you have data to be read from this socket
}
Your server will need to use agent objects that hold a BufferedReader that reads from their socket. Perhaps you will need to create a collection of these agent objects.
For example,
class ServerAgent implements Runnable {
private OutputStream out;
private BufferedReader br;
public ServerAgent(Socket clientSocket) throws IOException {
out = clientSocket.getOutputStream();
br = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
// ....
}
#Override
public void run() {
// TODO finish code that reads from br, BufferedReader
}
}
And your Server could have code like:
while (true) {
Socket clientSocket = server.accept();
futureList.add(threadPoolExector.submit(new ServerAgent(clientSocket)));
}

singleton client connector

Picture that you have a chat program where you want to send and recive data to & from the server. would it be smart to turn the clients connection into a singleton? or will this ruin the data stream.
my example of a client singleton:
public class Client {
private static Client client;
private final int portNumber = 7070;
private Socket socket;
private Client(){
connect();
}
public static synchronized Client getClient(){
if (client == null) {
client = new Client();
}
return client;
}
public void connect(){
try {
InetAddress adr = InetAddress.getByName("localhost");
socket = new Socket(adr, portNumber);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
There are two issues with your code:
singletons are very inflexible. If you want to implement load-balancing or connection pooling in the future, your hands are tied. Only one connection is allowed. And what about reconnecting? How do you get rid of old connection and create a new one?
connecting (or any operation that has side-effects) inside a constructor is not a good practice. Imagine unit-testing this class
So I don't advice singleton connection object. Instead have a ClientConnections manager class with Client connect() method. This manager class keeps track of all opened connections, can cache them, close unused, test periodically, etc. ClientConnections is a better candidate for singleton.
Make sense to use singleton clients if you dont want more than one connection per client. This should be fine for most cases, except when you want to support sending multiple files simultaneously.

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