This question already exists:
how to close a thread out of multiple instantiations
Closed 6 years ago.
I am making a skype like program. I have an "accept" thread and multiple User threads for each call. I store the accept thread in an arraylist every time a call is started. What I need to do is when there is less than two people in the call is interrupt the accept thread that goes with the user thread that send the command. To do this when an accept thread is created I log the index number and pass it on to all of the user threads so when it needs to send the interrupt command it just gets the thread from the arraylist using the index number. But when I send it nothing happens. Could someone tell me why this is? Thank you in advance!!!
Accept Thread
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
public class accept extends Thread { // Chat and Voice Server User Accept
private ServerSocket TextChat;
private Socket sText;
private int TextPort;
private int index;
boolean running = true;
accept(int ChatPort) {
TextPort = ChatPort;
chat.threads.add(this);
index = chat.threads.indexOf(Thread.currentThread());
try {
TextChat = new ServerSocket(ChatPort);
} catch (IOException e) {
System.out.println("Cant create server on port "+ ChatPort);
try {
TextChat.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
public void run() {
while(running == true) {
try {
sText = TextChat.accept();
System.out.println(sText+" Joined the chat");
new TextChat(sText, TextPort, index).start();
} catch (IOException e) {
System.out.println("Server on port "+TextChat+" Can't Accept");
try {
TextChat.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
System.out.println("Server on port "+TextChat+" Is Shutting Down");
try {
TextChat.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
public void setRunning(boolean run) {
running = run;
}
}
User Thread
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.ArrayList;
public class TextChat extends Thread {
private ObjectOutputStream out;
private ObjectInputStream in;
private Socket s;
private String msg;
private Boolean running = true;
private int port;
private String name;
private int threadIndex;
TextChat(Socket sText, int TextPort, int index) {
s = sText;
port = TextPort;
threadIndex = index;
try {
out = new ObjectOutputStream(s.getOutputStream());
if(port <= 65511) {
chat.users1.add(out);
}else {
chat.users2.add(out);
}
in = new ObjectInputStream(s.getInputStream());
} catch (IOException e) {
e.printStackTrace();
}
}
public void run() {
while(running == true) {
try {
msg = in.readObject().toString();
String[] part = msg.split("/");
if(part[0].equals("MYNAME")) {
name = part[1];
System.out.println("NAME ADDED "+name);
}
if(!msg.equals(null)) {
if(port <= 65511) {
for(ObjectOutputStream o : chat.users1) {
o.writeObject(name+": "+msg);
}
}else {
for(ObjectOutputStream o : chat.users2) {
o.writeObject(name+": "+msg);
}
}
}
} catch (ClassNotFoundException | IOException e) {
System.out.println(name+" Disconneted from chat");
if(port <= 65511) {
chat.users1.remove(out);
}else {
chat.users2.remove(out);
}
if(chat.users1.size() < 2) {
System.out.println("Chat server on port "+port+" is shutting down due to not enough people in call");
chat.threads.get(threadIndex).running = false;
running = false;
}
}
}
}
}
When you interrupt a thread, all it does is set a flag. This flag is monitored by some operations, but unless you are using one of these operations, nothing happens.
If you have a thread which is blocked on IO, the most effective why to unblock the thread is to close() the stream or socket to kill it. I would also set a flag e.g. boolean closed so you can detect that any IOException thrown was the cause of you closing the socket, rather than an error.
EDIT: Some suggestions.
always uses TitleCase for class names.
avoid mutable static fields wherever possible. In this case, I don't believe you need any.
always pass shared state, and make sure it's thread safe is used from multiple threads.
Don't extend Thread rather implement a Runnable and wrap it with a Thread
You only need one server port in this cases, unless you are implementing this as a peer-to-peer service, but that doesn't appear to be the case.
no need to write verbose expressions like while (running == true) when while (running) will do.
if you have a boolean running which is shared between threads make sure it is volatile.
DON'T catch an Exception and pretend it didn't happen. You are better off throws IOException on the constructor instead of creating a dead object.
Wrap each client in an object, and only register this object, not the thread which runs the object. As you have noted, holding the Thread isn't very useful.
Don't use a wrapper like Boolean when you don't expect a null value. Use a boolean which can't be null instead.
I suggest using flags which are false by default. Instead of running used closed. This makes it easier to know what the default/normal value of the variable is.
don't hard code ports like this in code, you should pass a flag or an id to say how it should behave.
Only use Object Stream for passing general objects. For passing text you can use a Writer/Reader or Data Stream which is simpler.
You don't need to check for null for a value which cannot be null e.g. msg.equals(null) can''t every return true.
Use the spell checker in your IDE Disconneted should be Disconnected
I wouldn't disconnect when you have 1 as someone might be about to join.
Related
public class Slave implements Runnable {
public ServerSocket slaveSocket;
public Slave(ServerSocket sk) {socket = sk;}
#Override
public void run() {
Socket client = slaveSocket.accept(); // slave will wait to serve a client
// more code...
Socket clientPart2 = slaveSocket.accept();
// more code...
}
}
public class Server {
public static void main(String[] args) {
// for example only, incomplete code
ServerSocket serverSocket = new ServerSocket(0); // a client connect to 8088
Slave slave = new Slave(serverSocket);
new Thread(slave).start(); // slave serve the current client, the server wait for new client
// send new slave's port to client ...
}
}
So I have a server that serves multiple clients at once. Whenever a client connects, the server will create a new Slave, send the IP/port of that slave to the client, then the client will work with the slave.
However, if the client receives the slave's address then do nothing (or quit) (Edit: it means the client and server are connected but the client do nothing, because for example the user goes for lunch) slaveSocket.accept() causes that slave Thread to run forever, which is wasteful.
I want the slave thread to exit after 30 second of waiting for slaveSocket.accept(). Since slaveSocket.accept() is blocking, I cannot do that from inside the void run().
What is the correct, clean way to solve this problem? Thank you.
Edit 1: a ServerSocket is passed to the slave because the client can have multiple processes that will connect to that slave. So it doesn't just perform one function.
If you set a timeout with setSoTimeout and no client connects, ServerSocket.accept will throw an exception. You can catch this exception.
To set a timeout of 30 seconds, use:
serverSocket.setSoTimeout(30000)
Non-blocking I/O:
Take a look at AsynchronousServerSocketChannel's accept method which returns a Future. Then the Future has a getter with timeout which can do what you are asking.
Note: you may read a related tutorial.
Then the getter will return an AsynchronousSocketChannel which can be converted back to blocking via the corresponding Channels.newInputStream and Channels.newOutputStream methods to be used with the blocking approach in the worker threads.
Blocking I/O:
I think you actually meant on how to implement a server which accepts clients sequentially and serves them in parallel, with blocking I/O. If that is the case, then you may take a look at the following example:
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Objects;
public class Main {
public static class Worker implements Runnable {
private final Socket sck;
private OutputStream os;
private InputStream is;
public Worker(final Socket sck) {
this.sck = Objects.requireNonNull(sck);
}
#Override
public void run() {
try {
os = sck.getOutputStream();
is = sck.getInputStream();
//ALL the work with the client goes here, unless you need more than one connections with him.
}
catch (final IOException iox) {
System.err.println(iox);
}
finally {
try { is.close(); } catch (final IOException | RuntimeException x) {}
try { os.close(); } catch (final IOException | RuntimeException x) {}
try { sck.close(); } catch (final IOException | RuntimeException x) {}
}
}
}
public static void main(final String[] args) {
ServerSocket srv = null;
try {
srv = new ServerSocket(8088);
while (true)
new Thread(new Worker(srv.accept())).start();
}
catch (final IOException iox) {
System.err.println(iox);
}
finally {
try { srv.close(); } catch (final IOException | RuntimeException x) {}
}
}
}
I am working on a Java UDP application. There is a thread in the application whose only job is to listen to a server on a specific port.
I wrote the application under the mistaken assumption that the server I am listening to will always be up; this, however, was a bad assumption.
If my application starts after the server is running, then everything works fine. If my application starts before the server is up, or if the server is restarted while my application is running, my application breaks.
MainClass.java
public class MainClass {
public static void main(String[] args){
ListeningClass myListeningClass = new ListeningClass();
Thread listenerThread = new Thread(myListeningClass);
listenerThread.setName("My Listening Thread");
listenerThread.start();
}
}
ListeningClass.java
public class ListeningClass implements Runnable {
private volatile boolean run = true;
private byte[] receiveBuffer;
private int receiveBufferSize;
private DatagramSocket myDatagramSocket;
private DatagramPacket myDatagramPacket;
#Override
public void run(){
try {
myDatagramSocket = new DatagramSocket(null);
InetSocketAddress myInetSocketAddress = new InetSocketAddress(15347);
myDatagramSocket.bind(myInetSocketAddress);
receiveBuffer = new byte[2047];
myDatagramPacket = new DatagramPacket(receiveBuffer, 2047);
while(run){
myDatagramSocket.receive(myDatagramPacket);
byte[] data = myDatagramPacket.getData();
receiveBufferSize = myDatagramPacket.getLength();
// process the data received here
}
} catch (SocketException se){
// do stuff
} catch (IOException ioe){
// do stuff
}
}
public boolean isRun(){
return run;
}
public void setRun(boolean run){
this.run = run;
}
}
Like I said, if my application starts after the server is running, everything works perfectly, just as expected. However, if my application starts before the server is running, then nothing works. Obviously, is is because the thread tries to open the connection once, and if it fails, then it never tries again.
I moved the DatagramSocket open code to within the while block but that wasn't pretty. I got a bunch of "port already bound" errors.
So, how can I reconstruct this so that it works properly?
It's not really a concurrency question. You just need to check the exceptions thrown on receive and handle appropriately. In this case, rebind the socket. See the docs for receive.
For example:
...
while(run) {
try {
myDatagramSocket.receive(myDatagramPacket);
byte[] data = myDatagramPacket.getData();
receiveBufferSize = myDatagramPacket.getLength();
// process the data received here
} catch (IOException ioe) {
// Perhaps use PortUnreachableException but not guaranteed
rebind(myDatagramSocket, myInetSocketAddress);
}
}
private void rebind(DatagramSocket s, InetSocketAddress addr) {
s.bind(addr);
}
I think that should be enough. the point is, you only want to rebind if your receive indicates there's an I/O problem with the server. You're binding for each receive if you place the bind in the loop - which is ok in your happy-path situation.
The important things to note here are the precise points in which the program fails and the type of exception that you're given.
Presumably it fails on line myDatagramSocket.receive(myDatagramPacket);, but double check with the stacktrace on your exception. The second thing to check is the type of exception. Is it a SocketException or a subclass of SocketException? Is there a specific error code? Try to be as specific as possible.
At this point, you should surround the section of code that fails in its own try catch within the while loop. You want to be able to say that should it fail, your thread will sleep and try again after a hiatus (to not bombard the server with requests). And to simply things further, I would section the code in its own method, so you would expect something like:
public class ListeningClass implements Runnable {
private static final int MAX_RETRIES = 30;
private static final int RETRY_SLEEPTIME = 30000;
private volatile boolean run = true;
private InetSocketAddress myInetSocketAddress;
#Override
public void run(){
try {
DatagramSocket myDatagramSocket = new DatagramSocket(null);
myInetSocketAddress = new InetSocketAddress(15347);
myDatagramSocket.bind(myInetSocketAddress);
byte[] receiveBuffer = new byte[2047];
DatagramPacket myDatagramPacket = new DatagramPacket(receiveBuffer, 2047);
awaitRequests(myDatagramSocket, myDatagramPacket)
} catch (SocketException se){
// do stuff
} catch (IOException ioe){
// do stuff
}
}
private void awaitRequests(DatagramSocket myDatagramSocket, DatagramPacket myDatagramPacket) throws SocketException, IOException {
int maxRetries = MAX_RETRIES;
while(run){
try {
myDatagramSocket.receive(myDatagramPacket);
byte[] data = myDatagramPacket.getData();
// Packet received correctly, reset retry attempts
maxRetries = MAX_RETRIES;
process(myDatagramPacket);
} catch (SocketException e) {
maxRetries--;
// Good place to write to log of some kind
if(maxRetries == 0) {
throw e;
}
Thread.currentThread().sleep(RETRY_SLEEPTIME);
// Lets attempt to restablish the connection
reconnect(myDatagramSocket);
}
}
}
private void process(DatagramPacket myDatagramPacket) {
int receiveBufferSize = myDatagramPacket.getLength();
// process the data received here
}
private void reconnect(DatagramSocket myDatagramSocket) {
myDatagramSocket.bind(myInetSocketAddress);
}
public boolean isRun(){
return run;
}
public void setRun(boolean run){
this.run = run;
}
}
Note a couple things. I only caught SocketException because I am assuming the type of exception that you're getting is a SocketException. If you're getting an IOException of some kind, then you should check that. Better still if you're specifying the subtype of that exception. The reason is this: you don't want to blanket handle all errors, but only those pertaining to the server being down. If the program lacks authentication to open the socket, you would want to fail immediately, not continually retry.
The second thing is that I've separated the processing of the packet in its own method, because I think that's the proper thing to do in these cases.
Im using this code:
final int LOCK_PORT= 54321;
ServerSocket ss = new ServerSocket(LOCK_PORT);
The thing is that in the same port you cannot listen to 2 different applications (teachers theory).
This code was implemented into an application and the same instance ran more than 1 time. The objective is that the same instance is not suposed to run more than 1 time in the same port. However this isnt working and it does run...
// Edited, more code...
public VentanaPropiedades() {
initFirst();
initComponents(); //graphic components of Matisse
}
private void initFirst() {
loadProperties(); //just internal values of the program, nothing to do
activateInstance();
}
private void activateInstance() throws Exception {
try {
final int LOCK_PORT= 54321;
ServerSocket ss = new ServerSocket(LOCK_PORT);
} catch (Exception e) {
System.out.println(e);
throw e;
}
}
private void killProgram() {
setVisible(false);
dispose();
System.exit(0);
}
private void validateInstance() {
try {
activateInstance();
} catch (Exception ex) {
killProgram();
}
}
--------------------------Supposed Solution---------------------------
The error catched when the 2nd instance DOES NOT RUN is this one:
java.net.BindException: Address already in use: JVM_Bind
However, this error not always happens and you can run more than 1 instance of the same program.
It doesn't work. You should get a BindException the second time you try to create the
socket. See if you accidentally catch it somewhere or if the port actually is different
or something similar.
The ServerSocket must be declared outside the method, right after main:
public class VentanaPropiedades extends javax.swing.JFrame {
ServerSocket ss = null;
// ... more code
}
And the activation method should use the reference:
private void activateInstance() throws Exception {
try {
final int LOCK_PORT= 54321;
ss = new ServerSocket(LOCK_PORT); // note the missing "ServerSocket" before ss
} catch (Exception e) {
System.out.println(e);
throw e;
}
}
The problem is that if you create the variable ServerSocket inside a method, the garbage collector will clean it once the method is done. If the variable is declared above, the garbage collector wont collect and clean it because the declared variable will stay instantiated but with NO reference.
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.
I got thread for server in my Android app and need to handle it properly when user decide to close it. I choose non-blocking ServerSocketChannel which accept() clients.
And got this
public class SocketServer extends Thread
{
private static final String LOG_TAG = "SocketServer";
private boolean isRunning = false;
private ServerSocketChannel listener = null;
public void _stop()
{
this.isRunning = false;
}
public void _start()
{
this.isRunning = true;
this.start();
}
private void free()
{
try
{
listener.close();
}
catch (IOException e)
{
//Error handle
}
listener = null;
}
public SocketServer(int port)
{
super();
try
{
listener = ServerSocketChannel.open();
listener.configureBlocking(false);
listener.socket().bind(new InetSocketAddress(port));
}
catch (IOException e)
{
//Error handle
}
}
public void run()
{
SocketChannel client = null;
while(isRunning)
{
try
{
client = listener.accept();//GC going mad
}
if(client != null)
Log.i(LOG_TAG, "ACCEPTED CLIENT");
catch (IOException e)
{
//Error handle
}
}
free();
}
All i'm doing is accepting new client - getting null because of no incoming connections and do it again until server is stopped.
ServerClient client is null at start and assigned to null by accept() if no connections available.
But Java's garbage collector thinks what client is somehow init by accept() or accept() somehow allocate some memory, which GC cleans after every while loop.
If comment accept() line (e.g do nothing) where will be no GC at all, so problem exactly in accept().
This quite not right in my opinion.
P.S. If there is some way to break blocking ServerSocket accept()/Socket read() state and exit properly, please tell me.
P.S. 2 Is it safe to write/ read to SocketChannel socket() as to Socket, will it block thread?
Many operations in Java create temporary objects internally to do their work.
You are much better off using a blocking SocketServer. This way the objects it creates is only on a per-accepted-Socket basis rather than a per-attempt basis.
I suggest you implement blocking NIO with a thread (or two) per connection first. If then you discover you have a performance issue with the number of threads you have, try using a Selector with non-blocking NIO.