So now, I am making a client server app based multithread. In server side, I make a thread for everysingle connection that accepted.
In thread class, I make a method that send a command to client. What i just want is, how to send a parameter to all running client? For simple statement, i just want to make this server send a message to all connected client.
I've been read this post and find sendToAll(String message) method from this link. But when i am try in my code, there is no method like that in ServerSocket .
Okay this is my sample code for server and the thread.
class ServerOne{
ServerSocket server = null;
...
ServerOne(int port){
System.out.println("Starting server on port "+port);
try{
server = new ServerSocket(port);
System.out.println("Server started successfully and now waiting for client");
} catch (IOException e) {
System.out.println("Could not listen on port "+port);
System.exit(-1);
}
}
public void listenSocket(){
while(true){
ClientWorker w;
try{
w = new ClientWorker(server.accept());
Thread t = new Thread(w);
t.start();
} catch (IOException e) {
System.out.println("Accept failed: 4444");
System.exit(-1);
}
}
}
protected void finalize(){
try{
server.close();
} catch (IOException e) {
System.out.println("Could not close socket");
System.exit(-1);
}
}
}
class ClientWorker implements Runnable{
Socket client;
ClientWorker(Socket client){
this.client = client;
}
public void run(){
...
sendCommand(parameter);
...
}
public void sendCommand(String command){
PrintWriter out = null;
try {
out = new PrintWriter(client.getOutputStream(), true);
out.println(command);
} catch (IOException ex) {}
}
}
Thanks for help :)
The below answer, is not recommended for a full fledged server, as for this you should use Java EE with servlets, web services etc.
This is only intended where a few computers want to connect to perform a specific task, and using simple Java sockets is not a general problem. Think of distributed computing or multi-player gaming.
EDIT: I've - since first post - greatly updated this architecture, now tested and thread-safe. Anybody who needs it may download it here.
Simply use (directly, or by subclassing) Server and Client, start() them, and everything is ready. Read the inline comments for more powerful options.
While communication between clients are fairly complicated, I'll try to simplify it, the most possible.
Here are the points, in the server:
Keeping a list of connected clients.
Defining a thread, for server input.
Defining a queue of the received messages.
A thread polling from the queue, and work with it.
Some utility methods for sending messages.
And for the client:
Defining a thread, for client input.
Defining a queue of the received messages.
A thread polling from the queue, and work with it.
Here's the Server class:
public class Server {
private ArrayList<ConnectionToClient> clientList;
private LinkedBlockingQueue<Object> messages;
private ServerSocket serverSocket;
public Server(int port) {
clientList = new ArrayList<ConnectionToClient>();
messages = new LinkedBlockingQueue<Object>();
serverSocket = new ServerSocket(port);
Thread accept = new Thread() {
public void run(){
while(true){
try{
Socket s = serverSocket.accept();
clientList.add(new ConnectionToClient(s));
}
catch(IOException e){ e.printStackTrace(); }
}
}
};
accept.setDaemon(true);
accept.start();
Thread messageHandling = new Thread() {
public void run(){
while(true){
try{
Object message = messages.take();
// Do some handling here...
System.out.println("Message Received: " + message);
}
catch(InterruptedException e){ }
}
}
};
messageHandling.setDaemon(true);
messageHandling.start();
}
private class ConnectionToClient {
ObjectInputStream in;
ObjectOutputStream out;
Socket socket;
ConnectionToClient(Socket socket) throws IOException {
this.socket = socket;
in = new ObjectInputStream(socket.getInputStream());
out = new ObjectOutputStream(socket.getOutputStream());
Thread read = new Thread(){
public void run(){
while(true){
try{
Object obj = in.readObject();
messages.put(obj);
}
catch(IOException e){ e.printStackTrace(); }
}
}
};
read.setDaemon(true); // terminate when main ends
read.start();
}
public void write(Object obj) {
try{
out.writeObject(obj);
}
catch(IOException e){ e.printStackTrace(); }
}
}
public void sendToOne(int index, Object message)throws IndexOutOfBoundsException {
clientList.get(index).write(message);
}
public void sendToAll(Object message){
for(ConnectionToClient client : clientList)
client.write(message);
}
}
And here for the Client class:
public class Client {
private ConnectionToServer server;
private LinkedBlockingQueue<Object> messages;
private Socket socket;
public Client(String IPAddress, int port) throws IOException{
socket = new Socket(IPAddress, port);
messages = new LinkedBlokingQueue<Object>();
server = new ConnecionToServer(socket);
Thread messageHandling = new Thread() {
public void run(){
while(true){
try{
Object message = messages.take();
// Do some handling here...
System.out.println("Message Received: " + message);
}
catch(InterruptedException e){ }
}
}
};
messageHandling.setDaemon(true);
messageHandling.start();
}
private class ConnectionToServer {
ObjectInputStream in;
ObjectOutputStream out;
Socket socket;
ConnectionToServer(Socket socket) throws IOException {
this.socket = socket;
in = new ObjectInputStream(socket.getInputStream());
out = new ObjectOutputStream(socket.getOutputStream());
Thread read = new Thread(){
public void run(){
while(true){
try{
Object obj = in.readObject();
messages.put(obj);
}
catch(IOException e){ e.printStackTrace(); }
}
}
};
read.setDaemon(true);
read.start();
}
private void write(Object obj) {
try{
out.writeObject(obj);
}
catch(IOException e){ e.printStackTrace(); }
}
}
public void send(Object obj) {
server.write(obj);
}
}
There is no method in server socket to send data or message to all running clinet threads.
Please go through the ServerThread.java program which is calling the sendToAll usng server.
// ... and have the server send it to all clients
server.sendToAll( message );
Check out zeroMQ. There are methods known as "pub sub" or "publish subscribe" that will do what you want. You can also use it to communicate between your threads. It is an amazing library in my opinion. It has java or jzmq bindings along with over 30+ others as well so you should be able to use it in your program.
http://www.zeromq.org/
Related
I think it's because when I multi-thread the client&server, the DataOutputStream and DataInputStream buffers I use get overwritten or something like that since the socket can only have 1 duplex connection.
Here's what I have for now:
Client Class in my client program:
public static void main(String args[]) throws UnknownHostException, IOException, InterruptedException {
for (int i=0;i<2;i++) //change limit on i to change number of threads
{
new Thread(new ClientHandler(i)).start();
}
Thread.sleep(10000);
ClientHandler class in my client program:
(Sends a value to the server, the server will echo it back).
public class ClientHandler implements Runnable {
public int clientNumber;
public ClientHandler(int i){
this.clientNumber=i;
}
public void run() {
Socket socket = null;
try {
socket = new Socket("localhost",9990);
System.out.println("connected client number "+clientNumber);
DataOutputStream output = new DataOutputStream(socket.getOutputStream());
DataInputStream input = new DataInputStream(socket.getInputStream());
output.writeDouble((new Random()).nextDouble());
System.out.println(input.readDouble());
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
Server Class in my server program:
ServerSocket socket = new ServerSocket(9990);
try {
while (true) {
Socket threadSocket = socket.accept();
new Thread(new ServerHandler(threadSocket)).start();
Thread.sleep(10000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
finally {
socket.close();
}
}
}
ServerHandler Class in my server program (receives value from client and echoes it back)
public class ServerHandler implements Runnable {
private Socket socket;
public ServerHandler(Socket socket) {
this.socket = socket;
}
public void run() {
while(true) {
try {
DataInputStream input = new DataInputStream(socket.getInputStream());
DataOutputStream output = new DataOutputStream(socket.getOutputStream());
double a = input.readDouble();
output.writeDouble(a);
}catch (IOException e){
e.printStackTrace();
}
}
}
So it's a pretty straight-forward implementation: create multiple threads of the client, and connect them to multiple threads of the server.
Everything works fine until the line:
double a = input.readDouble();
in my ServerHandler class.
I get an EOFException
I'm guessing it's because there can only be a single duplex connection between sockets. But if that's the case then how would I implement multi-threading of sockets at all?
So my question is: how can I get rid of the EOFException and allow myself to perform multi-threaded client-server socket interaction?
(preferably not changing much about my code because it's taken me a long time to get to this point).
The problem is that you share same Socket variable in ServerHandler for all threads:
private static Socket socket
Remove static keyword. Your ServerHandler will be something like this:
public static class ServerHandler implements Runnable {
private Socket socket;
public ServerHandler(Socket socket) {
this.socket = socket;
}
public void run() {
try {
DataInputStream input = new DataInputStream(socket.getInputStream());
DataOutputStream output = new DataOutputStream(socket.getOutputStream());
double a = input.readDouble();
output.writeDouble(a);
} catch (IOException e) {
e.printStackTrace();
}
}
}
I have a problem with my client/server program, which is blocked after one client is connected. My one client can communicate with my server, but when I try to connect another, the second can't connect. I never see my 'ok' on my console:
public class Server{
private Map<Integer,ThreadClient > mapThreads;
private ServerSocket serveur ;
public static void main(String args[])
{
try{
Serveur serv = new Server();
serv.setServer( new ServerSocket(4786,2));
while (true)
{
serv.getMapThreads().put(new ThreadClient(serv.getServer().accept(),serv);
System.out.println("ok");
}
}
catch (Exception e) { }
}
class ThreadClient implements Runnable
{
private Thread t;
private Socket socket;
private ObjectOutputStream oos ;
private ObjectInputStream ois;
private Serveur server;
public ThreadClient(Socket s, Server serv ) throws ClassNotFoundException
{
server = serv;
socket=s;
try{
oos = new ObjectOutputStream(socket.getOutputStream());
ois = new ObjectInputStream(socket.getInputStream());
}
catch (IOException e){ }
t = new Thread(this);
t.start();
}
public void run()
{
try
{
while(true){
// send and recev message
}
}
}
catch (Exception e){ }
}
Move the construction of the object streams out of the constructor and into the run() method. The process implies I/O with the peer so it shouldn't be carried out in the accept() thread.
I have a ArrayList<Socket> listOfSockets that adds a socket when I receive clientsocket = serversocket.accept() like this listOfSockets.add(clientsocket)
and then I send this whole list to another class like this.
Server_Client client = new Server_Client(clientSock, clientSocketList);
Thread X = new Thread(client);
X.start();
Here is the code for my class that I send the list and socket to
public class Server_Client implements Runnable{
//ArrayList<String> UserNameList;
ArrayList<Socket> clientSocketList;
Socket socket = null;
public Server_Client(Socket X, ArrayList<Socket> L){
this.socket = X;
this.clientSocketList = L;
}
#Override
public void run() {
try {
ListenforMessage NewMessages = new ListenforMessage(socket);
Thread myThread = new Thread(NewMessages);
myThread.start();
} catch (Exception e) {
System.err.println(e);
}
}
//------------------------------------------------------------------
//Class that handles incoming messages!
class ListenforMessage implements Runnable{
Socket socket;
DataInputStream IN;
DataOutputStream OUT;
public ListenforMessage(Socket x) {
this.socket = x;
}
#Override
public void run() {
try {
while (true) {
IN = new DataInputStream(socket.getInputStream());
OUT = new DataOutputStream(socket.getOutputStream());
String message = IN.readUTF();
//System.out.println(message);
for (Socket TEMP_SOCK : clientSocketList) {
if(TEMP_SOCK != this.socket){
SendMessage(message);
}
}
}
} catch (IOException ex) {
Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
public void SendMessage(String m) throws IOException{
try {
DataOutputStream OUT = new DataOutputStream(socket.getOutputStream());
OUT.writeUTF(m);
System.out.println("User said: " + m);
} catch (Exception e) {
}
}
//------------------------------------------------------------------
}
In the ListenforMessage class, in the for-loop I go trough the size of list and if TEMP_SOCK is not this.socket then I want to send a message to that socket, and if it is then don't do anything. But my problem is that when I connect with 2 clients they can't send message to each other. They just send the message to the server and the server sends back the message to the client. My question is, can you use a list like I do to check if the socket is not the socket that you are YOURSELF.
cause now Client1 sends a messages and receive the same messages from sever, and Client2 does the same thing.
I want Client1 to send and Client2 to receive the message(And other sockets on the same list)
Your code doesn't work because you should let SendMessage know to which socket it should send the message (i.e. you should pass TEMP_SOCK to it), instead, you're making it use the socket variable, which is the socket connected to the client that just sent the message.
Let me explain my work.
I have to send a file from server to client. In server I accepted the connection from the client and not closed the connection. Now I have to send the data as streams to the client.
Now I have selected a content and wrote in a file in method.
I have send method in which I have to send the file in inputstreams to the client. How to send?
public static void main(String args[])
{
int port=5000;
while(true)
{
try
{
ServerSocket ser=new ServerSocket(port+10);
System.out.println("CLIENT A IS CONNECTED");
ser.close();
}
catch(Exception e)
{
System.out.println(e);
}
try
{
ServerSocket ser1=new ServerSocket(port+20);
ser1.accept();
System.out.println("CLIENT B IS CONNECTED");
}
catch(Exception e)
{
System.out.println(e);
}
try
{
ServerSocket ser2=new ServerSocket(port+30);
ser2.accept();
System.out.println("CLIENT C IS CONNECTED");
}
catch(Exception e)
{
System.out.println(e);
}
try
{
ServerSocket ser3=new ServerSocket(port+40);
ser3.accept();
System.out.println("CLIENT D IS CONNECTED");
}
catch(Exception e)
{
System.out.println(e);
}
}
}
In main method I accepted All the client request.
private void jButton1ActionPerformed1(java.awt.event.ActionEvent evt) //sendbutton
{
try
{
FileReader buf=new FileReader("e:\\input.txt");
int port= // the port of client which I selected to send the data
try
{
#SuppressWarnings("resource")
ServerSocket ser=new ServerSocket(port);
Socket soc=ser.accept();
BufferedReader toclient=new BufferedReader(buf);
DataOutputStream dos=new DataOutputStream(soc.getOutputStream());
System.out.println(dos.toString());
dos.flush();
dos.close();
}
catch(Exception e)
{
System.out.println(e);
}
}
catch(Exception e)
{
System.out.println(e);
}
}
Now my question is I already opened the ports and the connection is established in the main method. I have to send the data from server to client by selecting to which client should receive the data in sendbutton method. I am confused how to check or pass the socket object serv1 to the send method?.
below is the sample server code (please add corresponding import statements and your logic)
class SampleServer
{
private int port;
private ArrayList clientList;
public SampleServer()
{
this.port = 4444;
}
public SampleServer(int port)
{
this.port = port;
}
public void startServer()
{
ServerSocket ss = new ServerSocket(this.port);
Socket soc;
while(true)
{
soc = ss.accept();
clientList.add(soc);
}
}
public ArrayList getClientList()
{
return clientList;
}
}
Below is the sample main method (take this as a reference and create your own code)
public class Main
{
public static void main(String[] args) throws Exception
{
//Create a server
//Server has to be only one and multiple clients can connect it
SampleServer server = new SampleServer(5555);
server.startServer();
//Creating one client
Socket soc = new Socket("localhost", 5555);
//Similarly create n-number of clients and connect to the same port as that of server
//server.getClientList(); will help you get the list of the clients connected to the server
}
}
I finished writing a Client/Server Socket communication program that works fine. Now I'm trying to figure out how to make it so that I can have multiple Client connections to the Server at once. I've looked around and there seems to be more than a couple of different ways to do this. so I've come here to ask you guys for help/suggestions.
My Server:
public class Server {
private ServerSocket serverSocket = null;
private Socket clientSocket = null;
public Server() {
try {
serverSocket = new ServerSocket(7003);
} catch (IOException e) {
System.err.println("Could not listen on port: 7003");
System.exit(1);
}
try {
clientSocket = serverSocket.accept();
} catch (IOException e) {
System.err.println("Accept failed");
System.exit(1);
}
}
public void startServer() throws IOException {
PrintWriter output = new PrintWriter(clientSocket.getOutputStream(), true);
BufferedReader input = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String inputLine, outputLine;
outputLine = "Connected to Server";
output.println(outputLine);
while ((inputLine = input.readLine()) != null) {
// This just determines users input and server ruturns output based on that
outputLine = this.getServerOutput(inputLine);
output.println(outputLine);
if (outputLine.equals("Bye"))
break;
}
output.close();
input.close();
clientSocket.close();
serverSocket.close();
}
}
Would I need to make my constructor create threads and startServer() or would be my run method?
You should use ExecutorService. Your client request processing would be the run() of a Runnable and after each accept you can call ExecutorService.submit(runnableTask) to asynchronously service the client.
A sample using ExecutorService.
public class MyServer {
private static MyServer server;
private ServerSocket serverSocket;
/**
* This executor service has 10 threads.
* So it means your server can process max 10 concurrent requests.
*/
private ExecutorService executorService = Executors.newFixedThreadPool(10);
public static void main(String[] args) throws IOException {
server = new MyServer();
server.runServer();
}
private void runServer() {
int serverPort = 8085;
try {
System.out.println("Starting Server");
serverSocket = new ServerSocket(serverPort);
while(true) {
System.out.println("Waiting for request");
try {
Socket s = serverSocket.accept();
System.out.println("Processing request");
executorService.submit(new ServiceRequest(s));
} catch(IOException ioe) {
System.out.println("Error accepting connection");
ioe.printStackTrace();
}
}
}catch(IOException e) {
System.out.println("Error starting Server on "+serverPort);
e.printStackTrace();
}
}
//Call the method when you want to stop your server
private void stopServer() {
//Stop the executor service.
executorService.shutdownNow();
try {
//Stop accepting requests.
serverSocket.close();
} catch (IOException e) {
System.out.println("Error in server shutdown");
e.printStackTrace();
}
System.exit(0);
}
class ServiceRequest implements Runnable {
private Socket socket;
public ServiceRequest(Socket connection) {
this.socket = connection;
}
public void run() {
//Do your logic here. You have the `socket` available to read/write data.
//Make sure to close
try {
socket.close();
}catch(IOException ioe) {
System.out.println("Error closing client connection");
}
}
}
}
how to make it so that I can have multiple Client connections to the Server at once
Right now you are starting your server and immediately waiting for a single client to connect in the constructor.
clientSocket = serverSocket.accept();
Then you handle that single socket connection inside of your startServer() method. This means that no other clients will be handled.
public void startServer() throws IOException {
PrintWriter output = new PrintWriter(clientSocket.getOutputStream(), true);
...
Typically with a server pattern like this, you would do something like the following:
Setup your server socket in the constructor.
Create an acceptClients() method which would loop waiting for a client to be accepted. This could fork a thread to accept the clients in a thread of its own in the background.
For each client, either fork a thread to handle the connection, passing the thread the clients socket. Better would be to, as #basiljames shows, use an ExecutorService to manage the threads for you.
Here's some sample code:
public class Server {
private ServerSocket serverSocket = null;
public Server(int portNumber) throws IOException {
serverSocket = new ServerSocket(portNumber);
}
// this could be run in a thread in the background
public void acceptClients() throws IOException {
// create an open ended thread-pool
ExecutorService threadPool = Executors.newCachedThreadPool();
try {
while (!Thread.currentThread().isInterrupted()) {
// wait for a client to connect
Socket clientSocket = serverSocket.accept();
// create a new client handler object for that socket,
// and fork it in a background thread
threadPool.submit(new ClientHandler(clientSocket));
}
} finally {
// we _have_ to shutdown the thread-pool when we are done
threadPool.shutdown();
}
}
// if server is running in background, you stop it by killing the socket
public void stop() throws IOException {
serverSocket.close();
}
// this class handles each client connection
private static class ClientHandler implements Runnable {
private final Socket clientSocket;
public ClientHandler(Socket clientSocket) {
this.clientSocket = clientSocket;
}
public void run() {
// use the client socket to handle the client connection
...
}
}
}
Using the ExecutorService thread-pools is recommended for just about all Thread implementations like this. If, however, you are stuck to using raw Thread for some reason, you can do the following instead in your acceptClients() method:
public void acceptClients() throws IOException {
while (!Thread.currentThread().isInterrupted()) {
// wait for a client to connect
Socket clientSocket = serverSocket.accept();
// fork a background client thread
new Thread(new ClientHandler(clientSocket)).start();
}
}
Change this: public void startServer() throws IOException
To this: public void startServer(Socket clientSocket) throws IOException
Then all you need to do is:
public Server()
{
try
{
serverSocket = new ServerSocket(7003);
}
catch (IOException e)
{
System.err.println("Could not listen on port: 7003");
System.exit(1);
}
try
{
while(true) {
final Socket socket = serverSocket.accept();
new Thread(new Runnable() {
public void run() {
try {
startServer(socket);
} catch(IOException e) {e.printStackTrace();}
}
}).start();
}
}
catch(IOException e)
{
System.err.println("Accept failed");
System.exit(1);
}
}
And lastly, you can remove private Socket clientSocket = null;
That should get you there. Or at least pretty close.
private static final int SERVER_PORT = 35706;
private ServerSocket serverSocket;
private final ArrayList<ClientThread> activeClients = new ArrayList<>();
public void startServer() {
try {
serverSocket = new ServerSocket(SERVER_PORT);
final ExecutorService clientPool = Executors.newCachedThreadPool();
while (!serverSocket.isClosed()) {
try {
Future<Socket> future = clientPool.submit(() -> {
Socket socket = serverSocket.accept();
ClientThread clientThread= new ClientThread(socket);
return (socket);
});
activeClients.add(future.get());
} catch (IOException e) {
clientPool.shutdownNow();
System.out.println(e.getMessage());
} catch (InterruptedException | ExecutionException e) {
System.out.println(e.getMessage());
}
}
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
public void stopServer() {
try {
serverSocket.close();
activeClients.forEach(socket -> {
try {
socket.close();
} catch (IOException e) {
System.out.println(e.getMessage());
}
});
} catch (IOException ex) {
System.out.println(e.getMessage());
}
}
private static class ClientThread implements Runnable{
private final Socket socket;
public ClientThread(Socket socket) throws IOException {
this.socket = socket;
}
#Override
public void run() {
/* Your implementation */
}
}