Отправка сообщения всем клиентам (связь Client-Server)

Итак, теперь я создаю многопоточное приложение на основе клиентского сервера. На стороне сервера я делаю поток для постоянно подключенного соединения.

В классе thread я создаю метод отправки команды клиенту. Я просто хочу, как отправить параметр ко всему запущенному клиенту? Для простого утверждения я просто хочу, чтобы этот сервер отправил сообщение всем подключенным клиентом.

Я читал этот пост и нашел sendToAll(String message) метод эта ссылка. Но когда я пытаюсь использовать свой код, в ServerSocket нет такого метода.

Хорошо, это мой пример кода для сервера и потока.

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) {}
}

}

Спасибо за помощь:)

Ответы

Ответ 1

Нижеприведенный ответ не рекомендуется для полноценного сервера, так как для этого вы должны использовать Java EE с сервлетами, веб-сервисами и т.д.

Это предназначено только тогда, когда несколько компьютеров хотят подключиться для выполнения конкретной задачи, а использование простых сокетов Java - не общая проблема. Подумайте о распределенных вычислениях или многопользовательских играх.

EDIT: Я - с первого поста - сильно обновил эту архитектуру, теперь протестировал и потокобезопасен. Любой, кто в ней нуждается, может скачать здесь.

Просто используйте (напрямую или по подклассу) Server и Client, start() их, и все готово. Прочтите встроенные комментарии для более мощных параметров.


В то время как общение между клиентами довольно сложно, я постараюсь упростить его, насколько это возможно.

Вот точки на сервере:

  • Сохранение списка подключенных клиентов.
  • Определение потока для ввода сервера.
  • Определение очереди полученных сообщений.
  • Опрос потока из очереди и работа с ним.
  • Некоторые методы утилиты для отправки сообщений.

И для клиента:

  • Определение потока для ввода клиента.
  • Определение очереди полученных сообщений.
  • Опрос потока из очереди и работа с ним.

Здесь класс Server:

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);
    }

}

И вот для класса Client:

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);
    }
}

Ответ 2

В серверном сокете нет способа отправить данные или сообщение всем работающим потокам клиники. Пройдите через программу ServerThread.java, которая вызывает сервер sendToAll usng.

// ... and have the server send it to all clients
server.sendToAll( message );

Ответ 3

Проверьте нульMQ. Существуют методы, известные как "pub sub" или "publish subscribe", которые будут делать то, что вы хотите. Вы также можете использовать его для связи между вашими потоками. По-моему, это потрясающая библиотека. Он имеет привязки java или jzmq вместе с более чем 30 другими пользователями, поэтому вы сможете использовать его в своей программе.

http://www.zeromq.org/

Ответ 4

Я адаптировал предыдущий код, но я получаю

java.lang.NullPointerException

когда я делаю это clientList.add(new ConnectionToClient(s)); ,

Ты знаешь почему? Это прекрасно работает, когда я этого не делаю.