Java Server with Multiclient Communication

socket programming multiple client to one server

For every client you need to start separate thread. Example:

public class ThreadedEchoServer {

static final int PORT = 1978;

public static void main(String args[]) {
ServerSocket serverSocket = null;
Socket socket = null;

try {
serverSocket = new ServerSocket(PORT);
} catch (IOException e) {
e.printStackTrace();

}
while (true) {
try {
socket = serverSocket.accept();
} catch (IOException e) {
System.out.println("I/O error: " + e);
}
// new thread for a client
new EchoThread(socket).start();
}
}
}

and

public class EchoThread extends Thread {
protected Socket socket;

public EchoThread(Socket clientSocket) {
this.socket = clientSocket;
}

public void run() {
InputStream inp = null;
BufferedReader brinp = null;
DataOutputStream out = null;
try {
inp = socket.getInputStream();
brinp = new BufferedReader(new InputStreamReader(inp));
out = new DataOutputStream(socket.getOutputStream());
} catch (IOException e) {
return;
}
String line;
while (true) {
try {
line = brinp.readLine();
if ((line == null) || line.equalsIgnoreCase("QUIT")) {
socket.close();
return;
} else {
out.writeBytes(line + "\n\r");
out.flush();
}
} catch (IOException e) {
e.printStackTrace();
return;
}
}
}
}

You can also go with more advanced solution, that uses NIO selectors, so you will not have to create thread for every client, but that's a bit more complicated.

Java Server with Multiclient communication.

Here I am sharing you a nice Chat Program having one server that is communicating with multiple clients using TCP protocol as per your requirement.

Program contains:

  • Each client is informed wherever a new client is added along with their name and position.
  • It also checks for existing names. Program doesn't allow multiple clients using same name.

Use this program as initial starter for your game. Please let me know if you want to add new functionality in the program.

Here is the code (see code comments for more clarification):

Note: replace host name in LiveChatClient.java file before running this program at port no 1234

Steps to run the program:

  • first run LiveChatServer only for single time
  • then run LiveChatClient for multiple clients as many as you want to add

Opcode.java:

Operation code that is used to set a client-server communication protocol

package com.chat;

/**************** an interface to define different operation code **************/

public interface Opcode {
int CLIENT_CONNECTEING = 1;
int CLIENT_CONNECTED = 2;
}

LiveChatServer.java:

Single server that is controlling multiple clients

package com.chat;

/************************ Live Chat Server *******************/

import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.LinkedHashMap;

public class LiveChatServer {

// Connection state info
private static LinkedHashMap<String, ClientThread> clientInfo = new LinkedHashMap<String, ClientThread>();

// TCP Components
private ServerSocket serverSocket;

// Main Constructor
public LiveChatServer() {

startServer();// start the server
}

public void startServer() {
String port = "1234";

try {
// in constractor we are passing port no, back log and bind address whick will be local
// host
// port no - the specified port, or 0 to use any free port.
// backlog - the maximum length of the queue. use default if it is equal or less than 0
// bindAddr - the local InetAddress the server will bind to

int portNo = Integer.valueOf(port);
serverSocket = new ServerSocket(portNo, 0, InetAddress.getLocalHost());
System.out.println(serverSocket);

System.out.println(serverSocket.getInetAddress().getHostName() + ":"
+ serverSocket.getLocalPort());

while (true) {
Socket socket = serverSocket.accept();
new ClientThread(socket);
}
} catch (IOException e) {
System.out.println("IO Exception:" + e);
System.exit(1);
} catch (NumberFormatException e) {
System.out.println("Number Format Exception:" + e);
System.exit(1);
}
}

public static HashMap<String, ClientThread> getClientInfo() {
return clientInfo;
}

// *********************************** Main Method ********************

public static void main(String args[]) {
new LiveChatServer();
}

}

LiveChatClient.java:

Multiple clients talking to each other via server

package com.chat;

/************************ Live Chat Client *******************/

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.net.SocketException;

public class LiveChatClient {
private String chatName;// current user's chat name(max 7 char if greater than show as 6
// char+...
private String serverAddress;

// TCP Components
private Socket socket;
private BufferedReader in;
private PrintWriter out;

public LiveChatClient() {

initHostName();
runClient();// have fun
}

public void initHostName() {
try {
//replace host name with your computer name or IP address
serverAddress = "[hostname]";
if (serverAddress == null)
System.exit(1);

serverAddress = serverAddress.trim();
if (serverAddress.length() == 0)// empty field
{
System.out.println("Server IP Address or Name can't be blank.");
initHostName();
return;
}
System.out.println("Trying to connect with server...\nServer IP Address:"
+ serverAddress);

// create socket
InetAddress inetAddress = InetAddress.getByName(serverAddress);
if (!inetAddress.isReachable(60000))// 60 sec
{
System.out
.println("Error! Unable to connect with server.\nServer IP Address may be wrong.");
System.exit(1);
}

initPortNo();
} catch (SocketException e) {
System.out.println("Socket Exception:\n" + e);
initHostName();
return;
} catch (IOException e) {
initHostName();
return;
}
}

public void initPortNo() {
try {

String portNo = "1234";

portNo = portNo.trim();
if (portNo.length() == 0)// empty field
{
System.out.println("Server port No can't be blank.");
initPortNo();
return;
}
System.out.println("Trying to connect with server...\nServer Port No:" + portNo);

socket = new Socket(serverAddress, 1234);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(), true);

} catch (IOException e) {
System.out.println("IO Exception:\n" + e);
initPortNo();
return;
}
}

public void sendChatName() throws IOException {
System.out.println("Enter your name:");
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String name = br.readLine();
if (name == null)
System.exit(1);

// title case (get only first 9 chars of chat name)
name = name.trim();

if (name.equalsIgnoreCase("All")) {
System.out.println("This name is already reserved. Try different one.");
sendChatName();
return;
}
if (name.length() == 0) {
System.out.println("Please enter your chat name.");
sendChatName();
return;
}
if (name.length() == 1)
chatName = String.valueOf(name.charAt(0)).toUpperCase();
if (name.length() > 1 && name.length() < 10)
chatName = String.valueOf(name.charAt(0)).toUpperCase()
+ name.substring(1).toLowerCase();
else if (name.length() > 9)
chatName = String.valueOf(name.charAt(0)).toUpperCase()
+ name.substring(1, 10).toLowerCase();

// sending opcode first then sending chatName to the server
out.println(Opcode.CLIENT_CONNECTEING);
out.println(chatName);
}

public void runClient() {
try {
sendChatName();
while (true) {
int opcode = Integer.parseInt(in.readLine());
switch (opcode) {
case Opcode.CLIENT_CONNECTEING:
// this client is connecting
boolean result = Boolean.valueOf(in.readLine());
if (result) {
System.out
.println(chatName + " is already present. Try different one.");
runClient();
}

break;

case Opcode.CLIENT_CONNECTED:
// a new client is connected
Integer totalClient = Integer.valueOf(in.readLine());
System.out.println("Total Client:" + totalClient);

for (int i = 0; i < totalClient; i++) {
String client = in.readLine();
System.out.println((i + 1) + ":" + client);
}

break;

}
}
} catch (IOException e) {
System.out.println("Client is closed...");
}
}

// *********************************** Main Method ********************

public static void main(String args[]) {
new LiveChatClient();
}

}

ClientThread.java:

Multiple thread started by server one for each client and containing information about all connected clients

package com.chat;

/************************ Client Thread *******************/

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.HashMap;

public class ClientThread implements Runnable {
// TCP Components
private Socket socket;
private BufferedReader in;
private PrintWriter out;
private String chatName;

// seperate thread
private Thread thread;

// boolean variable to check that client is running or not
private volatile boolean isRunning = true;

// opcode
private int opcode;
private HashMap<String, ClientThread> clientInfo = new HashMap<String, ClientThread>();

public ClientThread(Socket socket) {
try {
this.socket = socket;
this.clientInfo = LiveChatServer.getClientInfo();

in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(), true);

thread = new Thread(this);
thread.start();

} catch (IOException e) {
System.out.println(e);
}
}

public void run() {
try {
while (isRunning) {
if (!in.ready())
continue;

opcode = Integer.parseInt(in.readLine());// getting opcode first from client
switch (opcode) {
case Opcode.CLIENT_CONNECTEING:
chatName = in.readLine();

boolean result = clientInfo.containsKey(chatName);
out.println(Opcode.CLIENT_CONNECTEING);
out.println(result);
if (result)// wait for another chat name if already present
continue;

// send list of already online users to new online user
// for (Object user : clientInfo.keySet().toArray()) {
// out.println(Opcode.CLIENT_CONNECTED);
// out.println(user.toString());
// }

// put new entry in clientInfo hashmap
clientInfo.put(chatName, this);

int i = 0;
for (String key : clientInfo.keySet()) {
if (key.equals(chatName)) {
System.out.println(chatName + " added at " + (i + 1) + " position");
}
i++;
}

// tell other users about new added user and update their online users list
for (ClientThread client : clientInfo.values()) {
client.out.println(Opcode.CLIENT_CONNECTED);
client.out.println(clientInfo.size());

for (ClientThread client1 : clientInfo.values()) {
client.out.println(client1.chatName);
}
}

break;
}
}

// clsoe all connections
out.close();
in.close();
socket.close();
} catch (IOException e) {
System.out.println(e);
}
}
}

Here is the output when two client are added.

Server:

ServerSocket[addr=computerName/IPAddress,port=0,localport=1234]
computerName:1234
Abc added at 1 position
Xyz added at 2 position

Client 1:

Trying to connect with server...
Server IP Address:computerName
Trying to connect with server...
Server Port No:1234
Enter your name:
abc
Total Client:1
1:Abc
Total Client:2
1:Abc
2:Xyz

Client 2:

Trying to connect with server...
Server IP Address:computerName
Trying to connect with server...
Server Port No:1234
Enter your name:
xyz
Total Client:2
1:Abc
2:Xyz

Multiple client to server communication program in Java

MainServer class

public class Server {

public static void main(String[] args) throws IOException {

ServerSocket serverSocket = null;

boolean listeningSocket = true;
try {
serverSocket = new ServerSocket(2343);
} catch (IOException e) {
System.err.println("Could not listen on port: 2343");
}

while(listeningSocket){
Socket clientSocket = serverSocket.accept();
MiniServer mini = new MiniServer(clientSocket);
mini.start();
}
serverSocket.close();
}

}

Helper Class

public class MiniServer extends Thread{

private Socket socket = null;

public MiniServer(Socket socket) {

super("MiniServer");
this.socket = socket;

}

public void run(){
//Read input and process here
}
//implement your methods here

}

Communicating with multiple clients - Java Server

To read and write to multiple clients at the same time, you either need separate threads (blocking IO) or if you want to use a single thread, NIO (nonblocking IO).

You can check out this post about the implementation differences, but NIO is generally the more efficient way to go.

Using blocking I/O generally follows the code you used above, except you need a separate thread to handle each accepted socket. With NIO, the usage is a little more complicated; check out this tutorial.

Java - Server serves multiple clients at the same time

You do not have to overwrite start(), you must overwrite run()

private class ClientThread extends Thread{
Socket s;
Scanner sc;
PrintWriter pw;

ClientThread(Socket s){
this.s = s;
}

@Override
public void run() {
try{
String in,out;

sc = new Scanner(s.getInputStream());
pw = new PrintWriter(s.getOutputStream(), true);
int i=0;
do{
in = sc.nextLine();
System.out.println("In: " + in);
int tmp = Integer.parseInt(in)+1;
out = Integer.toString(tmp);
pw.println(out);
i++;
}while(i<10);
}catch(Exception e){}
}
}

Server thread:

@Override
public void run(){
try{
ServerSocket ss = new ServerSocket(port);
while(true){
Socket cl = ss.accept();
new ClientThread(cl).start();
}
}catch(Exception e){}
}

How to make communication between one server and multiple client in Java Socket Programming?

It seems like a lot of overhead to create a server/client app just for a web app to communicate with a local java program (and even more so to duplicate this process to do more than one thing at a time). If you are looking for concurrent processing in the background of a web app, you can always just create a thread (or multiple threads) to do the work. Or is there a reason why the simple java app can't be embedded in the web app?

MultiClient / Server. Handle communications

Ooohh its a bad idea to put everything onto a low level socket with a PrintWriter etc.
I got several encoding and multithreading errors in the past. So my (of course a little bit slower, but easy to use) solution is: Jersey & Grizzly.

The big advantage is: You can modify and extend your transfer objects very easily, without modifying your transport code(the low level socket writing)

An interface...

public interface I_ServiceCommons {
public static final String MEDIATYPE = "text/xml";
public static final String MEDIATYPE_ENCODING = I_ServiceCommons.MEDIATYPE + "; charset=utf-8";
public static final String SERIVCENAME = "/FUNNY_SERVICE_V001";
}

The server-side code

@Path(I_ServiceCommons.SERIVCENAME)
public class YourService {

@POST
@Produces(I_ServiceCommons.MEDIATYPE)
@Consumes(I_ServiceCommons.MEDIATYPE)
public ResultObject request(final RequestObject yourRequest) {
//process here your request in Server
}
}

Your Client....

public class abstract YourAbstractClient{
protected Logger log = Logger.getLogger(this.getClass());
protected final String serviceUrl;
private final WebResource resource;

public YourAbstractClient(final String url) {
this.serviceUrl = url + getService();
this.resource = Client.create().resource(this.serviceUrl);
}

public abstract String getService();

protected <RES, REQ> RES post(final Class<RES> resultClazz, final REQ req) {
final Builder builder = this.resource.type(I_ServiceCommons.MEDIATYPE).accept(I_ServiceCommons.MEDIATYPE);
try {
final RES result = builder.post(resultClazz, req);
return result;
} catch (final Exception e) {
throw new RuntimeException("Error posting data to [" + this.serviceUrl + "]: " + e.getMessage(), e);
}
}

}

Your ServiceClient...

public class Service extends YourAbstractClient {

public Service(final String url) {
super(url);
}

public MyResult getResult(final MyRequest req) {
return super.post(MyResult.class, req);
}

@Override
public String getService() {
return I_ServiceCommons.SERIVCENAME;
}
}

Your TransferObjects

@XmlRootElement
public class MyRequest implements Serializable {
public void setRequestType(final int p_AequestType) {
this.requestType = p_AequestType;
}

public int getRequestType() {
return this.requestType;
}
}

And the end...

String url = "http://127.0.0.1";
GrizzlyServerFactory.create(url) //starts the server
MyRequest res = new MyRequest();
MyResult result = new Service(url).getResult(req); // Corrected


Related Topics



Leave a reply



Submit