I'm, trying to minimize the footprint of a Java program.
The JVisualVM Sampler tells me that the socket.receive() takes a lot of CPU time, even if no data is coming in.
The socket is blocking and not connected to any other machine.
Is this just a problem of the sampler or a problem of the JVM or my Code?
// constructor
if (this.isRunning && !this.socket.isClosed())
return;
this.socket = new DatagramSocket(port);
this.isRunning = true;
super.start();
...
// receive loop
while (this.isRunning && !thread.isInterrupted()) {
try {
byte[] buf = new byte[256];
// receive request
DatagramPacket packet = new DatagramPacket(buf, buf.length);
this.socket.receive(packet);
if (isRunning) {
tokenize(packet, true);
}
} catch (SocketException se) {
LOG.warn("Socket closed from outside");
} catch (IOException e) {
e.printStackTrace();
this.isRunning = false;
}
}
Receive( ) is a blocking operation so the thread that executes it, will be blocked.
JVisualVM is saying that the thread is spending much time there (which is normal as nothing will be done until a new connection arrives).
You can also check the thread monitor to see the % time that the thread is blocked (i.e. in a I/O operation).
Ps. You might want to create worker threads in order to process the received packets. Otherwise your service will be able to handle just one request at a time.
Related
I've got a pair of threads running a Socket and ServerSocket:
runThreadA() {
// Connects to B, or fails if B is not yet accepting
socket.connect();
}
runThreadB() {
// Blocks until another thread connects
serverSocket.accept();
}
Is there a way I can guarantee that B calls accept() and blocks before A calls connect()?
Check CyclicBarrier and CountDownLatch which can help you make the threads to wait each other, they might be helpful.
Code properly. If connect() fails, log the issue, wait a backoff time, and then retry, unless really too much time has passed. Even if the server is listening, connect() may fail for other reasons you and me might not be aware of (e.g. a layer somewhere in the network API has a full buffer). That's why IOException is a controlled exception, and the Java compiler expects you to explicitly handle it: IOExceptions may happen, but this is not a programming error.
private static final Logger LOG = Logger.getLogger(YourClass.class);
for (int waitTime = 10; waitTime < 10000; waitTime *= 2) {
try {
socket.connect();
} catch (ConnectException ex) {
LOG.log(Level.WARNING,
"Connection failed, retrying in " + waitTime + " ms...", ex);
Thread.sleep(waitTime);
} catch (IOException ex) {
throw new RuntimeException("Unexpected IO Exception", ex);
}
}
Even if you used some synchronization primitives, like a barrier or a signaling, the server thread would always signal before listen() actually comes into effect. So, there would still be the possibility of bad thread interleavings.
Yeap, set a reasonable timeout
runThreadA() {
Socket s = new Socket()
s.connect(endPoint, REASONABLE_TIMEOUT )
}
That way, the thread A will attempt to connect but it will wait a REASONABLE amount of time before giving up.
Update
Another approach would be to have the second thread re-try for the same amount of REASONABLE time.
runThreadA() {
maxTimeout = currentTime() + REASONABLE_TIMEOUT
while ( currentTime() < maxTimeout ) {
socket.connect()
if ( isConnected( socket ) ) {
break;
}
Thread.currentThread.sleep( A_WHILE )
}
if ( ! isConnected( socket ) ) {
.... too bad, we can't work this way
exit();
}
continue with the work here...
}
I wrote a simple TCP server to transfare some user Data to it and save it in an simple MySQL table. If i now run more than 2000 clients after each other it stops working. While running i get some IO error java.io.EOFException you may also see the misstake i made for that. But the most importand is that i get this
IO error java.net.SocketException: Connection reset
Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread
at java.lang.Thread.start0(Native Method)
at java.lang.Thread.start(Unknown Source)
at Server.main(Server.java:49)
Enough Memory schould be there but the threads are still running and i dont see where i made the misstake that they dont get terminated. So i got up to 3900 threads running than.
So here is the part of the Server:
try {
// create new socket
ServerSocket sock = new ServerSocket(port);
textArea.setText(textArea.getText() + "Server started\n");
while (true) {
// accept the connection
Socket newsock = sock.accept();
// handle the action
Thread t = new ThreadHandler(newsock);
newsock.setSoTimeout(2000); // adding client timeout
t.start();
}
} catch (Exception e) {
guess really simple. Here is how i handle the socket:
class ThreadHandler extends Thread {
private Socket socket;
private MySQLConnection sqlConnection;
ThreadHandler(Socket s) {
socket = s;
sqlConnection = new MySQLConnection();
}
public void run() {
try {
DataOutputStream out = new DataOutputStream(
socket.getOutputStream());
DataInputStream in = new DataInputStream(new BufferedInputStream(
socket.getInputStream()));
Server.textArea.append((new Date()) + "\nClient connected IP: " + socket.getInetAddress().toString()+"\n");
int firstLine = in.readInt(); // get first line for switch
switch (firstLine) {
case 0:
// getting the whole objekt for the database in own lines!
String name2 = in.readUTF();
int level2 = in.readInt();
int kp2 = in.readInt();
String skill = in.readUTF();
LeadboardElement element2 = new LeadboardElement();
element2.setName(name2);
element2.setLevel(level2);
element2.setKillPoints(kp2);
element2.setSkill(skill);
sqlConnection.saveChaToLeadboard(element2);
break;
//case 1 return the top10
###.... shorten here the rest of the cases
out.close();
in.close();
//close this socket
socket.close();
Server.textArea.append("Client disconnected IP: " + socket.getInetAddress().toString()+ "\n" + (new Date())
+ "\n----------------------------------------------------\n");
// autoscrolldown
Server.textArea.setCaretPosition(Server.textArea.getDocument()
.getLength());
} catch (Exception e) {
System.out.println("IO error " + e);
try {
socket.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}finally{
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
the saveChaToLeadboard simply gets the name level kp and skill and uses a preparedStatement so save it to my MySQL Table.
I hope you can help me i just dont see the misstake of it. I think i need to Join it somewhere but if i put a join at the end of it (after socket.close()) it still does the same.
Here the save to database methode:
public void saveChaToLeadboard(LeadboardElement element) {
try {
// load driver
Class.forName("com.mysql.jdbc.Driver");
connection = DriverManager.getConnection(this.databaseURL
+ DATABASE_NAME, this.user, this.password);
// insert values into the prep statement
preparedStatement = connection
.prepareStatement(PREP_INSERT_STATEMENT);
preparedStatement.setString(1, element.getName());
preparedStatement.setInt(2, element.getLevel());
preparedStatement.setInt(3, element.getKillPoints());
if(!element.getSkill().equalsIgnoreCase("")){
preparedStatement.setString(4, element.getSkill());
}else{
preparedStatement.setString(4, null);
}
// execute
preparedStatement.executeUpdate();
connection.close();
} catch (Exception e) {
Server.textArea.append(e.getMessage() + "\n");
Server.textArea.setCaretPosition(Server.textArea.getDocument()
.getLength());
try {
connection.close();
} catch (SQLException e1) {
e1.printStackTrace();
}
}
Thanks alot!
Regards
Your run() method is mangled, but I suspect that part of the problem is that you are not always closing network sockets and streams. In particular, I suspect that you are not closing them if there is an exception while reading, or processing the data you read. You should always close sockets and streams in a finally block (or the Java 7 equivalent).
Another potential problem is that some of the connections may be stalling due to the other end not sending data. To deal with that, you would need to set a read timeout on the socket ... so that connections to slow / stuck clients can be closed.
Finally, it is probably unrealistic to even try to process 2000+ connections in parallel with a thread per connection. That's a LOT of resources1. I recommend you use a thread pool with a fixed upper limit in the low hundreds, and stop accepting new connections if all threads are in use.
1 - Each thread stack occupies at least 64K of memory on a HotSpot JVM, and possibly as much of 1Mb. Then there are the Heap resources that the thread directly or indirectly refers to, and OS resources needed to maintain the state of the threads and the sockets. For 2000 threads, that's probably multiple Gb of memory.
IMHO 2000 threads is on the high side for a single process and 2000 database connections definately is.
Regardless of whether or not you're hitting limits with 2000 incoming connections, your approach simply will not scale.
To acheive scalability you need to look at using resource pools - this means:
a pool of reader threads reading from the sockets queuing the data for processing.
a pool of worker threads processing the data queued by the reader threads.
a pool of database connections used by the worker threads - this connection pool could be adjusted so that each worker thread has it's own connection but the important thing is that you don't continually open and close database connections.
Look at the concurreny API for the thread pools and the NIO API for the IO.
This arrangement will allow you to tune your server to acheive the desired throughput.
How do you design a read and write loop which operates on a single socket (which supports parallel read and write operations)? Do I have to use multiple threads? Is my (java) solution any good? What about that sleep command? How do you use that within such a loop?
I'm trying to use 2 Threads:
Read
public void run() {
InputStream clientInput;
ByteArrayOutputStream byteBuffer;
BufferedInputStream bufferedInputStream;
byte[] data;
String dataString;
int lastByte;
try {
clientInput = clientSocket.getInputStream();
byteBuffer = new ByteArrayOutputStream();
bufferedInputStream = new BufferedInputStream(clientInput);
while(isRunning) {
while ((lastByte = bufferedInputStream.read()) > 0) {
byteBuffer.write(lastByte);
}
data = byteBuffer.toByteArray();
dataString = new String(data);
byteBuffer.reset();
}
} catch (IOException e) {
e.printStackTrace();
}
}
Write
public void run() {
OutputStream clientOutput;
byte[] data;
String dataString;
try {
clientOutput = clientSocket.getOutputStream();
while(isOpen) {
if(!commandQueue.isEmpty()) {
dataString = commandQueue.poll();
data = dataString.getBytes();
clientOutput.write(data);
}
Thread.sleep(1000);
}
clientOutput.close();
}
catch (IOException e) {
e.printStackTrace();
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
Read fails to deliver a proper result, since there is no -1 sent.
How do I solve this issue?
Is this sleep / write loop a good solution?
There are basically three ways to do network I/O:
Blocking. In this mode reads and writes will block until they can be fulfilled, so if you want to do both simultaneously you need separate threads for each.
Non-blocking. In this mode reads and writes will return zero (Java) or in some languages (C) a status indication (return == -1, errno=EAGAIN/EWOULDBLOCK) when they cannot be fulfilled, so you don't need separate threads, but you do need a third API that tells you when the operations can be fulfilled. This is the purpose of the select() API.
Asynchronous I/O, in which you schedule the transfer and are given back some kind of a handle via which you can interrogate the status of the transfer, or, in more advanced APIs, a callback.
You should certainly never use the while (in.available() > 0)/sleep() style you are using here. InputStream.available() has few correct uses and this isn't one of them, and the sleep is literally a waste of time. The data can arrive within the sleep time, and a normal read() would wake up immediately.
You should rather use a boolean variable instead of while(true) to properly close your thread when you will want to. Also yes, you should create multiple thread, one per client connected, as the thread will block itself until a new data is received (with DataInputStream().read() for example). And no, this is not really a design question, each library/Framework or languages have its own way to listen from a socket, for example to listen from a socket in Qt you should use what is called "signals and slots", not an infinite loop.
This is my run method, it opens a socket, and waiting for an accepted connection, if connection is accepted, will have a separate Thread open for execute it:
while (isKeepRun) {
socket = serverSocket.accept();
WorkTask worktask = new WorkTask();
worktask.setSocket(socket);
worktask.setIn(new ObjectInputStream(socket.getInputStream()));
worktask.setOut(new ObjectOutputStream(socket.getOutputStream()));
Thread wt = new Thread(worktask);
wt.start();
}
if (socket != null) {
socket.close();
}
if (serverSocket != null) {
serverSocket.close();
}
When the user call it to stop, they call this method, to change the while loop condition. in order to break the while loop:
public void stopWorking() {
isKeepRun = false;
}
Well, the WorkTask's run method is very simple like that:
try {
do {
objectOutputStream.flush();
receivedObj = objectInputStream.readObject();
if (receivedObj != null){
System.out.println(receivedObj.toString()+" " + receivedObj.hashCode());
}
} while (receivedObj != null
&& !receivedObj.equals(SharedConstant.SOCKET_EOF_STRING));
if (objectInputStream != null) {
objectInputStream.close();
}
if (objectOutputStream != null) {
objectOutputStream.close();
}
} catch (IOException e1) {
e1.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
The problem is assume that reading one message need 1 second per message, the user may give up to 100 messages, that's mean it requires 100 seconds to run, in the socket. When the isKeepRun is keep running, there is no problem. But when the user wanna to stop , and call stopWorking, the loop will be escaped, can the socket is closed, during the WorkTask is reading the message. How can I delay the execution of stopWorking if the socket is still reading, if the socket is finished reading, and the stopWorking will be call immediately, but if the socket don't have any thing to read, I can call the stopWorking in no delay?
Thanks.
If your worker thread is handling your client request then it should be his responsibility to close the socket connection. You should move the code that closes the accepted socket into your worker thread. Your server socket accept loop will be independent and will close as soon as the close request is made. But, the existing connections will still be valid and the worker thread can continue handling them.
There is a problem in your code:
while (isKeepRun) {
socket = serverSocket.accept();
....
}
....
if (socket != null) {
socket.close();
}
You use only one socket reference for all client socket. So if there are more than one client socket, then you will only close the last socket.
As above said, you can use wt.join() to wait for the worker thread to finish, then the main thread will finish. But you have only one reference for client socket. Even you wait, you can only wait for the last socket to finish. All the previous client socket will be closed if you set it to stop.
Try adding
wt.join()
after the wt.start(). This waits for thread to finish it's execution.
You can check if there are still active worker threads around by calling their isAlive method. To do so, you need to keep track of your workers (using some list or map).
You might also use a call back mechanism for the workers, through which they can report back, when they finished their task. Before stopping, you simply check if every worker is done.
In both cases, if there are still active workers, sleep for some time, and check again, until all threads have finished.
Edit:
Vikas Nalwar made a good point about letting the workers close the socket connection. It still might be a good idea to wait for the worker threads to finish, though.
I've written a tcp server in Java. It spawns worker instances (Runnable) and listens for incoming tcp connection. Upon connection from a client, it will take in data from the client and does its own processing.
Of late, I noticed that upon client disconnection, the entire server will crash with error java.net.SocketException: Connection reset when the client disconnects or quits. This was when I realised I hadn't tested the tcp server thoroughly for all instances of failure.
I looked into the code and noticed that the tcp server will crash at this line while((bytesRead.... -1) in the worker instance
final int BUFFSIZE = 65535;
int bytesRead;
byte[] buffer = new byte[BUFFSIZE];
din = new BufferedInputStream(clientSocket.getInputStream());
while ((bytesRead = din.read(buffer)) != -1) { //tcp server crashes at this line if client quits or disconnects.
// worker does its job.
}
I've been pondering about the best way to close worker instance without causing a crash on the tcp server. I don't have access to the client source code to modify anything on their end.
Any thoughts?
Bregs
Yakult121
Network I/O should be done within a try/catch block if you want to handle exceptions.
This line should throw an IOException if the connection is closed. Just make sure to catch the IOException and return from the run() method of your Runnable when it occurs. This will stop the thread handling this client connection.
You must have done something incorrectly if it craches the whole server, though. This probably means you don't have a thread per client connection, but rather a single thread handling the clients sequentially, one at a time. Post the server code for more information.
figured out the problem. Writing down what i did for any person looking to solve the same problem.
private boolean isStopped = false;
while (!isStopped()) {
try {
while ((bytesRead = din.read(buffer)) != -1) {
// worker does its job.
}
}
catch (IOException ex) {
System.out.println("Exception called! Most likely due to client disconnect!");
stop();
}
}
public boolean isStopped() {
return this.isStopped;
}
public synchronized void stop(){
this.isStopped = true;
}