Alright, so I changed it to this, I closed the socket and modified the loop
Socket clientSocket = serverSocket.accept();
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(),true);
connectedClients++;
if (connectedClients < maxPlayers) {MortgageRunnable m = new MortgageRunnable(clientSocket);
System.out.println("New player has connected!");
new Thread(m).start();}
else{out.println("Connection unsuccessful, Max players connected");clientSocket.close();}
the only thing left is it doesn't send the message to the client ("Connection unsuccessful, Max players connected") it just disconnects.
How can I send the message to the client?
You seem to be leaving sockets open when rejecting players.
The logic should be:
while (true) {
socket = accept()
if (too many players) {
send "too many players" message
close socket
} else {
increment player counter
new Thread(new MortgageRunnable(socket)).start()
}
}
Also, when a player leaves / thread exits, you should decrement the counter.
Finally, creating a new PrintWriter each time you send a message is a bad idea.
Your code continues to accept new incoming connections because the while loop does not exit. To fix that, once you hit the maximum allowed connections, you need to get out of the while loop. Here is your code (without the dangling try statement) with one extra line after printing "Max players connected". Once you reach maxPlayers total number of connections, this will stop accepting new connections.
while (true) {
Socket clientSocket = serverSocket.accept();
MortgageRunnable m = new MortgageRunnable(clientSocket);
System.out.println("New player has connected!");
if (!(connectedClients == maxPlayers)) {
new Thread(m).start();
connectedClients++;
} else {
m.displayMessage("Max players connected");
break; // get out of the while loop
}
}
Another small suggestion: instead of checking if (!(connectedClients == maxPlayers) {...}, change it to something like if (connectedClients < maxPlayers) {...} – simpler logic, the code is more readable, easier to reason about.
EDIT: here's a variation. This time, I've moved most of the work into a new acceptNewClient() method. Also, the if statement is reworked to eject once connectedClients < maxClients is no longer true.
public void listenForClientConnections() {
while (true) {
MortgageRunnable m = acceptNewClient();
connectedClients++;
boolean maxClientsReached = !(connectedClients < maxClients);
if (maxClientsReached) {
m.displayMessage("Max clients connected");
break; // exit "while" loop, no more connections will be accepted
}
}
}
private MortgageRunnable acceptNewClient() {
Socket clientSocket = serverSocket.accept();
MortgageRunnable m = new MortgageRunnable(clientSocket);
System.out.println("New client has connected!");
new Thread(m).start();
return m;
}
Related
So what I'm trying to do is have a socket that receives input from the client, put the client into the queue and then return a message to each client in the queue when my algorithm returns true.
This queue should support a few hundred clients at once but at the same time not bottle neck the server so it can actually do what its supposed to do.
This is what i have so far:
private static final int PORT = 25566;
private static final int THREADS = 4;
private ExecutorService service;
public void init() throws IOException, IllegalStateException {
ServerSocket serverSocket;
serverSocket = new ServerSocket(PORT);
service = Executors.newCachedThreadPool();
Socket socket;
while(true) {
socket = serverSocket.accept();
System.out.println
("Connection established with " + socket.getInetAddress().toString());
service.execute(() -> {
Scanner scanner = null;
PrintWriter output = null;
String line = null;
try {
scanner = new Scanner(new InputStreamReader(socket.getInputStream()));
output = new PrintWriter(socket.getOutputStream());
} catch(IOException e) {
e.printStackTrace();
}
try {
if (scanner == null || output == null)
throw new IllegalStateException("Scanner/PrintWriter is " + "null!");
line = scanner.nextLine();
while (line.compareTo("QUIT") != 0) {
/* This is where input comes in, queue for the algorithm,
algorithm happens then returns appropriate values */
output.flush();
line = scanner.nextLine();
}
} finally {
try {
System.out.println
("Closing connection with " + socket.getInetAddress().toString());
if(scanner != null) {
scanner.close();
}
if(output != null) {
output.close();
}
socket.close();
} catch(IOException e) {
e.printStackTrace();
}
}
});
}
}
Now what I think will happen with this, is if the queues do reach high enough levels, my thread pool will completely bottleneck the server as all of the threads are being put to use on handling the clients in the queue and there won't be enough processing for the algorithm.
EDIT: After a bunch of testing, I think it will work out if in the algorithm it returns the value then disconnects, not waiting for user response but having the users client reconnect after certain conditions are met.
Your bottleneck is unlikely to be processing power unless you are machine limited. What's more likely to happen is that all the threads in your thread pool are consumed and end up waiting on input from the clients. Your design can only handle as many clients at once as there are threads in the pool.
For a few hundred clients, you could consider simply creating a thread for each client. The limiting resource for the number of threads that can be supported is typically memory for the stack that each thread requires, not processing power; for a modern machine with ample memory, a thousand threads is not a problem, based on personal experience. There may be an operating system parameter limiting the number of threads which you may have to adjust.
If you need to handle a very large number of clients, you can set up your code to poll sockets for available input and do the processing only for those sockets that have input to be processed.
I have made a server in Java and implemented a GUI for it. On the GUI there are two buttons - 'Allow' and 'Reject' connections. When 'Allow' is clicked the boolen value 'AllowConnections' is set to true and for 'Reject' it is set to false.
Basically the program will initialise the gui and the actionlisteners then if AllowConnections is true a socket will be opened and allow a client to connect to it. I am wanting to be able to click 'Reject' and it kick the user off the socket. The problem is that I cannot break out of the loop which constantly gets the incoming messages as it will pause and wait for a user to connect or for a user to send a message. This is shown bellow:
server class:
boolean loop = true;
while (loop) {
if (allowConnections == true) {
remote.commands();
}
else {
System.out.println("reject");
}
}
remote class:
public static void commands() {
try {
serverSocket = new ServerSocket(serverPort);
System.out.println("open");
Socket clientSocket = serverSocket.accept();
connected = true;
System.out.println("connected");
BufferedReader clientMessage = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String input;
while (connected) {
input = clientMessage.readLine();
System.out.println(input);
// do commands
}
}
catch (IOException e) {
e.printStackTrace();
}
}
In the code above the program will pause and wait for a user to connect (line: 8) and also wait for a user to send a message (line: 18) which means I cannot just put a if(!allowConnections){break;} condition statement in to break the loop.
Any ideas on how I would break this loop as the condition changes (sort of like a while loop that constantly checks conditions) or how I could rewrite this to include the feature I need?
ServerSocket has method setSoTimeout: https://docs.oracle.com/javase/7/docs/api/java/net/ServerSocket.html#setSoTimeout(int)
This can be used to avoid accept blocking infinite. As the documentation states, if the time has been passed without a connection it will throw a java.net.SocketTimeoutException
Make allowConnections static and public (or use a getter), then you can check it inside commands() method.
EDIT: Start a new thread which checks if allowConnections has changed and call _ serverSocket.close()_ in case it change the state.
I'm trying to create a program for a distributed system. At the moment I have a thread for listening to connections, and a thread for sending, and a thread for receiving.
I've reached a problem where the client will connect but only when using breakpoints. I can't figure out the problem at all!. I've tried to implement things to slow the program down however nothing is working.
If you guys could take a look i'd be greatly appreciative.
public static void main(String[] args)
{
System.out.println("Server starting on port 5000");
RecievingConnection reciever = new RecievingConnection(5000,0); //Recieving Connection
reciever.start();
SendingConnection sender = new SendingConnection(5001,1); //Sending Connection
sender.start();
while(true){
while(reciever.ready==true){
System.out.println("In");
nodes first = new nodes(reciever.socket,0);
System.out.println("Node created");
first.start();
System.out.println("Client connected on port: " + reciever.socket.getLocalAddress());
nodes second = new nodes(sender.socket,1);
second.start();
reciever.ready=false;
sender.ready=false;
reciever.connectionComplete=true;
sender.connectionComplete=true;
}
}
}
public RecievingConnection(int port, int mode)
{
Serverport = port;
connectionMode = mode;
try{
server = new ServerSocket(port);
server.setSoTimeout(100000);
}
catch(IOException ex)
{
System.out.println(ex);
}
}
public void run(){
while(true){
if(ready == false){
try {
socket = server.accept();
ready = true;
System.out.println("Attempting to connect using port: " + Serverport);
while(connectionComplete == false){
//wait
}
} catch (IOException ex) {
System.out.println(ex);
}
}
}
}
The sending thread is basically the same code. Any idea what the problem is? "Nodes" is the thread for each node.
I solved it by adding a sleep in the main thread. I presume this is because the main thread takes priority over child threads?
Your problem is almost certainly at:
while (connectionComplete == false) {
//wait
}
This will loop forever, the other thtreads will not get any cpu time at all. It also explains why it works in debug - it's because in debug if you stop at a breakpoint, any other threads will get time.
You should at least do:
while (connectionComplete == false) {
//wait
Thread.sleep(0);
}
and maybe use a number much greater than 0. This will allow other thtreads a chance to run.
I am not suggesting that this will make your code work correctly but it should remove the current problem.
After that there's another tight loop that won't let any other thread time.
while (true) {
if (ready == false) {
Change that to:
while (true) {
if (ready == false) {
// ...
} else {
// Here too.
Thread.sleep(0);
}
}
You can't just share variables between threads. Make them volatile, synchronize or use CAS types like AtomicBoolean.
Read about it.
https://docs.oracle.com/javase/tutorial/essential/concurrency/interfere.html
http://www.journaldev.com/1061/java-synchronization-and-thread-safety-tutorial-with-examples
https://docs.oracle.com/javase/tutorial/essential/concurrency/atomicvars.html
Besides class "nodes" is not described here and classes are expected to start with an upper case letter.
I am creating a server-chat-client application and have borrowed code. I know how most of the things work except one.
In my Class Server I wait for a socket to be accepted.
public static ArrayList<String> clientUsernameList = new ArrayList<>();
/**
* #param args the command line arguments
* #throws java.io.IOException
*/
public static void main(String[] args) throws IOException {
int port = 8900; //Port number the ServerSocket is going to use
ServerSocket myServerSocket = null; //Serversocket for sockets to connect
Socket clientSocket = null; //Listerner for accepted clients
ClientThread[] clientsConnected = new ClientThread[20]; //Max clients in this server
try {
myServerSocket = new ServerSocket(port);
System.out.println("Server waiting for clients on port:" + port);
} catch (IOException ex) {
Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
}
while (true) {
try { //Freezes while-loop untill a socket have been accepted or if some failure occur
clientSocket = myServerSocket.accept();
System.out.println("Client have connected from:" + clientSocket.getLocalAddress().getHostName());
} catch (Exception e) {
//Print out exception
System.out.println(e);
}
//For-loop that counts every element in Array-clientsConnected
for (int i = 0; i < clientsConnected.length; i++) {
//If-statement checks if current element is null
if(clientsConnected[i] == null){
//If current element in the Array is null then create a new object from ClientThread class
//With a socket and the object of itself as parameter.
(clientsConnected[i] = new ClientThread(clientSocket, clientsConnected)).start();
//Must have a break otherwise it will create 20 objects (Exit for-loop)
break;
} //Exit if-statement
} //Exit for-loop
} //Exit while-loop
}
}
So if a socket gets accepted I create a thread class called Class ClientThread
To create a object of this class I need a socket and a array.
This is how my ClientThread class looks like
public class ClientThread extends Thread {
private ClientThread[] clientsConnected;
private Socket SOCKET = null;
private DataInputStream IN = null;
private DataOutputStream OUT = null;
private String userName,zone;
//-------------------------------------------------------
//Constructor
public ClientThread(Socket socket, ClientThread[] clientThread) {
this.SOCKET = socket;
this.clientsConnected = clientThread;
}
//Some more code
Now this is where I am lost. Do I send in my whole array? and if I do shouldn't user1 only get an array with 1 user and when user2 connects shouldn't he get an array with 2 users? I am lost. If someone could point me to something that explains this I would be grateful.
Your code will serve only 20 requests. For each one it adds new value to clientsContected, once the whole table is full it will just go back to the start of the loop (without closing the accepted connection).
Probably the idea of passing the clientsConnected to the thread, was so it can set the value to null once it stopped working (so that your main code in the loop can assigne a new client to it). GUessin as no code is included). But for that an index inside the array would be useful (so 3 parameters instead of 2) so the ClientThread doesn't have to search the whole array to find object matching this.
I would rather recommend using BlockingQueue (with limited capacity for example 5) to which you will pass accepted connections. Once it is full your main will be forced to wait on it till it has same space to insert new connection so you will stop accepting new sockets. Create the 20 threads, that in a inifinite loop tries to get a socket from that queue and serve it. Once they finish they go back an wait for new request.
So yes you passs the whole array.
Still it doesn't solve the problem of what happens if all are busy, as you keep accepting new clients instead of waiting for free Thread.
I have a network client which tries 3 times in a loop to connect to server. During this time I use sleep thread. Is there any way to replace Thread.sleep(700); with some code which skip the waiting period right after the client is connected.
NClient pc;
if (pc == null)
{
try
{
Thread.sleep(700);
}
catch (InterruptedException x)
{
//TODO
}
if (pc != null)
{
outPrint.println("Connected");
break;
}
}
I would like to improve the user experience by reducing the waiting period in which the connection negotiation is in progress. What are the options in Java to do this?
The answer to this question depends on the implementation of NClient. Typically, I'd use a connect timeout for this. The example below indicates how to do this with a Socket. I don't know what NClient is, so I can't give you an NClient example unfortunately.
Create a method that attempts to connect - up to 3 times
Socket connectToServer() {
Socket socket = new Socket();
final int connectTimeoutMs = 700;
for (int i=0; i<3; i++) {
try {
// the call to connect blocks the current thread for a maximum of 700ms if it can't connect
socket.connect(new InetSocketAddress("localhost", 8080), connectTimeoutMs);
} catch (IOException e) {
// failed to successfully connect within 700 milliseconds
e.printStackTrace();
}
}
return socket;
}
Use the above as follows
Socket socket = connectToServer();
if (socket.isConnected()) {
// do stuff with the valid socket!
}
In short, use a connect timeout!