Writing Java Server to handle multiple client concurrently (simultaneously) - java

I am working on a program where I have a Server and Client class, but at the moment it only handles only one client at a time.
I need the server to be able to handle multiple clients concurrently (simultaneously), using multithreading.
Here is my Server code; how can I change it to handle multiple clients concurrently?
public static void main(String[] args) throws IOException {
ServerSocket socket = new ServerSocket(8945);
Server serverInstance = new Server();
System.out.println("Server is running. Waiting for client.");
while(true) {
server.socket = s.accept();
System.out.println("Client connected");
serverInstance.run();
System.out.println("Client disconnected. Waiting for new client.");
}
}
public void run() {
try {
try {
in = new Scanner(socket.getInputStream());
out = new PrintWriter(socket.getOutputStream());
RequestHandlingMethod();
} finally {
socket.close();
}
} catch (IOException e) {
System.err.println(e);
}
}

Create a separate class that handles the client. Make it implement Runnable so that you can just start a separate Thread with it.
public class ClientHandler implements Runnable {
private final Socket socket;
public ClientHandler(Socket socket) {
this.socket = socket;
}
public void run() {
try (Socket socket = this.socket;
Scanner in = new Scanner(socket.getInputStream();
PrintWriter out = new PrintWriter(socket.getOutputStream()) {
//todo: do whatever you need to do
} catch (IOException ex) {
ex.printStackTrace();
}
System.out.println("Client disconnected.");
}
}
Then in your server you do:
System.out.println("Waiting for new client connection");
Socket clientSocket = s.accept();
System.out.println("Client connected");
new Thread(new ClientHandler(clientSocket)).start();
If you don't want to create a lot of disposable Threads, you might want to consider using an ExecutorService with a cached thread pool (or another thread pool of your choice if you prefer).
You would just create a new ExecutorService with ExecutorService executor = ExecutorService.newCachedThreadPool() and then inside your loop you do:
System.out.println("Waiting for new client connection");
Socket clientSocket = s.accept();
System.out.println("Client connected");
executor.submit(new ClientHandler(clientSocket));
If you think you are going to have a lot of concurrent clients, you might want to look at using a non-blocking server with NIO instead. It will have 1 single event loop thread instead (doesn't block on the accept) and handles all I/O events in there, and you can have a pool of worker threads that do the client handling logic.

Related

problem with connecting multiple clients to a server

hey I'm writing a simple code with a server socket and multiple clients which the server gets every client's username and stores them in a hashmap.the server accepts a socket client and the client enters the username but again the server accept the same socket client and it wants its username and the code stops here.i want it to work for multiple clients not just one.
server class:
public class Server implements Serializable{
// [..]
public void serverConnect() throws IOException, ClassNotFoundException
{
listener = new ServerSocket(9090);
System.out.println("Server is running...");
while (true)
{
System.out.println("Waiting ...");
socket=listener.accept();
for (Socket socket:socketList.keySet())
{
if (this.socket==socket)
{
checkSocket=false;
}
}
if (checkSocket)
{
socketList.put(socket,socketNumber);
System.out.println("Client is connected");
inputReader = new InputStreamReader(socket.getInputStream());
reader = new BufferedReader(inputReader);
user = reader.readLine();
Server.userList.add(user);
socketNumber++;
}
checkSocket=true;
}
}
}
client class:
public class Client {
public Client() {
}
public void clientConnect() throws UnknownHostException, IOException {
System.out.println("enter your username");
Scanner scanner = new Scanner(System.in);
String msg = scanner.nextLine();
Socket socket = new Socket("localhost", 9090);
PrintWriter writer = new PrintWriter(socket.getOutputStream(), true);
writer.println(msg);
}
}
In principle you have the workings of single thread server (which means it can accept only one client connection at a time). The main issue is that you have over-complicated how you receive a connection.
You can simplify your current code by dealing by moving the client connection socket and readers into the local scope and dealing with the socket directly.
public void serverConnect() throws IOException {
listener = new ServerSocket(9090);
System.out.println("Server is running...");
while (true) {
System.out.println("Waiting ...");
Socket socket = listener.accept();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()))) {
String user = reader.readLine();
Server.userList.add(user);
} catch (IOException ignore) {
} finally {
socket.close();
}
}
}
As you can see you don't need to keep hold of the socket beyond reading the value sent. If you are only expecting the one line of data from the client, you should also close the socket otherwise the client can hold the server hostage by not sending any data until the socket timeout is reached.
Further to this you also want to wrap the code inside the while loop with a try/catch block to prevent an exception terminating the server.
As I mentioned in the opening paragraph this code works as a single threaded server and it can only respond to a single request at a time. If you want to accept and process multiple requests you will need to spawn a new thread to handle the response. I would recommend constructing your code as below but for the sake of brevity you could do something like below:
public void serverConnect() throws IOException {
int MAX_WORKERS = 100;
ExecutorService service = Executors.newFixedThreadPool(MAX_WORKERS);
ServerSocket listener = new ServerSocket(9090);
System.out.println("Server is running...");
while (true) {
System.out.println("Waiting ...");
Socket socket = listener.accept();
service.submit(() -> {
System.out.println("Client is connected");
try {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()))) {
String user = reader.readLine();
Server.userList.add(user);
} finally {
socket.close();
}
} catch (Throwable ignore) {
}
});
}
}
So all that is happening above is that we are creating a thread pool of 100 threads using the ExecutorService. This means in theory we can accept 100 concurrent connections.
When a connection is accepted, we submit the socket and worker code to a thread which means that the main thread can return to listening for a new connections.

How to use data from Client Handler Threads in Java

I followed a few tutorials and found out how to use threads for multithreading socket servers. I've created a Server class that has ClientServiceThread class for clients. When the thread receives a message from the client, how can I access that information using the Server class?
Here is my Server Thread:
public void run(){
game = new Game();
try{
serverSocket = new ServerSocket(port);
System.out.println("Server Started");
}
catch (IOException e){
System.out.println(e);
}
while(true) {
try {
Socket clientSocket = serverSocket.accept();
ClientServiceThread cliThread = new ClientServiceThread(clientSocket);
threads.add(cliThread);
cliThread.start();
} catch(IOException e) {
e.printStackTrace();
}
}
}
Here is my ClientServiceThread class:
public void run() {
boolean m_bRunThread = true;
System.out.println("Accepted Client Address - " + socket.getInetAddress().getHostAddress());
try {
out = new ObjectOutputStream(socket.getOutputStream());
in = new ObjectInputStream(socket.getInputStream());
while(m_bRunThread) {
String clientCommand = in.readUTF();
System.out.println("Client Says :" + clientCommand);
if(!gameStarted) {
out.writeUTF("GAME_ALREADY_STARTED");
out.flush();
}
}
} catch(Exception e) {
e.printStackTrace();
}
}
EDIT 1: Essentially, I'm listening to commands/messages on the client handler threads. I later want to process them into my Server so I can manipulate my Game object through it.
The approach I'd recommend is to pass the game object to the client threads (it has to be thread-safe!), and then let the client threads take the actions on the game object directly. This will simplify your server class, and give you a single place to handle incoming messages.

How to pass object by socket in java Server Client

I'm new in Java Sockets, I have seen so many examples but I can't understand how to pass an argument from server to client and vice versa. My destination is to pass an Object that's why I'm using Object I/O Stream.
I have to classes Server and Player.
public class Server extends Thread{
public static final int TEST = 165;
ServerSocket serverSocket;
InetAddress address;
Player playerWhite;
public Server() {
start();
}
#Override
public void run() {
try
{
address = InetAddress.getLocalHost();
serverSocket = new ServerSocket(6000);
playerWhite = new Player();
System.out.println("server waits for players");
playerWhite.socket = serverSocket.accept();
playerWhite.start();
sendTestMessage(playerWhite);
}
catch (IOException ex)
{
Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
}
}
public void sendTestMessage(Player player) throws IOException
{
ObjectOutputStream testToClient = new ObjectOutputStream(player.socket.getOutputStream());
testToClient.write(TEST);
testToClient.flush();
}
And the Player class:
public class Player extends Thread {
Socket socket;
Player() throws IOException
{
socket = new Socket(InetAddress.getLocalHost(), 6000);
}
#Override
public void run() {
try {
listenTestStream();
}
catch (IOException | ClassNotFoundException ex)
{
Logger.getLogger(CheckerPlayer.class.getName()).log(Level.SEVERE, null, ex);
}
}
public void listenTestStream() throws IOException, ClassNotFoundException
{
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
int message = ois.readInt();
//To test
System.out.println("Server listened: " + message);
}
I execute it as create a Server object in the other class.
When I have testing this application I saw that sometimes client is faster than Server. Is it possible to make him "wait" for server response?
Thanks for your response.
EDIT 1: PROBLEM SOLUTION:
From outside we should create:
Player player = new Player(); // (class player extends from Thread)
player.start();
and delete the Player variable - is not necessary, we need only Socket so:
Server:
Socket playerWhiteSocket
public void run() {
try
{
serverSocket = new ServerSocket(PORT);
playerWhiteSocket = serverSocket.accept();
sendMessage(playerWhiteSocket, "Hello");
}
catch(IOException | ClassNotFoundException ex)
{}
public void sendMessage(Socket socket, String message) throws IOException
{
ObjectOutputStream testToClient = new ObjectOutputStream(socket.getOutputStream());
testToClient.writeObject(message);
testToClient.flush();
}
In Player class we need get method:
public String receiveMessage() throws IOException, ClassNotFoundException
{
//socket is a variable get from Player class socket = new Socket("severHost", PORT);
ObjectInputStream messageFromServer = new ObjectInputStream(socket.getInputStream());
String message = (String) messageFromServer.readObject();
return message;
}
I would recomment doing this public void start(){
try {
ServerSocket = new ServerSocket(this.port,10,this.localAddress);
// set timeout if you want
//this.clientServerSocket.setSoTimeout(timeout);
// infinity loop
while(true)
{
//wait for a client connection
Socket socket = ServerSocket.accept();
// start thread for every new client
Thread t = new Thread(new AcceptClients(this.socket));
t.start();
System.out.println(L"new client connected");
// call garbage collector and hope for the best
System.gc();
}
} catch (IOException e) {
System.out.println("IO Error");
e.printStackTrace();
}
}
and then in another class
public class AcceptClients implements Runnable{
// socket
private Socket socket;
public AcceptClients (Socket socket){
this.socket = socket;
}
#Override
public void run() {
// what happens if a client connect
}
}
I always use this and it works fine
Suggested changes.
Create ServerSocket only once. If you have done it, you won't get "Address already in use" error
After creating Server Socket, you thread should be in while (true) loop to accept connection from client.
Once you create a client socket, pass that socket to thread.
Now Player is used to send communication from server to client socket. So You need one more class like PlayerClient which create a socket to Server IP and Port. Now PlayerClient should create one more thread to handle IO operations like you have done from server. In this case, creating a socket is not in while loop from client side. It create a socket to server once. Now you can run this PlayerClient program from multiple machines.
If you are just sending just primitive type, use DataOutputStream & DataInputStream instead of ObjectStreams
This code will become like this
try
{
address = InetAddress.getLocalHost();
serverSocket = new ServerSocket(6000);
System.out.println("server waits for players");
while ( true){
Socket socket = serverSocket.accept();
Player playerWhite = new Player(socket);
sendTestMessage(socket);// Move this method to Player thread and change the signature of this method accordingly to accept a socket
}
}
catch (IOException ex)
{
Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
}
Player.java
Player(Socket socket) throws IOException
{
this.socket = socket;
start();
}
Have a look at this chat example for better understanding.
Yep it is.
It should work if you put it in a endlees loop like that:
try
{
while(true){
address = InetAddress.getLocalHost();
serverSocket = new ServerSocket(6000);
playerWhite = new Player();
System.out.println("server waits for players");
playerWhite.socket = serverSocket.accept();
playerWhite.start();
sendTestMessage(playerWhite);
}
}
catch (IOException ex)
{
Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
}
But I would not recommend to put this in a thread. Instead I would put the connection of a new client in a thread, so multiple clients can connect to the server

Creating the ServerSocket in a separate thread?

I have a problem with using a ServerSocket in my application.
I'm creating the ServerSocket in the constructor of my application. The constructor of the socket calls the accept() method to wait for a client to connect.
The problem is that the accept() method is freezing my whole application until a client connects. So I would like to ask if there's an alternative to creating the whole ServerSocket in a separate thread, that the constructor of the ServerSocket and its accept() method is called beside my main application?
Edit:
Thanks to Olivier for the advice, putting the .accept into a runnable and creating a threadpool to handle the clientconnections.
Thats my code right now:
public void start(){
final ExecutorService clientProcessingPool = Executors.newFixedThreadPool(10);
Runnable serverTask = new Runnable() {
#Override
public void run() {
try {
serverSocket = new ServerSocket(port);
while (true) {
Socket clientSocket = serverSocket.accept();
objectout = new ObjectOutputStream(clientSocket.getOutputStream());
clientProcessingPool.submit(new ClientTask(clientSocket,objectout));
}
} catch (IOException e) {
System.err.println("Accept failed.");
}
}
};
Everythings running fine! Thanks!
Usually, I use N+1 threads for this : one for the ServerSocket, to avoid blocking the whole application waiting for a client to connect; and N threads to process the client's requests, N being the size of the thread pool (I recommend using a thread pool over creating a new thread per client).
Here is an example (just coded it, you may want to have better exception management and such, but this is a minimal working example)
public class Server {
public static void main(String[] args) {
new Server().startServer();
}
public void startServer() {
final ExecutorService clientProcessingPool = Executors.newFixedThreadPool(10);
Runnable serverTask = new Runnable() {
#Override
public void run() {
try {
ServerSocket serverSocket = new ServerSocket(8000);
System.out.println("Waiting for clients to connect...");
while (true) {
Socket clientSocket = serverSocket.accept();
clientProcessingPool.submit(new ClientTask(clientSocket));
}
} catch (IOException e) {
System.err.println("Unable to process client request");
e.printStackTrace();
}
}
};
Thread serverThread = new Thread(serverTask);
serverThread.start();
}
private class ClientTask implements Runnable {
private final Socket clientSocket;
private ClientTask(Socket clientSocket) {
this.clientSocket = clientSocket;
}
#Override
public void run() {
System.out.println("Got a client !");
// Do whatever required to process the client's request
try {
clientSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

how to communicate between client and server in java

I have a chat program. Now the code works for communicate between client and server via command line. But it gives an exception (java.net.SocketException: Socket is closed) while running. Please help me to fix that problem.
In a java chat program,how will the communication be implemented between client and server?
ie.
client<-->server (between server and client)
or
client A<-->server<-->client B (server act as a bridge between two clients)
Is the 2 way communication can be implemented through a single socket?
Are there any other methods ?
How to communicate more than one client simultaneously?
server code
class Server
{
ServerSocket server;
Socket client;
public Server()
{
try
{
server = new ServerSocket(2000);
System.out.println("\tServer Started..........");
while (true)
{
client = server.accept();
Send objsend = new Send(client);
Recive objrecive = new Recive(client);
//client.close();
}
}
catch (Exception e)
{
System.out.println("Exception4 " + e);
}
}
public static void main(String arg[])
{
new Server();
}
}
class Recive implements Runnable
{
Socket client;
public Recive(Socket client1)
{
client=client1;
Thread trsend=new Thread(this);
trsend.start();
}
public void run()
{
ObjectInputStream ois;
Message M=new Message();
try
{
ois = new ObjectInputStream(client.getInputStream());
M = (Message)ois.readObject();
M.display();
ois.close();
}
catch (Exception e)
{
System.out.println("Exception1 " + e);
}
}
}
class Send implements Runnable
{
Socket client;
public Send(Socket client1)
{
client=client1;
Thread trrecive=new Thread(this);
trrecive.start();
}
public void run()
{
Message M=new Message();
InputStreamReader isr=new InputStreamReader(System.in);
BufferedReader br=new BufferedReader(isr);
try
{
System.out.println("Me(server)");
M.strmessage=br.readLine();
ObjectOutputStream oos=new ObjectOutputStream(cli ent.getOutputStream());
oos.writeObject((Message)M);
oos.flush();
oos.close();
}
catch (Exception e)
{
System.out.println("Exception " + e);
}
}
}
client code
class Client
{
public static void main(String arg[])
{
try
{
Send objsend=new Send();
Recive objrecive=new Recive();
}
catch(Exception e)
{
System.out.println("Exception "+e);
}
}
}
class Send implements Runnable
{
public Send()
{
Thread trsend=new Thread(this);
trsend.start();
}
public void run()
{
try
{
Message M=new Message();
InputStreamReader isr=new InputStreamReader(System.in);
BufferedReader br=new BufferedReader(isr);
while(true)
{
System.out.println("Me(client)");
M.strmessage=br.readLine();
Socket client=new Socket("localhost",2000);
ObjectOutputStream oos=new ObjectOutputStream(client.getOutputStream());
oos.writeObject((Message)M);
oos.flush();
oos.close();
}
}
catch(Exception e)
{
System.out.println("Exception "+e);
}
}
}
class Recive implements Runnable
{
public Recive()
{
Thread trrecive=new Thread(this);
trrecive.start();
}
public void run()
{
try
{
while(true)
{
Socket client=new Socket("localhost",2000);
ObjectInputStream ois=new ObjectInputStream(client.getInputStream());
Message CNE=(Message)ois.readObject();
CNE.display();
ois.close();
}
}
catch(Exception e)
{
System.out.println("Exception "+e);
}
}
}
First of all, don't close the streams in every run().
Secondly, check whether port for server which you are using is free.
This program makes your pc both host and server.
import java.io.IOException;
import java.net.*;
public class ClientServer {
static byte[] buffer = new byte[100];
private static void runClient() throws IOException {
byte buffer[] = new byte[100];
InetAddress address = InetAddress.getLocalHost();
DatagramSocket ds=new DatagramSocket();
int pos = 0;
while (pos<buffer.length) {
int c = System.in.read();
buffer[pos++]=(byte)c;
if ((char)c =='\n')
break;
}
System.out.println("Sending " + pos + " bytes");
ds.send(new DatagramPacket(buffer, pos, address, 3000));
}
private static void runServer() throws IOException {
InetAddress address = InetAddress.getLocalHost();
DatagramSocket ds = new DatagramSocket(3000, address);
DatagramPacket dp = new DatagramPacket(buffer, buffer.length);
ds.receive(dp);
String s=new String(dp.getData(),0,dp.getLength());
System.out.print(s);
}
public static void main(String args[]) throws IOException {
if (args.length == 1) {
runClient();
} else {
runServer();
}
}
}
also follow this link
There could be multiple places where the exception could be thrown. Without a stack trace it is difficult to state so accurately, as to the cause of failure.
But the root cause, is essentially due to the fact that you are closing the InputStream of the socket in your Receiver threads after reading a message, and closing the OutputStream of the socket in your Sender threads after sending a message. Closing either of these streams will automatically close the socket, so you if attempt to perform any further operation on it, a SocketException will be thrown.
If you need to ensure that your server and client do not shutdown in such an abrupt manner, you'll have to keep reading the InputStream (until you get a special message to shutdown, for instance). At the same time, you'll also have to keep writing to the OutputStream. Two-way communication is definitely possible, and the posted code is capable of the same (if the socket remains open).
If you have to handle multiple clients, you'll need multiple reader and writer threads on the server, each listening on an instance of a Socket returned from ServerSocket.accept(); in simpler words, you need a reader-writer pair listening on a distinct socket on the server for each client. At the moment, multiple clients can connect to the Server, as each incoming connection is provided its own client Socket object on the Server, that is provided to individual reader and writer threads. The main Server thread can continue to receive incoming connections and delegate the actual work to the reader-writer pairs.
chat programms normaly have a server through which all communication goes. The reason is that other wise every client needs to know how to reach every other client. And that doesn't work in the general case.
So you'll have a server, every client registers and talks with the server, which will forward messages to other clients.
Mostly communication is done via HTTP cause this is likely to go through firewalls and proxies. You probably want to read up on long polling if you are planning for anything serious.

Categories