I have a home grown web server in my app. This web server spawns a new thread for every request that comes into the socket to be accepted. I want the web server to wait until a specific point is hit in the thread it just created.
I have been through many posts on this site and examples on the web, but cant get the web server to proceed after I tell the thread to wait. A basic code example would be great.
Is the synchronized keyword the correct way to go about this? If so, how can this be achieved? Code examples are below of my app:
Web Server
while (true) {
//block here until a connection request is made
socket = server_socket.accept();
try {
//create a new HTTPRequest object for every file request
HttpRequest request = new HttpRequest(socket, this);
//create a new thread for each request
Thread thread = new Thread(request);
//run the thread and have it return after complete
thread.run();
///////////////////////////////
wait here until notifed to proceed
///////////////////////////////
} catch (Exception e) {
e.printStackTrace(logFile);
}
}
Thread code
public void run() {
//code here
//notify web server to continue here
}
Update - Final code is as below. The HttpRequest does just call resumeListener.resume() whenever I send a response header (of course also adding the interface as a separate class and the addResumeListener(ResumeListener r1) method in HttpRequest):
Web Server portion
// server infinite loop
while (true) {
//block here until a connection request is made
socket = server_socket.accept();
try {
final Object locker = new Object();
//create a new HTTPRequest object for every file request
HttpRequest request = new HttpRequest(socket, this);
request.addResumeListener(new ResumeListener() {
public void resume() {
//get control of the lock and release the server
synchronized(locker) {
locker.notify();
}
}
});
synchronized(locker) {
//create a new thread for each request
Thread thread = new Thread(request);
//run the thread and have it return after complete
thread.start();
//tell this thread to wait until HttpRequest releases
//the server
locker.wait();
}
} catch (Exception e) {
e.printStackTrace(Session.logFile);
}
}
You can use java.util.concurrent.CountDownLatch with a count of 1 for this. Arrange for an instance of it to be created and shared by the parent and child thread (for example, create it in HttpRequest's constructor, and have it retrievable by a member function). The server then calls await() on it, and the thread hits countDown() when it's ready to release its parent.
You probably need to use a Java Condition. From the docs:
Conditions (also known as condition
queues or condition variables) provide
a means for one thread to suspend
execution (to "wait") until notified
by another thread that some state
condition may now be true.
First of all, I echo the sentiment of others that re-inventing the wheel here will most likely lead to a variety of issues for you. However, if you want to go down this road anyway what you are trying to do is not difficult. Have you experimented with Jetty?
Maybe something like this:
public class MyWebServer {
public void foo() throws IOException {
while (true) {
//block here until a connection request is made
ServerSocket socket = new ServerSocket();
try {
final Object locker = new Object();
//create a new HTTPRequest object for every file request
MyRequest request = new MyRequest(socket);
request.addResumeListener(new ResumeListener() {
public void resume() {
locker.notify();
}
});
synchronized(locker){
//create a new thread for each request
Thread thread = new Thread(request);
//start() the thread - not run()
thread.start();
//this thread will block until the MyRequest run method calls resume
locker.wait();
}
} catch (Exception e) {
}
}
}
}
public interface ResumeListener {
public void resume();
}
public class MyRequest implements Runnable{
private ResumeListener resumeListener;
public MyRequest(ServerSocket socket) {
}
public void run() {
// do something
resumeListener.resume(); //notify server to continue accepting next request
}
public void addResumeListener(ResumeListener rl) {
this.resumeListener = rl;
}
}
Run under a debugger and set a breakpoint?
If unfeasible, then read a line from System.in?
Related
I have a Server that can receive multiple request at the same time.
In my Server, I have to make some traitement and wait for response. This traitmenet is done by externe library so I don't how much should I wait.
So the Server looks like :
public class MyServer{
#Override
//method from the library
public void workonRequest(){
//---
response=[...]
}
public void listenRequest() {
new Thread(() -> {
while (true) {
try {
socket = server.accept();
ObjectInputStream input = new ObjectInputStream(socket.getInputStream());
ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());
socket.setTcpNoDelay(true); //TODO : Not sure !
new Thread(() -> {
try {
handleRequest(input, output);
} catch (IOException e) {
throw new RuntimeException(e);
}
}).start();
} catch (IOException ex) {
System.out.println(ex.getMessage());
}
}
}).start();
}
And the handle request method is :
public void handleRequest(ObjectInputStream input, ObjectOutputStream output) throws IOException {
try {
while (true) {
//forward the request to the library
//work on it [means using the library and waiting]
// return response
}
}
}
The response object is the result that I want return to the client
How to deal with the problem of waiting for the answer?
How can I make sure that there will be no problems when more than 2 clients send requests at the same time.
Thanks in advance
How to deal with the problem of waiting for the answer ?###
Using while(true) can create issues because you are blocking the thread and opening sub thread and multi streams will make it more complex. There is easy way called reactive programming which handles this kind of multi-threaded issues easily, quarkus async solution and spring, if you still want to manage your sockets from java code you can use akka
How can I make sure that there will be no problems when more than 2 clients send requests at the same time.
That can be done by not blocking the main thread and If you manage to use reactive and/or async approach you will not have that problem.
Reference
https://quarkus.io/guides/getting-started-reactive
https://docs.spring.io/spring-framework/docs/current/reference/html/web-reactive.html
When I launch the GUI, it starts a new thread.
final Server myServer = new Server();
final Thread t1 = new Thread(myServer, "T1");
t1.start();
The GUI only has a button that will stop the thread upon clicking:
final JButton btnStartServer = new JButton("Stop server");
btnStartServer.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
myServer.stop();
}
});
The thread will create an object TrackingServiceImpl which is the Java RMI server. Thread itself looks like this:
class Server implements Runnable {
private volatile boolean exit = false;
public void run() {
try {
TrackingService server1 = new TrackingServiceImpl();
TrackingService serverInstance, stub = null;
Registry registry = null;
while (!exit) {
serverInstance = ((TrackingServiceImpl) server1).getInstance();
stub = (TrackingService) UnicastRemoteObject.exportObject((TrackingService) serverInstance, 0);
registry = LocateRegistry.createRegistry(4444);
registry.bind("TrackingService", stub);
System.out.println("Tracking service has started at port " + 4444);
}
System.out.println("Server is stopping....");
registry.unbind("TrackingService");
UnicastRemoteObject.unexportObject(registry, false);
} catch (Exception e) {
}
}
public void stop() {
exit = true;
}
}
Now if I click on the button before connecting any client to the server, the code works. Clients won't be unable to connect to the server. However, if I let a client connect to the server, and then I click on the button, the client continues to be able to invoke methods on the server even though the server should already have stopped (registry unbinded and exported).
Thanks in advance!
None of this makes sense. Your code does not execute correctly. You don't need the loop or the exit variable, or the Runnable either, or the thread. Once the remote object is constructed, exported, and bound, it is available to clients for remote method calls. To stop it, just unbind it and unexport it with UnicastRemoteObject.unexportObject(). NB At present you're only unexporting the Registry. There's no real need to do that.
I am writing a Server-Multiclient communication application, and I need to make a Thread that loops and accepts clients. My current code is:
Thread acceptor = new Thread() {
public void run() {
while(true){
System.out.println("looking for clients");
try{
Socket s = serverSocket.accept();
clientList.add(new ConnectionToClient(s));
}
catch(IOException e){ e.printStackTrace(); }
}
}
}
};
acceptor.setDaemon(true);
acceptor.start();
However, when I run my application, the text looking for clients only appears one time, and no clients can connect.
I don't understand why my while(true) loop isn't actually looping, and only running once.
EDIT:
The ConnectionToClient constructor is:
ConnectionToClient(Socket socket) throws IOException {
this.socket = socket;
in = new ObjectInputStream(socket.getInputStream());
out = new ObjectOutputStream(socket.getOutputStream());
Thread read = new Thread(){
public void run(){
while(true){
try {
Object obj = in.readObject();
messages.put(obj);
} catch(IOException | ClassNotFoundException | InterruptedException e) {
e.printStackTrace();
}
}
}
};
read.start();
}
You're calling acceptor.setDaemon(true);.
Its Javadoc explains:
Marks this thread as either a daemon thread
or a user thread. The Java Virtual Machine exits when the only
threads running are all daemon threads.
So you're marking your only running thread as a daemon thread (since your main thread ends when the main method ends). You're lucky that you got one iteration of the loop, since your VM almost immediately exits as there are no more non-daemon threads.
Solution: remove the line that reads acceptor.setDaemon(true);
Your updated post shows the other problem, the constructor ConnectionToClient(Socket socket) inadvertently tries to read from the Socket, which blocks the acceptor thread until the client sends data.
The problem is the constructor of ObjectInputStream tries to read the header of the object stream.
Therefor, you should move the construction of the ObjectInputStream and ObjectOutputStream into the read Thread, so that this doesn't block the acceptor Thread.
Ok, thanks to #ErwinBolwidt.
The problems were:
1) The .setDaemon(true) was causing problems.
2) Creating the ObjectInputStream before the client was connected was reading the header that needed to be sent to the server, and blocking the client from sending it to the server. Moving that to the read thread allowed the client to actually connect to the server.
Thanks again #ErwinBolwidt.
Let me explain the purpose of my application so you can guide me about the best possible approach.
The idea is building a web application to remotely manage some particular equipments that my company manufactures. These equipments will periodically connect to the remote server to send/receive certain data (through simple socket communication but they don't use Java); this data will be stored in the corresponding data base and will be available through the web application for the different users.
In the same way, when you access through the web interface, each client will be able to see their equipments and perform different changes in the configuration. At this point there are 2 possible options and this is the reason of this post:
The easiest but not the best option: the user performs some changes and I save those changes in the data base. When the equipment later establish communication to the server, then it'll read those changes and update its configuration.
The ideal solution: as soon as the user save the changes through the web interface and push the "send" button, those changes are sent to the corresponding equipment.
As mentioned above, these equipments will periodically open a socket communication (let's say every 5 minutes) to the server to send their configuration. At this moment, in order to implement the "ideal solution", the only option I can think of is not to close that socket so I can use it to immediately send information back to the equipment when a certain user makes any changes.
If this application grows along the time, I'm afraid that too many open sockets/threads can crash my application.
Let me illustrate with some code I was playing around. I know this is far from the final solution, it's just to help you understand what I'm looking for.
First of all, I register the socket server during the start-up of the web server (Tomcat in this case):
package org.listeners;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.sockets.KKMultiServer;
public class ApplicationListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent event) {
KKMultiServer kKMultiServer = new KKMultiServer();
Thread serverThread = new Thread(kKMultiServer);
serverThread.start();
event.getServletContext().setAttribute("PlainKKMultiServer", kKMultiServer);
}
public void contextDestroyed(ServletContextEvent event) { }
}
This is the main socket server class that listens for new connections:
public class KKMultiServer implements Runnable {
private Map<Long, KKMultiServerThread_v2> createdThreads = new HashMap<Long, KKMultiServerThread_v2>();
#Override
public void run() {
boolean listening = true;
try (ServerSocket serverSocket = new ServerSocket(5000)) {
while (listening) {
KKMultiServerThread_v2 newServerThread = new KKMultiServerThread_v2(serverSocket.accept(), this);
Thread myThread = new Thread(newServerThread);
myThread.start();
Long threadId = myThread.getId();
System.out.println("THREAD ID: " + threadId);
}
} catch (IOException e) {
System.err.println("Could not listen on port " + 5000);
System.exit(-1);
}
}
public Map<Long, KKMultiServerThread_v2> getCreatedThreads() {
return createdThreads;
}
}
And the thread class created with every single petition from each of the equipments (dispensers) to handle the socket communication:
public class KKMultiServerThread_v2 implements Runnable {
private Socket socket = null;
PrintWriter out = null;
BufferedReader in = null;
private long dispenserCode;
private KKMultiServer kKMultiServer;
public KKMultiServerThread_v2(Socket socket, KKMultiServer kKMultiServer) {
this.socket = socket;
this.kKMultiServer = kKMultiServer;
}
public void run() {
try {
out = new PrintWriter(socket.getOutputStream(), true);
in = new BufferedReader(
new InputStreamReader(
socket.getInputStream()));
} catch (IOException e) {
e.printStackTrace();
}
readDataFromDispenser();
}
private void readDataFromDispenser() {
String inputLine;
try {
while ((inputLine = in.readLine()) != null) {
if (inputLine.equals("Bye")) {
break;
}
if (dispenserCode == 0) {
dispenserCode = 1111; // this code will be unique per equipment
this.kKMultiServer.getCreatedThreads().put(dispenserCode, this);
}
}
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public void sendDataToDispenser(String dataToSend) {
if (!socket.isClosed() && socket.isConnected()) {
out.println(dataToSend);
} else {
this.kKMultiServer.getCreatedThreads().remove(this);
}
}
}
Now that the socket is created and alive I can use it directly from the web application to send messages back to the equipment (Struts Action in this case)
public class HelloWorldAction extends ActionSupport {
private static final long serialVersionUID = 1L;
public String sendMessageToDispenser() throws Exception {
ServletContext context = ServletActionContext.getServletContext();
KKMultiServer kKMultiServer = (KKMultiServer) context.getAttribute("PlainKKMultiServer");
Map<Long, KKMultiServerThread_v2> currentThreads = kKMultiServer.getCreatedThreads();
Iterator<Long> it = currentThreads.keySet().iterator();
while (it.hasNext()) {
Long key = (Long) it.next();
KKMultiServerThread_v2 currentThread = currentThreads.get(key);
currentThread.sendDataToDispenser("DATA TO YOU!");
}
return SUCCESS;
}
}
Do you think it's possible to perform this solution? I mean, keeping these connections open so I can access my equipments whenever necessary (without waiting for the periodically connections). What's the best approach? If you have any other suggestions please let me know.
Thank you very much.
To my mind it clearly depends on how many equipment will be connected to your system. Sockets are not always sending data so it can have low effect on the overall performance. Though, Socket are know to be a little slow, if you have a lot of data to send to/from your equipments, you should consider this.
If you want to have send data from your server to your client you have few solutions
Your server knows all your equipment after registering for example. When starting you equipment connect to the server. (be careful about local network redirection)
Your equipment and server use sockets to communicate
I don't think there is another solution but I can be wrong. If your equipment request your server every X seconds, it will never be exactly perfeclty on time.
I am trying to teach myself some networking in Java using the Kryonet library. The following code is almost identical to the code in the kyronet tutorial. https://code.google.com/p/kryonet/#Running_a_server
The client is successfully sending the message "Here is the request!" to the server (the server is printing it out) however the client is not receiving any response from the server even though the server is sending one.
I've tried unsuccessfully to fix it, can anyone see or suggest a possible problem/solution with the code?
(The code follows)
Client
public class Client_test {
Client client = new Client();
public Client_test() {
Kryo kryo = client.getKryo();
kryo.register(SomeRequest.class);
kryo.register(SomeResponse.class);
client.start();
try {
client.connect(50000, "127.0.0.1", 54555, 54777);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
client.addListener(new Listener() {
public void received (Connection connection, Object object) {
if (object instanceof SomeResponse) {
SomeResponse response = (SomeResponse)object;
System.out.println(response.text);
}
}
});
SomeRequest request = new SomeRequest();
request.text = "Here is the request!";
client.sendTCP(request);
}
}
Server
public class ServerGame {
Server server = new Server();
public ServerGame() {
Kryo kryo = server.getKryo();
kryo.register(SomeRequest.class);
kryo.register(SomeResponse.class);
server.start();
try {
server.bind(54555, 54777);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
server.addListener(new Listener() {
public void received (Connection connection, Object object) {
if (object instanceof SomeRequest) {
SomeRequest request = (SomeRequest)object;
System.out.println(request.text);
SomeResponse response = new SomeResponse();
response.text = "Thanks!";
connection.sendTCP(response);
}
}
});
}
}
Response & Request classes
public class SomeRequest {
public String text;
public SomeRequest(){}
}
public class SomeResponse {
public String text;
public SomeResponse(){}
}
After many hours watching youtube videos and sifting through the web I found the answer. Which I will post on here as it seems that quite a few people have had this problem so I would like to spread the word.
Basically the client would shut down immediately, before it could receive and output the message packet. This is because "Starting with r122, client update threads were made into daemon threads, causing the child processes to close as soon as they finish initializing.", the solution is "Maybe you could use this? new Thread(client).start();".
So basically instead of using
client.start();
to start the client thread you must use
new Thread(client).start();
Which I believe stops the thread being made into a daemon thread which therefore stops the problem.
Source: https://groups.google.com/forum/?fromgroups#!topic/kryonet-users/QTHiVmqljgE
Yes, inject a tool like Fiddler in between the two so you can see the traffic going back and forth. It's always easier to debug with greater transparency, more information.