So, this is what I have. This is a server program that connects to multiple clients by using threads. As of now, that main loop is pretty much infinite.
Say a client sent a shutdown command to a ServerThread. Would that ServerThread be able to access the main class, break out of the loop, and reach the end of the program?
I tried turning putting isRunning = false in the ServerThread, but that doesn't seem to work.
public class Server
{
public static boolean isRunning = true;
public static void main(String[] args)
{
// init stuff
try {
serverSocket = new ServerSocket(27647);
} catch (IOException e) {
println("Could not listen on port 27647");
}
while(isRunning)
{
Socket clientSocket = null;
try{
clientSocket = serverSocket.accept();
} catch(IOException e) {
println("Could not connect to client");
}
ServerThread serv = new ServerThread(clientSocket);
serv.start();
}
try {
serverSocket.close();
} catch (IOException e1) { }
}
}
You need to make isRunning volatile and you have to close the serverSocket to unblock the accepting thread. I suggest you have a method like
public void close() throws IOException {
isRunning = false;
serverSocket.close();
}
If you call this from any thread, the thread will stop almost immediately.
Related
I have a basic server thread in which I accept sockets with the accept () function. For a certain period of time, I would need to avoid connecting new sockets. I want to do this from another thread by telling the server thread to not make new connections.
public class ServerThread extends Thread {
private boolean running = false;
private final ConnectionManager connectionManager;
private final AtomicBoolean acceptNewConnections;
ServerThread(ConnectionManager connectionManager, int port) {
super("ServerThread");
this.connectionManager = connectionManager;
this.port = port;
this.acceptNewConnections = new AtomicBoolean(false);
}
// This is called from other threads
public void setAcceptNewConnections(boolean value) {
acceptNewConnections.set(value);
}
#Override
public void shutdown() {
acceptNewConnections.set(false);
running = false;
try {
join();
} catch (InterruptedException ignored) {}
}
#Override
public void run() {
running = true;
connectionManager.serverThreadStart();
try (ServerSocket serverSocket = new ServerSocket(port)) {
acceptNewConnections.set(true);
while (running) {
try {
if (acceptNewConnections.get()) {
final Socket socket = serverSocket.accept();
if (acceptNewConnections.get()) connectionManager.addClient(socket);
else socket.close();
} else {
try {Thread.sleep(10);} catch(InterruptedException e){}
}
} catch (SocketTimeoutException ignored) {
//
}
}
} catch (IOException e) {
//
}
connectionManager.serverThreadStop();
}
}
My questions are:
Is there a way to interrupt waiting for a new socket while waiting?
Is there a way to wait for a new socket, but would accept it as needed after waiting for it, not wait and accept it in one command?
How can I pause the server thread while blocking new connections without using Thread.sleep() and useless overusage of cpu?
Thank you so much for help.
I am trying to create a program with Java that can only have one instance of it running at a time.
I am using Sockets and ServerSockets to try to achieve this.
How the program is supposed to work is:
The main method will check if any parameters have been passed, it will try to write the first parameter to the server, if it fails that means, that means that this is the only running instance, so it will open the ServerSocket and then start the frame. If it doesn't fail then the application is already running so it should send the string and the other instance should be able to read it and process it.
Here's the main method:
public static void main(String[] args) {
String fileName = null;
if (args.length >= 1) {
fileName = args[0];
}
if (Singleton.sendSignal(fileName)) {
Frame.getFrame().open(fileName);
Singleton.checkInput();
}
}
And here's the server class:
public class Singleton {
private static final int portNumber = 4243;
private static ServerSocket serverSocket;
private static Socket clientSocket;
private static Socket echoSocket;
public static boolean sendSignal() {
try {
echoSocket = new Socket(InetAddress.getLocalHost().getHostName(), portNumber);
PrintWriter out = new PrintWriter(echoSocket.getOutputStream(), true);
out.write("Open\n");
out.close();
close();
return false;
} catch (Exception e) {
close();
return true;
}
}
public static void checkInput() {
try {
renewReader();
} catch (Exception e) {
close();
}
}
public static void renewReader() throws Exception {
serverSocket = new ServerSocket(portNumber);
clientSocket = serverSocket.accept();
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String inputLine = in.readLine();
if (inputLine.equals("Open")) {
Widget.getInstance().setVisible(true);
}
close();
renewReader();
}
public static void close() {
try {
serverSocket.close();
} catch (Exception e) {
}
try {
clientSocket.close();
} catch (Exception e) {
}
try {
echoSocket.close();
} catch (Exception e) {
}
}
}
Although half of this code works (only one instance runs at a time), only the first set of data are being passed and then the program stops reading. How can I make the socket listen until the program is closed?
I your checkInput() method, you are accepting for client connection once here. Try something like this:
public static void checkInput()
{
//do something here
serverSocket = new ServerSocket(portNumber);
//wait for request from client.
Socket clientSocket = serverSocket.accept();
//
// do your processing here
// call checkInput method again.
checkInput();
}
As soon as another instance it started, server will accept the request, do the processing and then again starts waiting for more requests (for this we called cehckInput again).
Also in your main() add this:
public static void main(String[] args)
{
String fileName = null;
if (args.length >= 1) {
fileName = args[0];
}
if (Singleton.sendSignal(fileName))
{
Frame.getFrame().open(fileName);
// start the server in a thread so that main method can continue on
new Thread()
{
public void run()
{
Singleton.checkInput();
}
}.start();
}
// do your other tasks.
}
On upon termination of program, your sockets will auto close. Also if you want to explicitly close the sockets, you can add a shutdown hook to close it.
A simple hook looks like this.
Runtime.getRuntime().addShutdownHook(your thread that will close sockets);
So I have a multithreaded server, and data sends back and forth correctly, but my write operations stalls on the slower connections. I've noticed that it goes by connection time. The first client to connect always receives data first from the server. The next one has to wait until the first one is done receiving and so on so forth. What I'm looking for is a server that sends data to many clients without waiting for a client to finish receiving. I've read up about NIO (non-blocking), but I'd really prefer keeping my current method, which is to use a separate thread for each client.
Here's the code.
Server:
public class Server implements Runnable {
private Thread thread;
private ServerSocket serverSocket;
private ArrayList<ClientThread> clients;
public Server(int port) throws IOException {
thread = new Thread(this);
clients = new ArrayList<ClientThread>();
serverSocket = new ServerSocket(port);
thread.start();
}
#Override
public void run() {
while (true) {
try {
//Listens to clients connecting.
ClientThread client = new ClientThread(serverSocket.accept());
clients.add(client);
ServerWindow.addText("-- Someone connected!");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public void broadcast(String data) {
broadcast(data, null);
}
public void broadcast(String data, ClientThread exclude) {
int amount = clients.size();
for (int i = 0; i < amount; i++) {
if (!clients.get(i).equals(exclude)) { //Don't send it to that client.
try {
clients.get(i).broadcast(data);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
Client thread object:
public class ClientThread implements Runnable {
private Thread thread;
private Socket socket;
private Scanner input;
private PrintWriter output;
public ClientThread(Socket s) throws IOException {
thread = new Thread(this);
socket = s;
socket.setTcpNoDelay(true);
//socket.setSoTimeout(10); //Send little chunk for 10 milliseconds.
input = new Scanner(socket.getInputStream());
output = new PrintWriter(socket.getOutputStream());
thread.start();
}
public void run() {
while (true) {
if (input.hasNext()) {
reciever(input.nextLine());
}
}
}
private void reciever(String data) {
ServerWindow.addText(data);
ServerWindow.server.broadcast(data, this);
}
public void broadcast(String data) throws IOException {
output.println(data);
output.flush();
}
}
It seems you are calling the broadcast method from the same thread.
This is a common pitfall for users new to multithreading in Java.
The fact that the broadcast method is in a subclass of Thread does not mean it will be executed on that Thread
In fact it will be executed on the thread that called it. The only method that will be executed on your created ClientThread is run() and anything that run() calls while it is executing. If you want said thread to not only read data from your connection but also write to it, you have to modify the run method to listen to external commands to start writing.
I'm trying to do something potentially stupid, but I reckon it's a good idea, so bear with me. I tried to implement it, but I hit an awkward issue with sockets closing between threads - so I want some fresh eyes on the case.
Scenario
I want to write an object from a Client to a Server via sockets. There may be more than one Client communicating with the Server concurrently.
The object, a Message, is handled by the Server through its handling mechanisms. It is proposed that instead of the Server's main thread looking out for new incoming connections, a Listener thread is set up. Once it spots an incoming connection, it alerts the Server, storing the socket in a queue without receiving the data, so it can go back to listening quickly.
In its own time, the Server picks up the waiting socket, spawns a new thread, reads the Message, and closes the socket.
The code
Here's my first thoughts on how this should be implemented. There is a fundamental flaw in it which I will explain below.
Ignore the use of public fields - I'm just trying to make the code short for you guys
public class Server {
public boolean messageWaiting = false;
public static void main(String[] args) {
new Server().run();
}
public void run() {
Listener l = new Listener();
l.listen(this);
try {
while (true) {
System.out.println("I'm happily doing my business!");
Thread.sleep(1000);
if (messageWaiting) {
acceptMessages(l);
}
}
} catch (InterruptedException die) {}
}
private void acceptMessages(Listener l) {
while (!l.waiting.isEmpty()) {
try (
Socket client = l.waiting.poll();
ObjectInputStream ois = new ObjectInputStream(client.getInputStream())
) {
// Handle messages in new threads! (or a thread pool)
new Thread() {
public void run() {
try {
System.out.println(ois.readObject());
} catch (Exception ex) {
ex.printStackTrace();
}
}
}.start();
} catch (Exception ex) {
// Oh no! The socket has already been closed!
ex.printStackTrace();
}
}
}
}
public class Listener {
public ConcurrentLinkedQueue<Socket> waiting = new ConcurrentLinkedQueue<>();
public void listen(final Server callback) {
new Thread() {
public void run() {
try (ServerSocket rxSock = new ServerSocket(7500)) {
while (!isInterrupted()) {
try (Socket client = rxSock.accept()) {
// Once a new socket arrives, add it to the waiting queue
waiting.add(client);
// Alert the server
callback.messageWaiting = true;
} catch (IOException ex) {
ex.printStackTrace();
}
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
}.start();
}
}
public class Client {
public static void main(String[] args) {
try (
Socket txSock = new Socket(InetAddress.getLoopbackAddress(), 7500);
ObjectOutputStream oos = new ObjectOutputStream(txSock.getOutputStream())
) {
oos.writeObject("This is a Message, trust me.");
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
What's wrong with this?
This:
I'm happily doing my business!
I'm happily doing my business!
java.net.SocketException: Socket is closed
at java.net.Socket.getInputStream(Unknown Source)
at Server.acceptMessages(Server.java:30)
at Server.run(Server.java:20)
at Server.main(Server.java:9)
This is because the Java 7 try blocks I'm using close the sockets once they're finished. So why don't I do this manually? Try yourself - you end up with a warning saying you're only ever going to call close() on a null object!
So, how do I avoid the whole issue of my incoming socket being closed before the Server thread picks up on it? Or is this a bad idea anyway and I should do something else?
Your statement in Listener
try (Socket client = rxSock.accept()) { ...
Is a try-with-resources for the client socket. As soon as you add it to the queue and exit the try block, the socket gets auto-closed.
I have an app that listens to incoming connections on a specified hostname and port. The listening is invoked with the method listen() (see below), which waits constantly for an incoming connection using ServerSocket.accept(), creating a new Thread to handle the input stream.
private ServerSocket serverSocket;
private Thread listenerThread;
public void listen() throws IOException {
this.listenerThread = new Thread(new Runnable() {
#Override
public void run() {
while (true) {
try {
Socket socket = TheServerClass.this.serverSocket.accept();
// Create new thread to handle the incoming connection
}
catch (IOException exc) { }
}
}
});
this.listenerThread.start();
}
Now I want to stop the running of listenerThread. But when I call this.listenerThread.interrupt(), this doesn't work.
I thought you can stop a thread by interrupting it, so why isn't that working?
(Notice: A possible solution is to close the ServerSocket using this.serverSocket.close(), but can it be accomplished with interrupt() or something?)
Call serverSocket.close(),
I guess since you are not doing IO yet - you can not interrupt it, and since the accept() doesn't throw InterruptedException you won't be able to interrupt it. The thread is interrupted, but that flag you have to check for yourself Thread.isInterrupted().
See How can I interrupt a ServerSocket accept() method?.
The answer is in the question. You need to close the socket. It's done using serverSocket.close(). Thread.interrupt() doesn't care about sockets.
Use this:
public class MyThread extends Thread {
private boolean stop;
private ServerSocket serverSocket;
public MyThread(ServerSocket ss) {
this.serverSocket = ss;
this.stop = false;
}
public void setStop() {
this.stop = true;
if (this.ss != null) {
this.ss.close();
}
}
public void run() {
while (!stop) {
try {
Socket socket = serverSocket.accept();
// Create new thread to handle the incoming connection
}
catch (IOException exc) { }
}
}
}
and from the listen() method just call setStop() method of the thread.