I'm trying to build simple java web server. Every request from a client must be supported by a separate thread. I wrote something like this:
this.serverSocket = new ServerSocket(this.serverPort);
while (!this.isStopped) {
Socket clientSocket = null;
clientSocket = this.serverSocket.accept();
HttpClient client = new HttpClient(clientSocket);
new Thread(client).start();
}
The run() function of HttpClient class:
public void run()
{
try {
InputStream input = client.getInputStream();
OutputStream output = client.getOutputStream();
Thread.sleep(1000);
output.write("HTTP/1.1 200 OK".getBytes());
output.write(("\n\nWorkerRunnable: dd").getBytes());
output.close();
input.close();
} catch (IOException ex) {
Logger.getLogger(HttpClient.class.getName()).log(Level.SEVERE, null, ex);
} catch (InterruptedException ex) {
Logger.getLogger(HttpClient.class.getName()).log(Level.SEVERE, null, ex);
}
}
When I throw away
Thread.sleep(1000);
everything works good, but with this a browser can not connect with the server.
What is the problem?
Try putting Thread.sleep(1000); after the output.write(...) statements. You should acknowledge the client ASAP, then wait.
Related
I have a server app written in C# for Windows. I have a client app for android. I want to send data continuously from client to server in an infinite loop. The data is being sent but sometimes, there is a bad delay. I'm really stuck at it. Here's my client side code:
new Thread(new Runnable() {
public void run() {
Socket socket = null;
PrintWriter out = null;
while(true) {
try {
socket = new Socket(IP, PORT);
out = new PrintWriter(socket.getOutputStream(), true);
out.println(msg);
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}).start();
Any idea why is there a delay?
Your problem is that you are initializing the socket every single iteration of your while loop.
new Thread(new Runnable() {
public void run() {
Socket socket = null;
PrintWriter out = null;
while(true) {
try {
socket = new Socket(IP, PORT);
out = new PrintWriter(socket.getOutputStream(), true);
out.println(msg);
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}).start();
Refactor it out of the loop, like this:
new Thread(new Runnable() {
public void run() {
Socket socket = new Socket(IP, PORT);
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
while(true) {
try {
out.println(msg);
} catch (IOException e) {
e.printStackTrace();
}
}
socket.close();
}
}).start();
Unless that is by design, in which case, why?
It seems the code is correct. The lag may be caused not only by the application but also by the network status.
Try to ping to the router from both devices and see if you are having lag spikes due to the wireless conection. If you see high lag in pings the problem is in the connection, not in the application.
I have many clients that are waiting for server messages. So the client make accept() and wait for server. When server have messages, open a connection to the client and send messages, after that, close the communication and the cycle restart.
I've seen usually the inverse approach, where the server do accept() and client connect to it. I've wrote this code but the client (that do accept() ) is blocked on point 3 and the server (that create the connection to the client) is blocked on point 2.
Sure i have some problems in my code (dont know where), but... this is the correct way ?
The client (that do accept() and wait for new messages)
try {
System.out.println("Waiting..");
receiver = serverSocket.accept();
System.out.println("1");
ObjectInput fromServerReader = new ObjectInputStream(receiver.getInputStream());
ObjectOutputStream toServerWriter = new ObjectOutputStream(receiver.getOutputStream());
System.out.println("2");
toServerWriter.writeObject("dummy");
toServerWriter.flush();
System.out.println("3");
ScheduledEvent scheduledEvent = (ScheduledEvent) fromServerReader.readObject();
System.out.println("4");
receiver.close();
System.out.println("5");
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
// Should never happen
}
The server (that when have new message to send to client, create the
connection)
try {
InetAddress address = InetAddress.getByName(sendToUser
.getMachineName());
socket = new Socket(address, port);
log.debug("1");
ObjectOutputStream toClientWriter = new ObjectOutputStream(
socket.getOutputStream());
ObjectInputStream fromClientReader = new ObjectInputStream(socket.getInputStream());
log.debug("2");
String read = (String)fromClientReader.readObject();
log.debug("3");
// Compose the message
ScheduledEvent scheduledEvent = new ScheduledEvent();
scheduledEvent.setSubject(event.getSubject());
scheduledEvent.setMessage(event.getText());
log.debug("4");
toClientWriter.writeObject(scheduledEvent);
toClientWriter.flush();
log.debug("5");
socket.close();
log.debug("6");
} catch (UnknownHostException e) {
// TODO handle
e.printStackTrace();
} catch (IOException | ClassNotFoundException e) {
// TODO handle
e.printStackTrace();
}
In client code, instead of using
PrintWriter writer;
Use
ObjectOutputStream writer;
And then use
writer.writeObject("dummy");
writer.flush();
Try using println instead of write toServerWriter.println("dummy");. The server may be waiting for the newline character.
Client side code is
try {
URL url=new URL("http://127.0.0.1:7655");
HttpURLConnection connection=(HttpURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.connect();
PrintWriter writer = new PrintWriter(connection.getOutputStream());
writer.println("Hello");
writer.flush();
writer.close();
connection.getResponseCode();
connection.disconnect();
} catch (UnknownHostException e) {
System.err.println("Don't know about host: hostname");
} catch (IOException e) {
System.err.println("Couldn't get I/O for the connection to: hostname");
}
Server Side code is
public static void main(String args[]) throws IOException {
ServerSocket echoServer = null;
String line;
DataInputStream is = null;
Socket clientSocket = null;
try {
echoServer = new ServerSocket(7655);
clientSocket = echoServer.accept();
while (true) {
is = new DataInputStream(clientSocket.getInputStream());
System.out.println("inside");
line = is.readLine();
System.out.println(line);
}
}catch (IOException e) {
System.out.println(e);
}finally{
is.close();
clientSocket.close();
}
}
When I run the client first time it server shows the output... second time when I run client, server doesn't show output. Is there some mistake in the code?
If I am not givng "Connection.getResponseCode" in the end server side receives null and shows null on console. Why is this necessary?
Your code is exactly designed that way.
You need to make use of multithreading in the server side on thread accepts all connection the other is your DataInputStream thread.
How i did this... i have a class all by it's self with getters and setters, and is only used for information or arrays that needed between threads. And in your main run the 2 threads that will always accept connections and read every connections.
I am using the following code to read messages from a server:
Socket socket;
try {
socket = new Socket(InetAddress.getByName("url.com"), 8080);
is = new DataInputStream(socket.getInputStream());
os = new DataOutputStream(socket.getOutputStream());
} catch (IOException ex) {
Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
JOptionPane.showMessageDialog(rootPane,
"Could not establish network connection to the server." + " \nPlease check your internet connection and restart the application.",
"Unable to connect",
JOptionPane.INFORMATION_MESSAGE);
WindowEvent wev = new WindowEvent(this, WindowEvent.WINDOW_CLOSING);
Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(wev);
setVisible(false);
dispose();
System.exit(0);
}
// Start thread to listen for messages from the server
new ListenFromServer().start();
/*
* Thread class to listen for message from the server
*/
class ListenFromServer extends Thread {
public void run() {
BufferedReader in = new BufferedReader(new InputStreamReader(is));
while (true) {
try {
String tmpMsg = in .readLine().replaceAll("\\r\\n|\\r|\\n", "");
JSONObject json = new JSONObject(tmpMsg);
if (json.get("type").toString().contains("preview")) {
System.out.println("PREVIEW: " + json.get("msg").toString());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
How can i detect if the connection drops? For example if the server crashes?
Please do not use DataInputStream or DataOutputStream for text. You don't need them and they add confusion.
To detect a server has gone you need to send a piece of data and get a response. If you don't with a certain time, the connection or service is lost.
I am writing HTTP WEB SERVER code. In the mean while I have to code retry policy on using port, so that on that port server can listen client's request.
Normal Code:
serversocket = new ServerSocket(ServerSettings.port);
It throws Exception, if ServerSettings.port is not free.
Now, I want to add retry policy, if ServerSettings.port is not free, try other ports. For that I write one code, and code is a s follows,
Updated Code:
try {
serversocket = new ServerSocket(ServerSettings.port);
} catch (IOException io) {
try {
ServerSettings.port += 505;
serversocket = new ServerSocket(ServerSettings.port);
} catch (IOException io1) {
try {
ServerSettings.port += 505;
serversocket = new ServerSocket(ServerSettings.port);
} catch (IOException io2) {
log.info(new Date() + "Problem occurs in binding port");
}
}
}
But above one shows poor coding skills, and not professional one.
How can I write retry policy for ports in a professional way, so that server can listen on that port?
Logically, I think this will work (Correct me if there are any syntax typos):
ServerSocket serversocket;
boolean foundPort = false;
while (!foundPort)
{
try {
serversocket = new ServerSocket(ServerSettings.port); // If this fails, it will jump to the `catch` block, without executing the next line
foundPort = true;
}
catch (IOException io) {
ServerSettings.port += 505;
}
}
You could wrap it in a function, and instead of foundPort = true;, you would return the socket object.