Socket server hang when testing with ab, waiting BufferedReader.readline() - java

I am making a Java-based web server. But when I am testing it with ApacheBench, it sometimes stop responding.
On a Macbook Air:
ab -n 20000 -c 40 -d http://localhost:1080/
is guaranteed to timeout after 16400 or more requests were done.
On Ubuntu desktop
ab -n 20000 -c 1000 -d http://localhost:1080/
could done successfully most of the time, but sometimes stop responding after several runs.
I've identified (using Eclipse) that when the server stop responding, it is waiting for BufferedReader.readline() which I use it to read HTTP request header. But I have no idea why is it waiting.
Test code is here:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class TestServer {
public static void main(String[] args){
ServerSocket socket = null;
try{
socket = new ServerSocket(1080);
ExecutorService pool = Executors.newFixedThreadPool(10);
while(true){
Socket s = socket.accept();
pool.execute(new RequestHandler(s) );
}
}
catch(Exception e){
e.printStackTrace();
}
finally{
if(null!=socket){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
class RequestHandler implements Runnable{
final Socket s;
public RequestHandler(Socket s) {
this.s = s;
}
public void run() {
try {
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
String line = br.readLine();
PrintWriter pw = new PrintWriter(s.getOutputStream());
pw.print("HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n");
pw.print(line);
pw.flush();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally{
if(s!=null){
try {
s.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
BTW, when writing the test code, I found something else strange
If
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
String line = br.readLine();
is replaced with
String line = "don't read the socket";
ab will fail with such message: "apr_socket_recv: Connection refused (111)Connection reset by peer (104)"
But open localhost:1080 with Firefox 4 will see the "don't read the socket" mess show up.

I wonder if this is a deliberate part of the ApacheBench test: to see how your server behaves when a connection is opened to it but then no data sent. Presumably ApacheBench is open source so you can have a look at see if it invokes some special behaviour (my bet is on it opening the socket and then not sending a request) after 16400 tries.
In any case, you probably want to make sure you set an explicit timeout on the socket in case your version of Java is defaulting to 0 (=infinite). Don't assume that every client will behave perfectly and always send you precisely the data you're expecting.
So as a general rule, you need to make sure that your web server doesn't fall over if "something unusual happens"-- networks are like that, and sometimes packets/connections will get randomly dropped and you need to deal with it. Operating systems may well impose limits on e.g. how long a connection can be open for and so your server could suddenly see the "rug pulled from beneath it's feet" by the OS. I imagine the ApacheBench test may simulate a few gremlins like this (which could even be what you're seeing in Ubuntu, though the readLine() hanging is probably a simulation of not sending a request on an open connection as I mention).

Related

Implementing a simple java TCP server

There are two readers plugged to the internal network. They just send data to the server machine, where I want to have this java app running receiving the data. It won't be that much data. Each reader could be transmitting single strings like "1234567" to a rate as much as maybe half a dozen times per second.
Without entering into much detail about the readers, they are datalogic and both are different models, but with this in common: They are configured to transmit the data via tcp/ip to a certain ip:port.
I tested the data trasmission with this software: https://www.hw-group.com//products/hercules/index_en.html to see if I'm receiving the data properly and it does check out, it works well.
The problem comes when I run my TCP server implementation: I receive the data from one of the devices 100% of the times, while the other one is hit and miss: Sometimes the data sent over the network never makes it to my app and I don't know why.
I'm pasting the code of what I'm using: It's simple but, with my java knowledge and after digging around the internet, it's the best I came up with.
Here's the java file with the main:
package tcpserverclasstest;
public class TCPServerClassTest {
public static void main(String[] args) throws InterruptedException {
TCPServerThread myTCPServerThread = new TCPServerThread();
myTCPServerThread.start();
}
}
Here's TCPServer.java:
package tcpserverclasstest;
import java.io.IOException;
import java.net.Socket;
import java.io.*;
public class TCPServer extends Thread {
public static final int PORT_NUMBER = 4413;
protected Socket socket;
public TCPServer(Socket socket) {
this.socket = socket;
System.out.println("New client connected from " + socket.getInetAddress().getHostAddress());
start();
}
public void run() {
InputStream in = null;
try {
in = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String request;
request = br.readLine();
System.out.println("Message received:" + request);
} catch (IOException ex) {
System.out.println("Unable to get streams from client");
} finally {
try {
in.close();
socket.close();
System.out.println("Socket closed");
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
}
And here's TCPServerThread.java:
package tcpserverclasstest;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class TCPServerThread extends Thread {
public static final int PORT_NUMBER = 4413;
protected Socket socket;
public void run(){
System.out.println("Waiting for incoming connections on port " + PORT_NUMBER);
ServerSocket server = null;
try {
server = new ServerSocket(PORT_NUMBER);
server.setReceiveBufferSize(262144);
server.setReuseAddress(true);
while (true) {
new TCPServer(server.accept());
}
} catch (IOException ex) {
System.out.println("Unable to start server.");
} finally {
try {
if (server != null)
server.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
I tried to implement the server on a thread since I want to implement this into a bigger project in the future and I don't want that app locked in the loop that is waiting for connections.
Any clues on what should I do to see why I'm not receiving some of the data? Any suggestion on a better way to achieve this?
Thanks!
first thing that comes to mind is your server only connects to one of the clients. Your TCPServerThread's run method listens for one connection and when it is made it initializes a TCPServer with this connection, meaning only one of the readers connects. Maybe after connecting to one reader you can listen for other.
Second, your TCPServer reads only one line and then closes the connection, and a line is considered to be terminated by any one of a line feed ('\n'), a carriage return ('\r'), or a carriage return followed immediately by a linefeed. So your readers should send linefeed ('\n', or '\r', or '\r\n'). If not you shouldn't use readLine, maybe read some amount of data in a while loop.
To debug your TCP connections and really be sure the data is actually coming to your server, you can use WireShark. This shows all the packets coming in your network card and you can filter based on tcp.port to see only your connections.

manage socket connection in Java over tcp

I wrote a client which basically just open a socket and send content over the connection. ( the content follows the Http protocol)
The problem I'm facing regards to the question - how and when should i close the connection.
The issue is that the connection sometime closes too early ("FIN" is sent to the server before the server answered).
in this case the server's answer is lost.
I tried to use Thread.sleep before closing the connection but nothing seems to affect the time between the content is sent and the "FIN" message is sent. (viewed in Wireshark)
The answer sometimes arrive and sometimes not ( race condition).
How can i delay the "FIN" message so i won't miss the server's response?
i added the relevant class. The relevant function is sendContentOverSocket
public class SocketClient {
private String hostName;
private int portNumber;
private Socket ConnectionSocket;
public void init(String hostName, int portNumber){
this.hostName = hostName;
this.portNumber = portNumber;
this.ConnectionSocket=createSocketConnection();
}
private Socket createSocketConnection() {
Socket socket = null;
try {
socket = new Socket(this.hostName, this.portNumber);
return socket;
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return socket;
}
public void sendContentOverSocket(String content) {
try {
PrintWriter out = new PrintWriter(
ConnectionSocket.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(
ConnectionSocket.getInputStream()));
out.print(content);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
out.close();
in.close();
ConnectionSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
TCP works with a concept called a half close.
When you close the socket that is an indication that you are not going to send anymore.
In your explanation I see "FIN is sent to the server before the server answered", if you are the client, that would mean that you have performed a close on the socket.
If you expect a result from a server within a certain time frame you need some kind of timing mechanism, possibly making use of select in combination with a timeout.
If the server closes his end of the connection, you detect this by receiving bytes in receive. Usually this means that you have to close the socket too.
So in conclusion there is 3 reasons for you to close the socket :
the server closes his end of the socket basically saying i am not going to send anymore
you have waited for a while and you are tired of waiting and decide to close the socket yourself.
any other error conditions but usually they all appear like receiving 0 bytes or a negative number.
You should close the connection after you've read the response, of course. Difficult to see the mystery here. No sleeps. If you don't read the response (a) you can't know whether the request succeeded or failed, and (b) the server is liable into encounter an exception as well.
Your code is poor quality. All those methods should propagate exceptions instead of catching them internally and returning null.
In case of Java 7, since all three classes, i.e. Socket, PrintWriter, BufferedReader, implement AutoCloseable and based on the fact, that you want to close socket right after you invoke sendContentOverSocket(String content) try to use the following code:
public class SocketClient {
private String hostName;
private int portNumber;
public void init(String hostName, int portNumber) {
this.hostName = hostName;
this.portNumber = portNumber;
}
public void sendContentOverSocket(String content) {
try (Socket socket = new Socket(this.hostName, this.portNumber);
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()))) {
out.print(content);
} catch(IOException e) {
//Appropriate exception handler
}
}
}
In this case Java will close all resources properly by itself.
If you use Java 6 or earlier try to use try-finally block instead:
solved.
i now understand how it works.
what i was missing in the client is the attempt to read from the input Stream.
When you try to read
while ((inputFromServer = in.readLine()) != null)
the client waits for input. The only thing that will break this loop is the server closing the connection.
after that happens you can safely close the connection on the client side. No need to delay the FIN and such...

open multiple server socket ports for multiple clients

I am trying to open multiple ports on a server socket so that i could connect multiple clients. Each time i create a create a thread and start it (i know the overridden run method will be invoked) i open a port and listen for a client .
But the problem is that when i run the client socket project and try to connect to the port i opened in server ,it says java.net.connectException : connection refused:connect.
I also noticed a peculiar thing happenning.The output in the console window is different every time i run the "server code "
i have been working on this for the last 3 days and i have achieved nothing i guess.
note: this problem is unique for me as i have not found this particular problem on this forum any where so please be kind as i am a newbie to java and socket programming though i have been coding on c++ for quite some time now .
server socket
import java.io.*;
import java.net.*;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.*;
public class TryThreads extends Thread
{
private int Portnumber;
private static String inputLine;
public TryThreads(int portNumber)
{
Portnumber = portNumber;
setDaemon(true);
}
public static void main(String[] args)
{
//create three threads
Thread first = new TryThreads(63400);
Thread second = new TryThreads(63401);
first.start();
second.start();
//third.start();
System.out.println("ending main");
return;
}
public void run()
{
try
{
System.out.println("one socket port opened");
ServerSocket serverSocket = new ServerSocket(Portnumber);
System.out.println("one socket port opened");
while (true)
{
System.out.println("ending main2");
//System.out.println("one socket port opened");
Socket clientSocket = serverSocket.accept();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
while((inputLine = bufferedReader.readLine()) != null)
System.out.println(inputLine);
}
}
catch(IOException e)
{
System.out.println(e);
}
}
}
client socket
import java.io.*;
import java.net.Socket;
public class client
{
private static PrintWriter printWriter;
public static void main(String[] args)
{
BufferedReader in = null;
try
{
Socket socket = new Socket("localhost",63400);
printWriter = new PrintWriter(socket.getOutputStream(),true);
printWriter.println("Hello Socket");
printWriter.println("EYYYYYAAAAAAAA!!!!");
}
catch(Exception e)
{
System.out.println(e);
}
}
}
In your TryThreads constructor, use:
setDaemon(false);
You have set your server threads to be daemon threads and they are therefore terminating as soon as main exits, so your server is stopping as soon as you start it.
See Thread.setDaemon():
The Java Virtual Machine exits when the only threads running are all daemon threads.
By the way, after the above issue is corrected, be aware that your implementation will lead to the server receiving a "connection reset" SocketException, which will break your server thread out of its loop and prevent it from accepting additional exceptions. You can fix this on the client side by doing socket.close() before you exit to ensure a graceful shutdown, but you will still want to fix it on the server side since you cannot assume that clients will be well-behaved.
Normally whenever you want to write a message using PrintWriter, you need to flush it when your done (printwriter.flush()). That makes sure the message is sent.

Bufferedreader blocks thread but adding in if(br.ready()) stops disconnect check

Im making a chat server/client. I have a BufferedReader reading my inputstream from a socket, and when it .readLine() it blocks. I added in if(BufferedReader.ready()) but that means I can no longer detect disconnected clients, as if i did add in else System.out.println("Client disconnected") then whenever the client user does not send a message for more than a couple of milliseconds it presumes the user is dissconnected.
How do I get out of this?
code:
import java.io.BufferedReader;
import java.io.InputStream;
import java.net.Socket;
public class SpeechHandler implements Runnable {
public SpeechHandler (BufferedReader r, ServerMain sm, Socket soc) {
try {
boolean connected = true;
while (connected) {
try {
String text = null;
text = r.readLine();
if (!text.equals(null)) {
sm.tellAll(text);
}
} catch (Exception e) {
System.out.println("Client " + soc.getInetAddress() + " has disconnected");
sm.removeStream(soc.getInputStream());
sm.removeStream(soc.getOutputStream());
e.printStackTrace();
connected = false;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void run () {
}
}
Found Answer The problem was not the reader blocking the thread, but the fact that all the code was written in the constructor, not the run() method, as that meant the other thread waited for the constructor to complete before moving on.
I have a BufferedReader reading my inputstream from a socket, and when it .readLine() it blocks.
Correct. That is the specified behaviour.
I added in if(BufferedReader.ready()) but that means I can no longer detect disconnected clients
Correct. There are few if any correct uses of ready(), and this isn't one of them.
then whenever the client user does not send a message for more than a couple of milliseconds it presumes the user is dissconnected.
That's a bug in your code. Don't 'presume' after 'a couple of milliseconds'.
How do I get out of this?
You are using blocking I/O. You are expected to dedicate a thread to reading from the socket, and detecting end of stream or an exception to indicate peer disconnection.

Simple java socket client, what throws this ConnectException?

I'm writing a very simple client for my very simple server. Line 17 throws a ConnectException at runtime if the server isn't running, I don't know why. I have looked through the docs for Socket's constructor and getInputStream(), but neither of them throw the ConnectException. I looked at the docs for the CE, and it says "Signals that an error occurred while attempting to connect a socket to a remote address and port. Typically, the connection was refused remotely (e.g., no process is listening on the remote address/port)." That is exactly true, the server isn't running, but I don't know how to know this other than trial and error, why isn't it in the docs for Socket?
import java.net.*;
import java.io.*;
public class ClientLesson {
//declare vars
static Socket socket;
static BufferedReader inputReader;
public static void main(String[] args) throws IOException {
try {
socket = new Socket("Lithium", 55555);
} catch (IOException ioe) {
System.out.println(ioe.toString());
}
try {
this is the problem --> inputReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
} catch (IOException ioe) {
System.out.print("couldn't get I/O stream");
ioe.printStackTrace();
}
String fromServer;
while ((fromServer = inputReader.readLine()) != null) {
System.out.println(fromServer);
}
inputReader.close();
socket.close();
}
}
I just realized the problem is entirely different...the ConnectException is thrown by the Socket constructor, and handled as an IOException, since CE is a subtype, that makes sense to me now. I'm getting a NPE at line 17, but I was confused by the terminal output, here it is:
nexus#Lithium ~/Desktop/Java Workspace/networking $ java ClientLesson
java.net.ConnectException: Connection refused
Exception in thread "main" java.lang.NullPointerException
at ClientLesson.main(ClientLesson.java:17)
I didn't understand those two were separate issues. Now I know the problem is line 17 should check to see if the first try was successful before calling methods on the socket.

Categories

Resources