In my android app, my activity is starting another thread for some socket network operations, and this thread is always waiting for incoming data from the socket(blocking on read() function in a while loop).
Now, when my activity gets destroyed, I would like to keep things clean, and destroy that thread. To implement this functionality, I defined a volatile boolean variable isSupposedToStop which would be initialized to false, and when onStop() gets called, it sets that boolean to true, and calls socket.shutdownInput() which causes the thread blocking on read() to throw an IOException, then read the isSupposedToStop boolean to know that it is supposed to stop.(if you have better ways feel free to discuss it).
So, in my run() implementation after connecting my socket I have:
sock= new Socket("127.0.0.1", 1234);
InputStream is= sock.getInputStream();
byte[] buffer= new byte[200];
while(true){
if(isSupposedToStop) return;
try {
is.read(msgSizeBuff, 0, 200);
} catch(IOException e){
}
if(isSupposedToStop) return;
//do something with the received message
}
in onStop(), I have:
isSupposedToStop= true;
if(sock!= null) {
try {
sock.shutdownInput();
sock.close();
} catch (IOException e) {
}
}
thread.join()
that is working good. as when the thread is waiting for new data (blocking on read()), read() throws an IOException immediately when onStop() calls shutdownInput(), and control is back to the thread which reads my boolean value and exits.
but the problem is happening if onStop() gets called when the thread is still waiting to establish the connection (blocking on new Socket()) so if the host is down for example the app freezes for about 3 seconds, so do you recommend to just omit the thread.join() call? or is there a way to wake up this thread?
Once you have called the read method you are essentially blocked - you can only escape by interrupting the thread.
public void test() {
Thread socketThread = new Thread(new Runnable() {
#Override
public void run() {
System.out.println("Hello");
}
});
// Do your stuff.
//...
// Time to quit - should abort any blocked reads.
socketThread.interrupt();
}
Another alternative - this may not work at all - is to use the available method of InputStream.
public void test() throws IOException {
Socket sock = new Socket("127.0.0.1", 1234);
InputStream is = sock.getInputStream();
boolean done = false;
while (!done) {
int available;
if ((available = is.available()) > 0) {
// Your read stuff.
is.read(buffer, 0, available);
}
}
}
The new Socket isn't supposed to block networking. Not even a SYN/ACK.
Therefore you can setSOTimeout() right after construction. But you wouldn't set it to anything less than 3 seconds to be fair.
You are suggesting that it takes 3 seconds to respond to a socket.close()... So I fear it cannot get any faster, but you can try a thread.interrupt(), in case it is sitting in interruptable (non native) code.
Related
I need to continuously listen to a remote socket and react on given input.
public void listen(String ip, int port) {
try (
Socket socketListener = new Socket(ip, port);
BufferedReader portReader = new BufferedReader(new InputStreamReader(socketListener.getInputStream()));
) {
while (true) {
while (!portReader.ready()) {
// Wait for next PORT message
}
Logger.log(LogComponent.SOCKET, "Event received");
}
}
}
What am I doing so enormously wrong that the code above is using 100% CPU load?
While debugging I can see that the while-!portreader-loop is the evildoer. But most of the examples I've found are doing it the same way.
EDIT #1
Considering your comments I have following solution right now:
try {
Socket SocketListener = new Socket(ip, port);
BufferedReader portReader =
new BufferedReader(
new InputStreamReader(SocketListener.getInputStream())
);
// We do not use common while(true)-pattern for reading the input.
// Instead, we check for new input 3 times a second.
ScheduledExecutorService executor = Executors.newScheduledThreadPool(10);
executor.scheduleAtFixedRate(() -> {
try {
processInput(portReader);
} catch (IOException e) {
e.printStackTrace();
}
}, 0, 333, TimeUnit.MILLISECONDS);
} catch (Exception exception) {
exception.printStackTrace();
}
And processInput(0) is doing the action now.
This ends in better performance results than using simply Thread.sleep() - though I don't understand why.
When using this approach: Can the code miss some messages from the socket? I mean during the intervals?
Your CPU is busy because it's processing instructions in the while loop.
To avoid it, you should use a function that waits for the socket to be connected. If you are waiting for incoming connection, use Socket.accept(). This will block the thread (i.e. thread won't be scheduled for execution) until connection is established.
Do not use Thread.sleep() as others have suggested. While this does lower the CPU usage somewhat, it will still burn CPU unnecessarily, as well as introduce a latency. This is a bad engineering practice.
Apart from that, you might want to look into non-blocking or asynchronous I/O. See here for more information.
The problem is that your code inside your while(true) is consuming all the CPU. Make a single change like:
public void listen(String ip, int port) {
try (Socket socketListener = new Socket(ip, port);
BufferedReader portReader = new BufferedReader(new InputStreamReader(socketListener.getInputStream()));) {
while (true) {
while (!portReader.ready()) {
// Wait for next PORT message
try {
Thread.sleep(1);
} catch(InterruptedException e) {
//handle InterruptedException
}
}
Logger.log(LogComponent.SOCKET, "Event received");
}
}
}
I have this runnable receiver which I want to stop. but as it is a constantly receiving socket it's thread is in blocking mode.
I found that I had to stop the socket from outside the thread itself, using socket.close()
So i defined a public static socket. (which itself is bad, i guess?) then i start new threads and try stopping them with this code, (have not changed anything)
public static DatagramSocket socket;
Starting each thread seperatly works fine. but as the socket now is global, I can't stop them individually. How do I make the socket var global but individual? Or what do I need to make this possible?
public void startSls () throws SocketException{
try{
socket = new DatagramSocket(parseInt(port));
}catch (SocketException e) {
Log.e("CCSstream", e.toString());
}
slst = new Thread(new slss(port));
slst.start();
}
public void stopSls(){
socket.close();
stopSLS = true;
slst.interrupt();
runThreads1 = false;
}
If anything is unclear I can explain.
Thanks
I have a class which connects to a server as below.
#Override
public void run() {
while (running) {
try {
msgHandler.log("Connecting to " + host + ":" + port);
Socket s = new Socket(host, port);
if (s.isConnected() && !s.isClosed()) {
msgHandler.connectionInit(s);
}
BufferedInputStream input = new BufferedInputStream(s.getInputStream());
}
}
The consumer which is the msgHandler, frequently polls the socket if a connection ever goes down as below.
#Override
public void connectionInit(Socket s) throws IOException {
logger.info("Connected to AWW Service on " + configuration.getAwwHost() + ":" + configuration.getAwwPort());
output = new BufferedOutputStream(s.getOutputStream());
connector.componentReady();
Timer t = new Timer();
t.schedule(new TimerTask() {
#Override
public void run() {
try {
pollServer();
} catch (IOException e) {
// SOCKET GETS BROKEN HERE
}
}
}, 0, 25000);
}
Question is, how can i communicate from the exception i get when the socket connection gets broken back to the run() thread, so it can try to reinitialize the socket and the input stream?
I dont think a notify() or wait() mechanism is appropriate here as wait() will just put the run() thread to sleep.
I was thinking whats the equivalent of setting a flag when the connection gets broken, and the run() thread constantly checks the flag, and when it is set to true, it reinitialize the socket. But i am sure there would be a more efficient multi threading approach native to java for achieving this.
I think the simplest approach is using an AtomicBoolean variable that is accessible to both threads - you could pass the variable in when constructing each thread's run class if necessary. Nice thing about AtomicBoolean is that it is already thread safe/synchronized and mutable so that it can be passed around and modified by reference.
See this similar question for some more details.
I think that in the run() function, you should have a code like the following one.
// ...
try
{
// ...
int read = input.read(...);
// ...
}
catch (IOException e)
{
// TODO: terminate the thread and restart a new connection
}
So, if an error occurs during the pollServer() call, also my code above should generate an exception.
Also when you call the close function of a Socket object, the input and output streams will generate the relative exceptions.
I'm trying to use server sockets to set up a connection between a client and a server. I'm also not using java.nio.
The problem is that I'm constantly sending a test message, and detecting whether if it is successful in sending the message (the client is still connected), if not, then the client is disconnected.
Shown here:
try
{
Scanner in = new Scanner(socket.getInputStream());
BufferedReader in_2 = new BufferedReader(new InputStreamReader(socket.getInputStream()));
while(stopThread)
{
if(in_2.ready())
{
String message = in_2.readLine();
dt = new DateTime();
PrintStream out = new PrintStream(socket.getOutputStream());
server.detect(message, dataSets, out);
dataSets.add(message);
GUI.textArea_1.append(message + "\r\n");
GUI.textArea_1.setCaretPosition(GUI.textArea_1.getDocument().getLength());
}
else
{
PrintStream out = new PrintStream(socket.getOutputStream());
out.println("Testing Connection \r\n");
if(out.checkError())
{
try
{
socket.close();
}
catch (IOException e)
{
e.printStackTrace();
}
stopThread = false;
GUI.textArea.append(userName + " disconnected \r\n");
GUI.textArea.setCaretPosition(GUI.textArea.getDocument().getLength());
server.inputDataForm(userName, dt, dataSets);
}
Thread.sleep(3000);
}
}
The problem is that the Thread.sleep(3000) is actually interfering with getting data, since after 3 seconds, I will get a huge amount of data (because I stopped the thread for 3 seconds).
Now, what I proposed is a anonymous class in the else statement.
class runThread implements runnable
{
void run()
{
//Put the else statement here
}
}
But the stopThread = false is not a constant, which I'm trying to control.
Other threads I've searched only puts variables inside main inside the anonymous class, but I need stopThread to stop the while loop if the client is disconnected.
Does anyone have an idea?
Thanks!
Consider setting a short timeout on your socket. This will allow you to control how long your thread will block while waiting for data from the socket.
If data are not quickly available, a very specific java.net.SocketTimeoutException will be raised. You can handle this exception by checking your stopThread flag. If it is set, you can return from the method. Otherwise, the socket is still valid and you can try another read operation with timeout.
If any other exception type is thrown, your socket is probably no longer valid.
socket.setSoTimeout(20); /* 1/50th of a second. */
BufferedReader in = new BufferedReader
(new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8));
while (!stop) {
try {
String message = in.readLine();
if (message == null)
handleEOF();
else
handleMessage(message);
} catch(SocketTimeoutException ignore) {
/* Loop back to check "stop" flag. */
continue;
} catch(IOException ex) {
handleDisconnection();
break;
}
}
By the way, if you are using Swing, remember that you can only modify graphical components from Swing's Event Dispatch Thread, and you can't tie up the EDT in long-running operations like this socket handling. You should be passing tasks from this thread to Swing's invokeLater() utility.
Why don't you make a class that implements runnable but also has the method stop();
public class MyRunner implements Runnable(){
MutableBoolean stop = false;
public void run(){...}
public void stop(){
stop = true;
}
}
I'm trying to create a server to send a message which is based on the calculation result from another class.
My question is that since the calculation result is from another class, how do I make the server pause till the result is ready, and how should I pass the result to my server class and send out the result?
public class MyServer {
ServerSocket providerSocket;
Socket connection = null;
static ObjectOutputStream out;
ObjectInputStream in;
String message;
public static String myServerSend;
BufferedReader data = new BufferedReader(data);
MyServer() {}
void run() {
try {
providerSocket = new ServerSocket(2013, 10);
System.out.println("Waiting for connection");
connection = providerSocket.accept();
out = new ObjectOutputStream(connection.getOutputStream());
out.flush();
in = new ObjectInputStream(connection.getInputStream());
do {
try {
message = (String) in.readObject();
System.out.println("server receive>" + message);
// HERE IS MY QUESTION
// myServerSend is the result from other class,
//How can I pause the server here till myServerSend is ready???????
sendMessage(myServerSend);
} catch (ClassNotFoundException classnot) {
System.err.println("Data received in unknown format");
}
} while (!message.equals("bye"));
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
//write msg into ObjectOutputStream
public static void sendMessage(String msg) {
try {
out.writeObject(msg);
out.flush();
System.out.println("server send>" + msg);
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
Use
Thread.sleep(30000); // Milli secs - 30 secs -- Put your sleep time
sendMessage(myServerSend);
Without more specific info about what you have tried and why you have discarded what you have tried, I see several options here.
Call directly the other class and wait till the result is ready. This may not be a good idea if the calculation takes too long, but if not, it's the simplest way.
You can apply polling and get the server to sleep for a certain amount of time to not exhaust resources while waiting for an answer.
Use synchronized objects and concurrency via wait and notify methods. Some useful links on this: 1 2 3
You have few options to acheive this:
1- Create a Thread for your calculation and call join to make your server wait for the thread to finish
Thread thread = new Thread() {
public void run(){
// Call your calculation class
}
}
thread.start();
thread.join(); // surround with try and catch
// or you can use to timeout if the calculation took long
// thread.join(MAX_TIME_MILLIS);
sendMessage(myServerSend);
2- Use wait/notify on a shared object between your server and calculation class
3- Use semaphore object initialized with 0 and call acquire in your server class to wait and call release after you finish your calculations, see my answer here for an example