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.
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, 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.
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.
I am working on a java program that is essentially a chat room. This is an assignment for class so no code please, I am just having some issues determining the most feasible way to handle what I need to do. I have a server program already setup for a single client using threads to get the data input stream and a thread to handle sending on the data output stream. What I need to do now is create a new thread for each incoming request.
My thought is to create a linked list to contain either the client sockets, or possibly the thread. Where I am stumbling is figuring out how to handle sending the messages out to all the clients. If I have a thread for each incoming message how can I then turn around and send that out to each client socket.
I'm thinking that if I had a linkedlist of the clientsockets I could then traverse the list and send it out to each one, but then I would have to create a dataoutputstream each time. Could I create a linkedlist of dataoutputstreams? Sorry if it sounds like I'm rambling but I don't want to just start coding this, it could get messy without a good plan. Thanks!
EDIT
I decided to post the code I have so far. I haven't had a chance to test it yet so any comments would be great. Thanks!
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.ServerSocket;
import java.util.LinkedList;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
public class prog4_server {
// A Queue of Strings used to hold out bound Messages
// It blocks till on is available
static BlockingQueue<String> outboundMessages = new LinkedBlockingQueue<String>();
// A linked list of data output streams
// to all the clients
static LinkedList<DataOutputStream> outputstreams;
// public variables to track the number of clients
// and the state of the server
static Boolean serverstate = true;
static int clients = 0;
public static void main(String[] args) throws IOException{
//create a server socket and a clientSocket
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(6789);
} catch (IOException e) {
System.out.println("Could not listen on port: 6789");
System.exit(-1);
}// try{...}catch(IOException e){...}
Socket clientSocket;
// start the output thread which waits for elements
// in the message queue
OutputThread out = new OutputThread();
out.start();
while(serverstate){
try {
// wait and accept a new client
// pass the socket to a new Input Thread
clientSocket = serverSocket.accept();
DataOutputStream ServerOut = new DataOutputStream(clientSocket.getOutputStream());
InputThread in = new InputThread(clientSocket, clients);
in.start();
outputstreams.add(ServerOut);
} catch (IOException e) {
System.out.println("Accept failed: 6789");
System.exit(-1);
}// try{...}catch{..}
// increment the number of clients and report
clients = clients++;
System.out.println("Client #" + clients + "Accepted");
}//while(serverstate){...
}//public static void main
public static class OutputThread extends Thread {
//OutputThread Class Constructor
OutputThread() {
}//OutputThread(...){...
public void run() {
//string variable to contain the message
String msg = null;
while(!this.interrupted()) {
try {
msg = outboundMessages.take();
for(int i=0;i<outputstreams.size();i++){
outputstreams.get(i).writeBytes(msg + '\n');
}// for(...){...
} catch (IOException e) {
System.out.println(e);
} catch (InterruptedException e){
System.out.println(e);
}//try{...}catch{...}
}//while(...){
}//public void run(){...
}// public OutputThread(){...
public static class InputThread extends Thread {
Boolean threadstate = true;
BufferedReader ServerIn;
String user;
int threadID;
//SocketThread Class Constructor
InputThread(Socket clientSocket, int ID) {
threadID = ID;
try{
ServerIn = new BufferedReader(
new InputStreamReader(clientSocket.getInputStream()));
user = ServerIn.readLine();
}
catch(IOException e){
System.out.println(e);
}
}// InputThread(...){...
public void run() {
String msg = null;
while (threadstate) {
try {
msg = ServerIn.readLine();
if(msg.equals("EXITEXIT")){
// if the client is exiting close the thread
// close the output stream with the same ID
// and decrement the number of clients
threadstate = false;
outputstreams.get(threadID).close();
outputstreams.remove(threadID);
clients = clients--;
if(clients == 0){
// if the number of clients has dropped to zero
// close the server
serverstate = false;
ServerIn.close();
}// if(clients == 0){...
}else{
// add a message to the message queue
outboundMessages.add(user + ": " + msg);
}//if..else...
} catch (IOException e) {
System.out.println(e);
}// try { ... } catch { ...}
}// while
}// public void run() { ...
}
public static class ServerThread extends Thread {
//public variable declaration
BufferedReader UserIn =
new BufferedReader(new InputStreamReader(System.in));
//OutputThread Class Constructor
ServerThread() {
}//OutputThread(...){...
public void run() {
//string variable to contain the message
String msg = null;
try {
//while loop will continue until
//exit command is received
//then send the exit command to all clients
msg = UserIn.readLine();
while (!msg.equals("EXITEXIT")) {
System.out.println("Enter Message: ");
msg = UserIn.readLine();
}//while(...){
outboundMessages.add(msg);
serverstate = false;
UserIn.close();
} catch (IOException e) {
System.out.println(e);
}//try{...}catch{...}
}//public void run(){...
}// public serverThread(){...
}// public class prog4_server
I have solved this problem in the past by defining a "MessageHandler" class per client connection, responsible for inbound / outbound message traffic. Internally the handler uses a BlockingQueue implementation onto which outbound messages are placed (by internal worker threads). The I/O sender thread continually attempts to read from the queue (blocking if required) and sends each message retrieved to the client.
Here's some skeleton example code (untested):
/**
* Our Message definition. A message is capable of writing itself to
* a DataOutputStream.
*/
public interface Message {
void writeTo(DataOutputStream daos) throws IOException;
}
/**
* Handler definition. The handler contains two threads: One for sending
* and one for receiving messages. It is initialised with an open socket.
*/
public class MessageHandler {
private final DataOutputStream daos;
private final DataInputStream dais;
private final Thread sender;
private final Thread receiver;
private final BlockingQueue<Message> outboundMessages = new LinkedBlockingQueue<Message>();
public MessageHandler(Socket skt) throws IOException {
this.daos = new DataOutputStream(skt.getOutputStream());
this.dais = new DataInputStream(skt.getInputStream());
// Create sender and receiver threads responsible for performing the I/O.
this.sender = new Thread(new Runnable() {
public void run() {
while (!Thread.interrupted()) {
Message msg = outboundMessages.take(); // Will block until a message is available.
try {
msg.writeTo(daos);
} catch(IOException ex) {
// TODO: Handle exception
}
}
}
}, String.format("SenderThread-%s", skt.getRemoteSocketAddress()));
this.receiver = new Thread(new Runnable() {
public void run() {
// TODO: Read from DataInputStream and create inbound message.
}
}, String.format("ReceiverThread-%s", skt.getRemoteSocketAddress()));
sender.start();
receiver.start();
}
/**
* Submits a message to the outbound queue, ready for sending.
*/
public void sendOutboundMessage(Message msg) {
outboundMessages.add(msg);
}
public void destroy() {
// TODO: Interrupt and join with threads. Close streams and socket.
}
}
Note that Nikolai is correct in that blocking I/O using 1 (or 2) threads per connection is not a scalable solution and typically applications might be written using Java NIO to get round this. However, in reality unless you're writing an enterprise server which thousands of clients connect to simultaneously then this isn't really an issue. Writing bug-free scalable applications using Java NIO is difficult and certainly not something I'd recommend.