I am implementing a Transfer Server program which takes messages from clients (via console input) and then forwards it to some sort of mailbox.
To allow concurrent reception of several messages by different clients, I first created a class that implements the Runnable interface. Each of this class instances will handle the communication with exactly one client:
public class ClientConnection implements Runnable {
//...
//...
#Override
public void run() {
try {
// prepare the input reader and output writer
BufferedReader reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
PrintWriter writer = new PrintWriter(clientSocket.getOutputStream(), true);
Message message = new Message();
String request = "";
// read client requests
while ((request = reader.readLine()) != null) {
System.out.println("Client sent the following request: " + request);
String response;
if (request.trim().equals("quit")) {
writer.println("ok bye");
return;
}
response = message.parseRequest(request);
if (message.isCompleted()) {
messagesQueue.put(message);
message = new Message();
}
writer.println(response);
}
} catch (SocketException e) {
System.out.println("ClientConnection: SocketException while handling socket: " + e.getMessage());
} catch (IOException e) {
throw new UncheckedIOException(e);
} catch (InterruptedException e) {
System.out.println("Client Connection was interrupted!");
e.printStackTrace();
} finally {
if (clientSocket != null && !clientSocket.isClosed()) {
try {
clientSocket.close();
} catch (IOException ignored) {}
}
}
}
}
I do have a parent thread which is responsible for starting and managing all the ClientConnection runnables:
#Override
public void run() {
clientConnectionExecutor = (ThreadPoolExecutor) Executors.newCachedThreadPool();
while (true) {
Socket clientSocket;
try {
// wait for a Client to connect
clientSocket = serverSocket.accept();
ClientConnection clientConnection = new ClientConnection(clientSocket, messagesQueue);
clientConnectionExecutor.execute(clientConnection);
} catch (IOException e) {
// when this exception occurs, it means that we want to shut down everything
clientConnectionExecutor.shutdownNow(); // force terminate all ClientConnections
return;
}
}
}
Now according to this Stackoverflow Question, I would have expected that as soon as shutdownNow(); is being called, an InterruptedException would be thrown within my ClientConnection.run() method, and there, it should print Client Connection was interrupted!. But this does not happen, so the catch clause seems never to be reached, the input reading loop just goes on.
I read in another Stackoverflow question that this might be related to some other codeline within the block seems to be consuming the InterruptedException, but there wasn't any particular information on what codeline could do that. So I am thankful for any hints.
Edit: It turns out that as soon as I manually exit the loop by typing "quit" on the client, the loop will quit and then, Client Connection was interrupted! will be printed. So somehow the exception seems to be ignored as long as the loop is running, and only handled afterwards.
From Oracle docs for shutdownNow:
There are no guarantees beyond best-effort attempts to stop processing actively executing tasks. For example, typical implementations will cancel via Thread.interrupt(), so any task that fails to respond to interrupts may never terminate.
If you take a look into ThreadPoolExecutor sources, you will find out that shutdownNow interrupts threads with this code:
void interruptIfStarted() {
Thread t;
if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
try {
t.interrupt();
} catch (SecurityException ignore) {
}
}
}
Your ClientConnection doesn't check the flag Thread.interrupted. Due to information in the post, I can't figure out which method throws InterruptedException. Probably, some other method, for example, readLine of reader or writer, blocks the thread, because they use socket's InputStream and OutputStream and because it's obvious that socket's streams block the thread if data is not immediatly available.
For example, I wrote this code to test it:
class Example {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
try(ServerSocket serverSocket = new ServerSocket()) {
serverSocket.bind(new InetSocketAddress(8080));
Socket socket = serverSocket.accept();
int dataByte = socket.getInputStream().read();
System.out.println(dataByte);
} catch (IOException e) {
e.printStackTrace();
}
});
thread.start();
thread.interrupt();
}
}
On OpenJdk-16.0.2 there is no actual interruption.
I see two possible solutions for your problem:
Check Thread.interrupted inside the while loop if you are sure that Socket doesn't block your thread.
If your are not sure, use SocketChannel in non-blocking mode instead of Socket for checking Thread.interrupted manually.
For the second way I tranformed my example into this:
class Example {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
try(ServerSocketChannel serverSocket = ServerSocketChannel.open()) {
serverSocket.configureBlocking(false);
serverSocket.bind(new InetSocketAddress(8080));
SocketChannel socket = null;
while (socket == null) {
socket = serverSocket.accept();
if (Thread.interrupted()) {
throw new InterruptedException();
}
}
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
socket.read(byteBuffer);
byte[] bytes = new byte[byteBuffer.limit()];
byteBuffer.flip();
byteBuffer.get(bytes);
System.out.println(new String(bytes, StandardCharsets.UTF_8));
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
System.out.println("Interrupted successfully");
}
});
thread.start();
thread.interrupt();
}
}
It works.
Good luck with Java :)
I would have expected that as soon as shutdownNow(); is being called, an InterruptedException would be thrown within my ClientConnection.run()
Your messagesQueue should be a BlockingQueue. So messagesQueue.put(message) will make you need to catch an Interrupted exception. So only when the thread is blocked in the put method(queue is full), you call threadpool#shutdownNow, then the thread will receive an Interrupted exception. In other cases, thread will not receive this Interrupted exception.
You can change while ((request = reader.readLine()) != null) to while ((request = reader.readLine()) != null && !Thread.interrupted()).
Another solution is to maintain all client sockets, and close all client sockets when you need to close them, this way, the client thread will directly receive an IOException:
List<Socket> clientSockets = new ArrayList<>();
while (true) {
try {
Socket accept = serverSocket.accept();
clientSockets.add(accept);
executorService.submit(new ClientConnection(accept));
}catch (Exception e) {
for (Socket socket : clientSockets) {
try {
socket.close();
} catch (Exception exception) {
//
}
}
//executorService.shutdownNow();
}
}
Related
I am using newFixedThreadPool to simultaneously serve incoming requests to a server socket. For some reason the worker classes serving the clients are not being run in separate threads. When I send multiple requests to the socket, the requests get served sequentially, not simultaneously like they should. I am running OpenJDK 1.8.0_77 if that makes any difference.
This is an excerpt of my main class:
ExecutorService executorService = Executors.newFixedThreadPool(100);
ServerSocket serverSocket = new ServerSocket(5656);
while(true) {
Socket socket = serverSocket.accept();
executorService.execute(new ConnectionHandler(socket));
}
This is my worker class:
public class ConnectionHandler implements Runnable {
private Socket socket;
public ConnectionHandler(Socket socket) {
this.socket = socket;
}
public void run() {
try {
Thread.sleep(5000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
BufferedReader reader = null;
PrintWriter writer = null;
try {
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
writer = new PrintWriter(socket.getOutputStream(), true);
while(true) {
String line = reader.readLine();
if(line == null) break;
writer.println("Echo: " + line);
}
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
try {
if(reader != null) reader.close();
if(writer != null) writer.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
Sorry, I not good with computer.
The problem was that I was echoing many messages in a loop to the socket, but the echo command sends messages sequentially and waits for every message to finish before it sends the next one.
The problem is this call:
executorService.execute(new ConnectionHandler(socket));
The execute method is allowed to force the calling thread to block until the task is complete, or even have the calling thread perform the actual work. Instead, do this:
executorService.submit(new ConnectionHandler(socket));
This will asynchronously run your task using threads in the pool.
So I am creating a server that I am trying to get to handle ASCII data. While I can get the Streams to work and call the methods. However the listening thread to add items to a Queue (ArrayBlockingQueue), and it will loop until the queue is full with null data.
Server code, Client Handler (compressed, let me know if I left something out.):
class ClientThread extends Thread {
// ASCII commands defined here (byte NUL=0x00; byte SOH=0x01; etc.)
private Socket socket;
private InputStream sInput;
private OutputStream sOutput;
BlockingQueue<byte[]> queueIn = new ArrayBlockingQueue<>(30, true);
private boolean goodToGo = false;
ClientThread(Socket socket){
id = ++Server.uniqueId; /* To be replaced with UIDs */
this.socket = socket;
/* Create Data Streams */
try {
sInput = (socket.getInputStream());
sOutput= (socket.getOutputStream());
goodToGo = true;
} catch (IOException ex) {
ServerInit.logger.log(Level.WARNING, "Error Openning Streams!", ex);
}
}
#Override
public void run(){
boolean keepGoing = true;
System.out.println("Client thread started.");
/* Start listening thread */
new Thread() {
#Override
public void run(){
while(goodToGo) {
System.out.println("Listening thread looping.");
try {
byte[] temp = IOUtils.toByteArray(sInput); // read client input using Apache Commons IO.
// Add the result to the queue.
queueIn.put(temp);
} catch (EOFException eof){
ServerInit.logger.log(Level.INFO,"Remote client closed connection.");
close();
}
catch (IOException ex) {
ServerInit.logger.log(Level.WARNING, "Error Reading Stream!", ex);
close();
}
}
}
}.start();
while (keepGoing && goodToGo){
System.out.println("Main thread looping.");
try{
byte[] message = queueIn.take();
if (message.length >= 4){
/* Message picked apart and worked with here */
} else if (message.length == 0 ){
// Do nothing.
} else {
ServerInit.logger.log(Level.WARNING, "Unable to process item from queue.");
}
} catch (Exception e) {
/* Here just for completeness, I don't catch Exceptions this way. :) */
}
}
}
protected void close(){
// try to close the conection
goodToGo = false;
try {
if (sOutput != null) {
sOutput.close();
}
if (sInput != null) {
sInput.close();
}
if (socket != null) {
socket.close();
}
ServerInit.SERVER.remove(id);
} catch (Exception e){
ServerInit.logger.log(Level.FINER, "Error closing client connections.", e);
}
}
}
And client code:
public class TestClient{
public static void main(String args[]){
try{
Socket socket = new Socket("localhost", 5525);
OutputStream outputStream = socket.getOutputStream();
byte[] buffer = { 0x02, 0x05, 0x07, 0x04 };
outputStream.write(buffer);
outputStream.flush();
outputStream.close();
} catch (Exception e) {
/* Again, I don't catch exceptions like normally. */
}
}
}
My Questions: What is causing the "listening" thread to loop and add null data to queue indefinitely?
And While I know this is not the Code Review exchange, if anyone can think of better classes to utilize, If they could just mention it.
EDIT:
Following a suggestion, I changed the queue from an ArrayList<> to an ArrayBlockingQueue.
IOUtils.toByteArray() is not appropriate for this usage. It will read to end of stream and return you one big byte array, not a sequence of messages. So there is certainly no point in calling it twice, or in a loop. After the initial result, all you can get is an infinity of empty byte arrays.
I've not used IOUtils.toByteArray but my suspicion is that if there is no data in the stream when you call it then it either returns null or an empty array.
This makes sense if you think about it since otherwise it has no idea how many bytes to read. It has no way to know if you are sending an array containing 1, 4 or 1000 bytes so it just reads everything that is ready when you call it.
You need to somehow sleep between each call to toByteArray and ignore any empty responses. A better way would be to see if you can sleep until more data arrives on the socket.
I have a TCP socket connection which works well on Android 2.3 but now facing some problems on Android 4.1.
The problem is that InputStream.read() method always returns -1 (without blocking), like the connection is closed.
Creating socket:
SocketFactory socketFactory = SocketFactory.getDefault();
Socket socket = socketFactory.createSocket("c.whatsapp.net", 5222);
socket.setSoTimeout(3*60*1000);
socket.setTcpNoDelay(true);
Retrieving input and output streams and writing some initial data:
InputStream inputStream = new BufferedInputStream(socket.getInputStream());
OutputStream outputStream = new BufferedOutputStream(socket.getOutputStream());
outputStream.write(87);
outputStream.write(65);
outputStream.write(1);
outputStream.write(2);
outputStream.flush();
Then, this condition always passes without blocking:
int c = inputStream.read();
if (c < 0) {
Log.d(TAG, "End of stream");
}
This code is running in a background thread. And it was working on Gingerbread.
Tried to use InputStreamReader and OutputStreamWriter instead of direct streams - no effect.
I have seen that very same error before, although this answer might look offtopic give it a chance and let me know if it worked, for some reason sockets are having strange behavior on jellybean even when they were working completely fine in lower android versions, the way I fixed this issue was to move the targetSdkVersion to jelly bean as well as the Project Build Target under Android properties of the project, didn't modify one single line of code, just that, and for some reason it does the trick...
Hope this helps.
Regards!
I had some similar issue where the inputStream.read() returned -1 and I did not get any Exception. In fact the server was down and the connection broken. I didn't test it with different versions, only with 4.0.
Here's the Google Bug Report about this behavior.
Unfortunately status of the bug seems to be 'closed' as not reproduceable.
My work around was to interpret the -1 as a close of the socket and an unreachable server. When you try to reconnect, you get the right errors.
I have had a similar problem and fixed it with a workaround like this
private static ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1);
private static class WatchDog implements Runnable{
private Thread thread = Thread.currentThread();
public void run() {
Log.d(LOG_TAG, "Interrupting read due to timeout");
thread.interrupt();
}
}
private void read(InputStream in, ByteBuffer bb, long waitTime) throws IOException {
int startingPos = bb.position();
long timeout = System.currentTimeMillis() + RESPONSE_TIMEOUT;
ScheduledFuture<?> watchdogFuture = executor.schedule(new WatchDog(), RESPONSE_TIMEOUT, TimeUnit.MILLISECONDS);
try {
while(System.currentTimeMillis() < timeout && bb.hasRemaining()){ //workaround fixing timeout after 1ms
try{
int read = in.read(bb.array(), bb.position(), bb.remaining());
if(read > 0){
bb.position(bb.position()+read);
}
} catch(SocketTimeoutException e){}
if(bb.hasRemaining()){
Thread.sleep(5);
}
}
watchdogFuture.cancel(true);
} catch (InterruptedException e) {}
if(bb.hasRemaining()){
throw new SocketTimeoutException("Unable to read requested bytes: "
+ (bb.position()-startingPos) + "/" + (bb.limit()-startingPos)
+ " after " + (System.currentTimeMillis() - timeout + RESPONSE_TIMEOUT) + "ms");
}
}
Using BufferedReader and PrintWriter works on all versions for me and is extremely convenient for sending and receiving anything you want (even JSON strings) via any communication protocol. Try saving them as member variables when starting your background thread like this:
mInput = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
mOutput = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream())), true);
For asynchronous communication your background thread might then look like this:
#Override
public final void run() {
while (!Thread.currentThread().isInterrupted()) {
if (mInput == null) {
break;
}
String message = null;
try {
message = mInput.readLine();
} catch (IOException e) {
// handle the exception as you like
break;
}
if (Thread.currentThread().isInterrupted()) {
// thread was interrupted while reading
break;
} else if (message != null) {
// handle the message as you like
}
}
}
Use another background thread to send messages:
#Override
public void run() {
if (mOutput != null) {
mOutput.println(<message to be );
if (mOutput == null) {
// the above thread was interrupted while writing
} else if (!mOutput.checkError()) {
// everything went fine
} else {
// handle the exception
}
}
}
Also, you will have to close the streams from outside to make sure readLine doesn't block forever:
try {
mOutput.close();
mInput.close();
mOutput = null;
mInput = null;
} catch (IOException e) {
// log the exception
}
Now, since you're using TCP sockets it may happen that the socket is actually dead and readLine is still blocking. You have to detect that and close the streams just like above. For that, you will have to add another thread (oh well) that periodically sends keep-alive-messages. If no message was received from the remote device for X seconds, it has to close the streams.
This whole approach makes sure the socket is closed and all threads finish at all circumstances. Of course you can make the communication synchronous, if that is what you need, by removing the sender-thread and including println() inside the reader-thread instead. I hope that helps you (even though the answer comes 8 months late).
Friend,
try inputStream.readLine(); (i.e) DataInputStream.readLine(); (Deprecated method)
this worked for me...
Try this code -
Runnable runnable = new Runnable() {
#Override
public void run() {
synchronized (this) {
Socket s = null;
String inMsg = null, msg2 = null;
try {
try {
s = new Socket(server, port);
} catch (Exception e) {
return;
}
BufferedReader in = new BufferedReader(
new InputStreamReader(s.getInputStream()));
BufferedWriter out = new BufferedWriter(
new OutputStreamWriter(s.getOutputStream()));
try {
inMsg = in.readLine()
+ System.getProperty("line.separator");
} catch (Exception e) {
return;
}
out.write(message + "\n\r");
out.flush();
try {
msg2 = in.readLine();
if (msg2 == null) {
return;
}
} catch (Exception e) {
return;
}
out.close();
s.close();
} catch (Exception e) {
return;
}
}
}
};
It works for me.
You should use Apache Commons IO: http://commons.apache.org/proper/commons-io/
See IOUtils.copy() http://commons.apache.org/proper/commons-io/javadocs/api-release/index.html?org/apache/commons/io/package-summary.html
I'm using socket to writing multiple clients - server application in java. I wrote simple client - server application and everything was ok but when i tried change it to multi clients app I got the exception when i started client:
Exception in thread "pool-1-thread-1" java.lang.NullPointerException
at MiniSerwer.run(Serwer.java:110)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
at java.lang.Thread.run(Thread.java:679)
I have two more classes (threads - InWorker and OutWorker to input and output).
Serwer.java (without InWorker and OutWorker) :
public class Serwer {
Serwer(int port) {
ServerSocket serversocket=null;
ExecutorService exec= Executors.newCachedThreadPool();
try {
serversocket=new ServerSocket(port);
} catch (IOException e) {
e.printStackTrace();
}
while(true) {
Socket socket=null;
try {
socket = serversocket.accept();
} catch (IOException e) {
e.printStackTrace();
}
exec.execute(new MiniSerwer(socket)); // create new thread
}
} }
MiniSerwer - helper class to create owns thread to everyone client
class MiniSerwer implements Runnable{
Socket socket=null;
ExecutorService exec=null;
ObjectOutputStream oos=null;
ObjectInputStream ois=null;
MiniSerwer(Socket socket) {
this.socket=socket;
try {
oos=new ObjectOutputStream(socket.getOutputStream());
oos.flush();
ois=new ObjectInputStream(socket.getInputStream());
} catch (IOException e) {
e.printStackTrace();
}
}
public void run() {
while(true) {
exec.execute(new InWorker(socket, ois)); // input stream
exec.execute(new OutWorker(socket, oos)); //output stream
Thread.yield();
}
}
}
I change my program but it still doesn't work. Any other suggestion ?
Server:
public class Serwer implements Runnable{
ServerSocket serversocket=null;
ExecutorService exec= Executors.newCachedThreadPool();
int port;
Serwer(int port) {
this.port=port;
}
public void run() {
try {
serversocket=new ServerSocket(port);
while(true) {
Socket socket=null;
try {
socket = serversocket.accept();
exec.execute(new MiniSerwer(socket)); // create new thread
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
int port;
Scanner in = new Scanner(System.in);
System.out.println("Enter the port:");
port = in.nextInt();
ExecutorService exec=Executors.newCachedThreadPool();
exec.execute(new Serwer(port));
}
}
MiniSerwer:
class MiniSerwer implements Runnable{
Socket socket=null;
ExecutorService exec=Executors.newCachedThreadPool();
ObjectOutputStream oos=null;
ObjectInputStream ois=null;
MiniSerwer(Socket socket) {
this.socket=socket;
}
public void run() {
try {
oos=new ObjectOutputStream(socket.getOutputStream());
oos.flush();
ois=new ObjectInputStream(socket.getInputStream());
} catch (IOException e) {
e.printStackTrace();
}
while(true) {
exec.execute(new InWorker(socket, ois)); // input stream
exec.execute(new OutWorker(socket, oos)); //output stream
Thread.yield();
}
}
}
I have a lot of exceptions when I'm trying send message from client to server.
2 sec. after connecting on the server side (i don't send anything) :
Exception in thread "pool-2-thread-1" java.lang.OutOfMemoryError: unable to create new native thread
at java.lang.Thread.start0(Native Method)
at java.lang.Thread.start(Thread.java:657)
at java.util.concurrent.ThreadPoolExecutor.addWorker(ThreadPoolExecutor.java:943)
at java.util.concurrent.ThreadPoolExecutor.processWorkerExit(ThreadPoolExecutor.java:992)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
at java.lang.Thread.run(Thread.java:679)
Your executor service, in your MiniSerwer class, is never initialized. That's the root cause of your NPE.
But like I mentioned in my comment, you should not be doing all the Serwer logic in it's constructor. The object never gets fully initialized because you never exit the constructor. Make the entire class Runnable and move that logic to the overridden run method. Then add a main method to be used in actually instantiation/running the server.
Also, in your MiniSerwer, your stream initialization can fail. You need to validate the streams aren't null before using them in the run method. Or just move the initialization logic for them to the beginning of your run method.
EDIT
You also have a bug in your MiniSerwer implementation, you spawn an infinite number of threads to process the object input and output streams:
while(true) {
exec.execute(new InWorker(socket, ois)); // input stream
exec.execute(new OutWorker(socket, oos)); //output stream
Thread.yield();
}
You will either run out of threads, run out of memory, or both. To be honest, your solution is over-engineered, I doubt the In and Out workers really need to be separated the way you have them now.
Never do such terrible things. In the code below you ignored exception twice:
First ignore:
try {
serversocket=new ServerSocket(port);
} catch (IOException e) {
e.printStackTrace();
}
after that serversocket could be null as before
and second ignore:
while(true) {
Socket socket=null;
try {
socket = serversocket.accept();
} catch (IOException e) {
e.printStackTrace();
}
exec.execute(new MiniSerwer(socket)); // create new thread
}
after that try...catch socket also could be null as before.
Both things could lead to the NullPointerException !
Fix it all like:
try {
serversocket=new ServerSocket(port);
while(true) {
Socket socket=null;
try {
socket = serversocket.accept();
exec.execute(new MiniSerwer(socket)); // create new thread
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
} catch (IOException e) {
e.printStackTrace();
}
UPD: This one: while(true) {...} is also terrible thing. But let's left this after the brackets of this question.
I'm developing an Android 3.1 Tablet application that runs a service with this thread:
public class UDPServerThread extends Thread
{
[ ... ]
public void run()
{
while (!end)
{
try
{
byte[] buf = new byte[MESSAGE_SIZE];
// Wait an incoming message.
DatagramPacket packet = new DatagramPacket(buf, buf.length);
socket.receive(packet);
// TODO: Notify Service with packet received
Message msg = new Message();
msg.obj = packet;
mServiceHandler.sendMessage(msg);
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
public void stopServer()
{
Log.v("UDPServerThread", "stopServer");
if (socket != null)
socket.close();
end = true;
}
}
When I call stopServer() method from service I get the following error:
java.net.SocketException: Interrupted system call
Which is the right way to stop this thread while it is on socket.receive(packet);?
The only real problem with this exception is that you cannot easily distinguish it from an actual I/O error. I'd suggest switching to using a SocketChannel rather than a Socket -- then you can interrupt your server thread and it will throw a ClosedByInterruptException instead, which you can catch and handle specifically.
According to the javadoc of the close method:
Any thread currently blocked in an I/O operation upon this socket will throw a SocketException.
So when you call close, socket.receive(packet);, if it is currently in blocking mode, will throw a SocketException which is caught in your catch (IOException e) block and the stacktrace is printed.