Client-Server communication where Server initiates - java

I would like to have this setup:
Server hosting TCP socket server
Multiple clients connected over TCP (keeping connection open)
Then I would like to initiate a message from the Server to the client. I can't figure out how to do this, and have multiple client sessions at the same time. Techniques I've read involve the Server listening on a port, and when it receives communicate from a client, it launches a new thread to handle and process that, and then it goes back to listening on the port for the next request of another client.
So, then how would I tap into that and send a message to a client running on one of those threads?
My actual usage scenario if you are interested is below. Final goal is like a remote control for your file system to upload files to the server.
- Each client has a java background application running in the system tray that connects to the server
- Server hosts connections, and also hosts a RESTFul webservice to initiate communication
- Mobile device connects to Server over RESTFul webservices to request informatino about the client's filesystem. So it can drill down and find a file, then click and have the file uploaded to the server.
The idea here is mobile users needing to upload files from their desktop to the server while away from their office on a mobile device. (and this is for custom product, so can't use a third-party app_
PS: I've been looking at the simple Client-Server chat program here: http://way2java.com/networking/chat-program-two-way-communication/

You want to have a server listening at all times on a specified port. Once the server notices an incoming connection on that port you should create a new Thread to handle the communication between that client and the server, while the main thread keeps on listening for other incoming connections. This way you can have multiple clients connected to one server. Like so:
private void listen() throws IOException {
serverSocket = new ServerSocket(port)
while (GlobalFlags.listening) {
new ServerThread(serverSocket.accept();
if (GlobalFlags.exit) {
serverSocket.close();
break;
}
}
}
Where the GlobalFlags are variables to control the listening process and are not really necessary. You could do a while True and just keep listening for ever and ever.
In my project I have a main server controller which had listeners running in Threads. The controller controlled the GlobalFlags. I'm sure instead of using global flags there is a better way to do inter thread communication but for me this was the simplest at the time.
The ServerThread should be looping all the time switching between sending output to the client and receiving input from the client. Like so:
ServerThread(Socket socket) {
super("GameServerThread");
this.socket = socket;
try {
this.socket.setTcpNoDelay(true);
} catch (SocketException e) {
// Error handling
}
this.terminate = false;
}
#Override
public void run() {
try {
out = new PrintWriter(socket.getOutputStream(), true);
in = new BufferedReader(
new InputStreamReader(
socket.getInputStream()));
String inputLine, outputLine;
while ((inputLine = in.readLine()) != null) {
outputLine = processInput(inputLine);
out.println(outputLine);
if (terminate) {
break;
}
}
}
out.close();
in.close();
socket.close();
} catch (Exception e) {
// Error handling, should not use Exception but handle all exceptions by themselves.
}
On the client side you have a thread running through a similar loop, receiving input from the server and then sending output to the server.
In this example processInput is the function used to process the client's input. If you want the server to initiate contact you can make the server send something to the outputstream before listening for input and make the client listen first.
I have extracted this example from one of my own projects and the this.socket.setTcpNoDelay(true) is supposed to make the process faster. Reference here: http://www.rgagnon.com/javadetails/java-0294.html
"java.net.Socket.setTcpNoDelay() is used to enable/disable TCP_NODELAY which disable/enable Nagle's algorithm.
Nagle's algorithm try to conserve bandwidth by minimizing the number of segments that are sent. When applications wish to decrease network latency and increase performance, they can disable Nagle's algorithm (that is enable TCP_NODELAY). Data will be sent earlier, at the cost of an increase in bandwidth consumption. The Nagle's algorithm is described in RFC 896.
You get the current "TCP_NODELAY" setting with java.net.Socket.getTcpNoDelay()"
So to send a message to a specific client you could put all the threads upon creation in an ArrayList so you can keep track of all the currently connected clients. You can have the processInput method halt and polling a queue/variable until another class puts the message to be send in the queue/variable. So how to gain a handle on the class depends on your implementation of processInput. You could give every thread an ID (which is what I did in my project) and maybe have the processInput method poll an ArrayList at index=ID. Then to send output to the client you would have to set the variable at index=ID.
This method seems kind of clunky to me personally but I'm not really sure how else I would do it. You would probably use Queues and have processInput write the input to its Queue and then wait for another class to read it and put its response in the Queue. But I have personally never worked with Queues in java so you should read up on that yourself.

In my knowledge
1) Server hosting TCP socket server -- Possible
2) Multiple clients connected over TCP -- Possible
3) Then I would like to initiate a message from the Server to the client -- Not Possible. The Client has to initiate a connection creation, then the server might be able to send data packets to You. Example: You need to open Facebook website on your browser, Facebook server cannot decide to send its page to your PC on its own because your PC will not have a static IP address, and also if Facebook hypothetically writes code to initiate connection to Your PC, then it is as good as Your PC is the server and Facebook website/server acts as client.

Related

Sending both data and ACKs from the same port on the same machine

I am implementing the TFTP (trivial FTP) protocol in Java. I have a client and a server, and so far the client can request a file and the server sends him that data.
Here is where I hit my problem - for obvious testing reasons, I run both the client and the server on my machine. However, when sending a file, there have to be two sockets listening on the same port:
the client needs to listen for received data packages
the server needs to listen for the client's acknowledgements
...and also two respective sockets for sending data and acknowledgements, also sharing a port.
This normally does happen on the same port, but on different machines. Is there a way to get around this, and make both client and server work peacefully on the same host, without any ugly hacks? And by ugly hacks I mean something like:
predefined offset for the ACK communication port (such as +15 over the data port; this is what I'm currently using now. It sort of works but it feels wrong and is error-prone)
repeatedly closing and opening sockets (send data, close socket used to send data so that the client can use that port to send his ACK, etc.); this also works at the moment, but also via a hack. Here is, for example, how I "reopen" a socket used for sending things:
public void open() {
try {
socket = new DatagramSocket(localPortCache);
} catch (SocketException e) {
e.printStackTrace();
}
}
This is evil. My sockets, originally, receive dynamically-allocated ephemeral port numbers. I then memorize that value and use it to "restore" my socket to the old port. However, it can't be guaranteed that that port is still available. It usually is, but there's no guarantee. Am I being overly-paranoid in this case?
generating a new ACK-communication port in the handshake and send it to the client via the control port (69) in an additional step
Update:
I have managed to fix my problem. My issue was that I wasn't trying to reuse my sockets. For instance, I sent something from a socket on port X, but then tried to allocate a new socket on that port to listen for the ACK, instead of just reusing the old socket.
The client doesn't need to use a fixed port number. Just bind it to zero. The server should send the response back to the originating client whatever its port number.

Chat server - options for implementing

I'm trying to develop a Java chat server. I don't know if the better solution is to do either of:
Create a socket for each client and keep it open
Set an interval in the client application and query a database to check if there are messages for the client.
Which is the best way to go for this situation?
i suggest you to learn Serialization if you want to develop an application with UI support. Moreover, you have to create a socket for each client especially in Server side. And a Server should have threads which maybe you can call client handler, to deal with clients' requests. Query a database for checking received messages is meaningless but you can save all messages in a database maybe. My advice is if you are going to use a database (well i suggest that), use it for dealing with registration process of clients. So whenever a client sends a request to server for logging in, a thread will check will check if that client has already have an account or not in database.If not you can implement a simple register form. And logically every client will have a friend list which you should keep them in a database.
EDIT: The Server will look like this.
public class Server {
public static void main(String[] args) {
try {
ServerSocket s = new ServerSocket(8087);
System.out.println("Server Started");
while (true) {
Socket incoming = s.accept();
System.out.println(incoming.getInetAddress().getHostAddress() + " was connected!");
new ClientHandler2(incoming).start();
}
} catch (Exception e) {}
}
}
So the main point is Server should never stop to listen the specified port.
Client Handler which is a thread created in Server side.
public class ClientHandler extends Thread {
private Socket incoming;
public ClientHandler(Socket incoming){
this.incoming = incoming;
}
#Override
public void run(){}
Server will send the initialized socket into the ClientHandler's constructor and call start() method to run it.
Actually you do not have to keep connection for eternity for each client ! All you have to do is store client's state server side and then communicate via any connection. Then you can get back resource and use them more wisely when your client doesn't seem to be active for a while.

Expanding my Java program to send a alert message to other computers

I've written a java intake program that send an PDF-formatted intake to a shared folder so that other people in the network can read it. However, there is not a way for the other people to know that an intake was sent unless someone tells them, so I want the program to send an alert message to the other computers telling them that an intake has been sent.
Now I've done some research into this and figured that TCP is the way to go since it's reliable. I also know that this is a one-to-many sending going on, so I assume that my Intake program will act as the server an the other computers will be the client, or should it be the other way around?
Now I assume that I have to create a client program that listens to the server and waits for it to send a message.
With that in mind, how do I:
Create a client program that listens for the message continuously until the program is closed. I assume that I'll be using "while (true)" and sleep. If so, how long do I put the program to sleep?
Make it as part of Windows service so that can load up when Windows start.
On the server end, how do I:
Send messages to more than one computer, since TCP is not capable of multicasting or broadcasting. I assume an array/vector will play a part here.
Oh, this is a one-way communication. The client doesn't have to respond back to the server.
First of all, UDP is quite reliable (in fact, as reliable as the IP protocol itself). TCP simply ensures that the data was received which involved quite a lot of magic in the back end. Unless you absolutely need to be sure that other machines got the message, you could do it with UDP. Mind that I'm not saying “Don't use TCP”, I just want to make it straight that you should take UDP into consideration as well.
Anyway, yes, you can create a simple listening program. Here is an example of a client in Java that reads messages from the server. It overrides the run method of a Thread class:
public void run() {
try {
String messageFromServer = reader.readLine();
while (messageFromServer != null) {
// Do things with messageFromServer here
// processor.processFromServer(messageFromServer);
messageFromServer = reader.readLine(); // Blocks the loop, waits for message
}
}
catch (IOException e) {
// Handle your exception
}
}
Amongst other things, my thread was set up as such:
public CommunicationThread(String hostname, int port, int timeout) throws IOException, SocketTimeoutException {
InetSocketAddress address = new InetSocketAddress(hostname, port);
socket = new Socket();
socket.connect(address, 2000); // 2000ms time out
// You can use the writer to write messages back out to the server
writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
}
Now, regards to server-side you can do something as follows:
Write a program to allow clients to contact, given that they know your address.
Accept the connections, and store the sockets in a list.
When you need to send out a message, traverse the list and send the data to everyone on it.
You can start listening on your server with
this.socket = new ServerSocket(port);
You could (or even should(?)) make it threaded so that you can accept clients while serving others. You can accept new clients with:
socket.accept(); // Blocks, waiting for someone to connect, returns open socket
Feel free to pass that to a whole new class which can deal with BufferedWriter (and maybe even BufferedReader if you want to read from clients as well). That class is where you would implement things such as writeToClient(message)
Consider the situation where you have a ClientConnection class that has writeToClient(String s) method and (Server server, Socket socket) and initialized ArrayList conList.
Here is how you would follow:
In a separate thread in Server, accept connections with
ClientConnection con = new ClientConnection(this, socket.accept());
conList.add(con);
Then, when you want to write to clients:
for (ClientConnection c : conList) {
c.writeToClient("I'm sending you a message!");
}
I hope you get a vague idea of what you need to do. Read the Socket documentation, it's very useful. Also, as always with threaded applications, make sure you aren't doing things such as modifying a list while traversing it and avoid race conditions.
Good luck!

How can I force the server socket to re-accept a request from a client?

For those who do not want to read a long question here is a short version:
A server has an opened socket for a client. The server gets a request to open a socket from
the same client-IP and client-port. I want to fore the server not to refuse such a request but to close the old socket and open a new one. How can I do ti?
And here is a long (original) question:
I have the following situation. There is an established connection between a server and client. Then an external software (Bonjour) says to my client the it does not see the server in the local network. Well, client does nothing about that because of the following reasons:
If Bonjour does not see the server it does not necessarily means that client cannot see the server.
Even if the client trusts the Bonjour and close the socket it does not improve the situation ("to have no open socket" is worser that "to have a potentially bad socket").
So, client do nothing if server becomes invisible to Bonjour. But than the server re-appears in the Bonjour and Bonjour notify the client about that. In this situation the following situations are possible:
The server reappears on a new IP address. So, the client needs to open a new socket to be able to communicate with the server.
The server reappears on the old IP address. In this case we have two subcases:
2.1. The server was restarted (switched off and then switched on). So, it does not remember the old socket (which is still used by the client). So, client needs to close the old socket and open a new one (on the same server-IP address and the same server-port).
2.2. We had a temporal network problem and the server was running the whole time. So, the old socket is still available for the use. In this case the client does not really need to close the old socket and reopen a new one.
But to simplify my life I decide to close and reopen the socket on the client side in any case (in spite on the fact that it is not really needed in the last described situation).
But I can have problems with that solution. If I close the socket on the client side and than try to reopen a socket from the same client-IP and client-port, server will not accept the call for a new socket. The server will think that such a socket already exists.
Can I write the server in such a way, that it does not refuse such calls. For example, if it (the server) sees that a client send a request for a socket from the same client-IP and client-port, it (server) close the available socket, associated with this client-IP and client-port and than it reopens a new socket.
You can't "reopen" a socket on your server. If the socket already exists and the client is trying to reconnect then you should get an BindException (see your previous question). The scenario that may be possible:
Client Shuts down socket
Server OS "notices" socket is dead on client side and shuts its side down
Client reconnects on the same port, but with a "new" socket
In this case you may consider it be the "same" socket, but it really isn't. That said a strategy you may wish to adopt is to have some sort of map (hash of client IP/port) to whatever mechanism you are using to service the socket or some kind of persistent state data, so that it can simulate a continuation of a previous socket (in the same vein as http sessioning). Something along the lines of:
HashMap<Client, State> sessions = ...;
public void server(){
...
while(true){
Socket socket = server.accept();
Client client = new Client(socket);
State s = sessions.get(client);
if(s == null){
s = new State();
sessions.put(client, s);
}
client.setState(s);
service(client);
}
...
}
and you can adjust the map lookup to define what a "session" means within your application (same client IP, same client IP & client port, some sessionid sent over the wire, etc).
If you are just trying to make it possible for the client to reconnect and force the server to "notice" the client is disconnected, the only real way in Java is to try and read/write data, and if it has been shutdown then it should throw an exception. Therefore as was mentioned in your other question you could add some kind of ack/nak feature to your protocol and add some type of check if you believe the client is disconnected (for example if you haven't read any data in the last N milliseconds, send a message the client must echo within M milliseconds, otherwise it is assumed to be disconnected). You can also try isConnected, isInputShutdown, isOutputShutdown, but I have found those to be unreliable in my own code to indicate the socket state, unless you have closed the socket (i.e. the one you are testing on the server).
The situation you describe is impossible. You can't get a new connect request from the same remote IP:port as an existing connection. The client will not permit it to occur.
Based on the comments:
You cannot write the server in a way that it will close a socket it still thinks is connected and automatically accept the new connection, as application code does not have that kind of control over the TCP stack, nor is there a way to reopen a connection.
The chance of the port numbers being the same between your client restarts is very small.
But still, if that happens, the server will note that that you're trying to set up an already connected socket, and refuse your new connection. There's not much else your client can do in this case besides close your socket, create a new one and try to connect again - and another random port will be selected.
additional note, your server should take some form of action to detect and close dead sockets, if all your server does is read incoming data, the "dead" sockets will never be
closed as they will never be detected as dead.(enabling tcp keepalive is one cheap measure to take against dead sockets staying up for months, though it will take a couple of hours to detect them as such by default.)

how can make two clients chat with each other?

this is not my homework(my homework is just about doing chat with a client and server which it works correctly especially with your help[:-)]
but I want to make two clients chat with each other,I don't know that when i get text from the first one how can I send that text to the other client.would you please help me.thanks.
public class MainServer {
static Socket client = null;
static ServerSocket server = null;
public static void main(String[] args) {
System.out.println("Server is starting...");
System.out.println("Server is listening...");
try {
server = new ServerSocket(5050);
} catch (IOException ex) {
System.out.println("Could not listen on port 5050");
System.exit(-1);
}
try {
boolean done = false;
while (!done) {
client = server.accept();
System.out.println("Client Connected...");
BufferedReader streamIn = new BufferedReader(new InputStreamReader(client.getInputStream()));
PrintWriter streamOut = new PrintWriter(client.getOutputStream(),true);
String line = streamIn.readLine();
if (line.equalsIgnoreCase("bye")) {
streamIn.close();
client.close();
server.close();
done = true;
} else {
System.out.println(line);
streamOut.println(line);
}
}
} catch (IOException e) {
System.out.println("IO Error in streams " + e);
}
}}
That's it, your two "clients" will both act as client and server :
Listening to incoming things on a socket and sending things over an other sockets.
On the server, you can keep a Set of all the clients that are currently connected to the server. The server should listen for messages (can do this with a ServerSocket, and clients connect with normal Sockets). Each time the server receives a message, it sends this message back to all clients in the Set, and the clients display the message.
EDIT: this is for a client-server system, where clients connect to a central server instead of directly to each other. If you want to do direct client-to-client, one of them will just have to act as the server, and you'll need to implement a chat UI in both.
Here is a very simple, ~100 line, GUI chat program.
Have a look at Building an Internet chat system.
This explains how to write simple Clients and a Server with Java.
Unless you want to get into really complicated P2P discovery protocols, you would have to have a server to act at least as an intermediary.
In order to establish a direct client to client connection, the clients would need to know each others IP addresses. To do this, each client would first connect and "register" itself with a central server.
When a client wants to talk to another client, it would ask for that client's address from the server, then establish a connection directly with that client. So each client is acting both as a client (establishing connections with the server and other clients) and as a server (accepting connections from other clients).
It seems simple in theory, but in practice it gets more complicated. For example, what if the client you want to connect to is behind a firewall? You could have a hole in the firewall for incoming connections to get through, or you could fall back to having the communication go through the server, or if one of the clients is behind a firewall and the other isn't, the server could mediate the connection in the opposite direction.
Basically, there are two approaches:
One Chat server that receives all messages and distributes/forwards them to the clients (xmpp/jabber works this way)
One server that connects clients directly. Like on peer-to-peer networks
Looking back at your previous work, I think, the first approach is more feasible.
The server will offer one port where new clients can connect. After a client requests to participate/use the server, there server spawns a worker thread with a server socket on a different (available) port number and tell the client that port number. This is the reserved communication channel for that client with the server.
The rest is pretty straightforward: a client can send a new chat message, the server will pick it up and send it to all connected clients.
If a client disconnects, the worker thread will close the socket, return it to the pool and terminate.

Categories