I developed my own client and server in java und I implemented a long-polling communication. So my client will always ask for new operations to be executed. If a server has a new operation, then he will send it to the client. The whole communication is based on java-sockets. Now I am thinking to renounce on long-polling-communication and implement a server-push. In this case the client will not ask my server anymore. He will just wait for notifications. If my server has a new operation to be executed, then he will make a server-push. My Goal is to save time on the client-side. So he will not send any request anymore
Question1: is it possible to implement a server-push on my model based on sockets in Java ?
Question2: if yes,how can I implement a server-push?
On server side:
...
DataOutputStream toClient = new DataOutputStream(socket.getOutputStream());
outToClient.writeBytes("event_xyz");
...
On client side you should listen for events
If I understood your question in the right way, you just have to wait for incoming data on the client. For example with a DataInputStream.readUTF(); this method waits until the ServerSocket pushes some data through the stream with the method DataOutputStream.writeUTF(String s) .
Related
I'm creating a Java program, based on the client-server model in which I need the server and the client(s) to communicate.
More specifically I need them to "give orders" to each other or request things, and transfer data inside those orders/requests, you can see what I'm trying to achieve looks something like a method, but instead of happening locally, those "methods" are called by one side and executed by the other.
For instance a possible scenario is:
The server is listening for orders
The client tries to authenticate
and sends username and password to the server
The server receives
the authentication request, controls whether the username and
password are correct and reports back to the client
The client is
now authenticated
The server is once again listening for orders
Now, my first idea was to use DataInputStream and DataOutputStream, sending requests under the form of strings, for instance, if I wanted the client to request authentication I would do something like this:
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
dos.writeUTF("requestAuth");
dos.writeUTF(username);
dos.writeUTF(password);
and the server:
DataInputStream dis = new DataInputStream(socket.getInputStream());
if(dis.readUTF().equals("requestAuth")){
String username = dis.readUTF();
String password = dis.readUTF();
//Check whether they're correct or not bla bla bla
}
This doesn't seem like the best option to me, I think there's better ways to do this but I just don't know how, I already searched for a better solution but found nothing.
Another problem that arised is that I need both the server and the client to be able to send those requests simultaneously and these requests can be sent anytime, asynchronously.
For instance: let's say the client is authenticating, it's sending the username, password, etc... but meanwhile the server wants to check if the client is still connected because a Thread is doing it every second, how can I make sure each information is delivered in the right place without the stream clogging up or threads receiving unwanted data? If the client is waiting to know whether the username and password are correct, I don't want to clog it up with the request of the other thread that's doing something completely different.
Basically: my client/server program can be multithreaded, can sockets too without things getting messy? Can I have thread ServerA communicating with thread ClientA, and thread ServerB communicating with thread ClientB without interferring with each other? Can I have multiple streams from the same socket and work on them separately?
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.
I want to send a message to a socket on a gateway(client), and then wait for a message to recieve from a gateway.
While waiting, on other hand I again send a message from server socket to gateway which is client but on accept()(ServerSocket) method my connection blocks.
I was wondering is this because of the previous request which was waiting to recieve something by using inputStream. I used threads to maintain this and use setReuseAddress() to do this.
I am not posting a code right now as I just want to know is this logic is fine or is there any logic to handle multiple requests(messages) to be send from a Server-Socket to a client-Socket and I also dont want to close the socket because the socket has to be connected through out the application.
On the client end, you use a Socket object to connect to a server which uses a single ServerSocket. Once the connection is established you will have a Socket at both ends and you can use this Socket to Serversocket connection to send data in either direction. i.e.
A single server socket is needed for new connections only.
See: here
i m a new .
i m a java developer(fresher) and currently i m working on BSE project and i m facing problem to read the packet of bytes on the client(client socket) from the server(server socket). if u can help me then please help me.
Thanks in advance
Well, if you want to interact directly with packets, then you need to use a DatagramSocket instead of the regular Socket and ServerSocket.
Then, you should visit this link to see a good tutorial on how to get started with sending and receiving individual packets.
The basic idea is that the Client or Server will block on the recieve() call while it waits for its partner to send a packet using send().
If you aren't interested in the individual packets like you indicated in your question, then you will want to use Socket and ServerSocket. The first step to communicating between the two involves code that will look similar to the following:
//Server
// this call will block until the client tries to connect to the server
Socket cientConn = new ServerSocket(8878).accept();
// now you can use the connection's input and output streams to send data
/******************/
// Client
Socket serverConn = new Socket(addressOfServer, 8878);
// now you can use the connections input and output streams
After you get connections set up, you will have basically 2 read/write loops. One on the client, and one on the server.
while(true) [
// check for data from an input stream
...
// respond with message back
}
You will need a similar loop for the client and the server.
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.)