Программа Сервер / Мультиклиент не отправит сообщение всем клиентам - PullRequest
0 голосов
/ 22 сентября 2018

Я работаю над программой, включающей многопоточный сервер, в которой я хочу, чтобы сообщения, отправляемые клиентами, передавались обратно каждому клиенту, подключенному в данный момент к серверу.Это не совсем так.Я отправлю сообщение от клиента на сервер, и оно вернется к тому же клиенту.Не для другого клиента.Допустим, с одним клиентом я последовательно набираю «Один», затем «Два», затем «Три».Обмен будет выглядеть примерно так:

Клиент 1: «Один»

Эхо от сервера ON Консоль клиента 1: «Один»

Клиент 1: «Два»

Эхо от сервера ON Консоль клиента 1: «Два»

Клиент 1: «Три»

Эхо от сервера ON 1 Консоль клиента: «Три»

Эта часть делает то, что должна.Но абсолютно ничего не происходит на консоли клиента 2.Допустим, обмен выше уже произошел.Экран клиента 2 по-прежнему будет пустым.Затем я наберу что-нибудь в Client 2, скажем, «Test».Сервер ответит Клиенту 2 «Один».Допустим, я снова набираю «Test» в Client 2. Сервер ответит «Two».Вы поняли идею.Я не уверен, почему он это делает.У меня есть три файла: Клиент, Сервер и один, предназначенный для управления соединениями между ними.

РЕДАКТИРОВАТЬ: Я думаю, я знаю проблему!В строке 43 в клиенте консоль ожидает некоторого пользовательского ввода, прежде чем он продолжится.Я думаю, поэтому, когда первый клиент отправляет пользовательский ввод, он получает правильный ответ, а второй - нет: потому что второй клиент ничего не вводил в консоль, и он все еще ожидает некоторого ввода, чтобыпродолжить.Любые идеи о том, как обойти это?

Клиент:

package client;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;

public class Client {

//The socket for the client
Socket sock;
//The stream to read incoming data
DataInputStream din;
//The stream to send outgoing data
DataOutputStream dout;

public static void main(String[] args) {
    //Create a new client
    new Client();
}

public Client() {
    try {
        //Activate the socket to the host and port
        sock = new Socket("localhost", 4444);
        //Open the input and output streams 
        din = new DataInputStream(sock.getInputStream());
        dout = new DataOutputStream(sock.getOutputStream());

        //Start listening for user input
        listenIn();
    } catch (UnknownHostException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

public void listenIn() {
    //Monitors the console for user input
    Scanner userIn = new Scanner(System.in);

    while(true) {
        //While there is nothing left to read from the console
        while(!userIn.hasNextLine()) {
            try {
                //Ensures resources aren't constantly being used by listening for input
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        //Get line from user input
        String input = userIn.nextLine();

        //if user exits the client, break the loop and exit the program
        if(input.toLowerCase().equals("quit")) {
            break;
        }

        try {
            //outputs user input to Server
            dout.writeUTF(input);
            //Flushes all data out of the data output stream's buffer space
            dout.flush();

            //While there's nothing to read from the input stream, save resources
            while(din.available() == 0) {
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            //When there's incoming data, print it to the console
            String reply = din.readUTF();
            System.out.println(reply);
        } catch (IOException e) {
            e.printStackTrace();
            break;
        }
    }

    //Close all the I/O streams and sockets, so there aren't memory leaks
    try {
        din.close();
        dout.close();
        sock.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

}

Сервер:

package server;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;

public class Server {

//The server's socket
ServerSocket sSock;
ArrayList<ServerConnection> connections = new ArrayList<ServerConnection>();
boolean run = true;

public static void main(String[] args) {
    //Create a new server
    new Server();
}

public Server() {
    try {
        //Initialize the server socket to the correct port
        sSock = new ServerSocket(4444);
        //While the socket should be open
        while(run) {
            //Initialize the client socket to the correct port
            Socket sock = sSock.accept();
            //Create a new server connection object between the client socket and the server
            ServerConnection sConn = new ServerConnection(sock, this);
            //Start the thread
            sConn.start();
            //Add the connection to the arraylist
            connections.add(sConn);
        }  
    } catch (IOException e) {
        e.printStackTrace();
    }
}
}

Подключение к серверу:

package server;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;

public class ServerConnection extends Thread{

Socket sock;
Server server;
DataInputStream in;
DataOutputStream out;
boolean run = true;

//Create the server connection and use super to run it with Thread's constructor
public ServerConnection(Socket socket, Server server) {
    super("ServerConnectionThread");
    this.sock = socket;
    this.server = server;
}

public void sendOne(String text) {
    try {
        //Write the text to the output stream
        out.writeUTF(text);
        //Flush the remaining data out of the stream's buffer space
        out.flush();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

//Send a string to every client
public void sendAll(String text) {
    /*Iterate through all of the server connections in the server
    and send the text to every client*/
    for(int i = 0; i < server.connections.size(); i++) {
        ServerConnection sc = server.connections.get(i);
        sc.sendOne(text);
    }
}

public void run() {
    try {
        //Set the input stream to the input from the socket
        in = new DataInputStream(sock.getInputStream());
        //Set the output stream to write out to the socket
        out = new DataOutputStream(sock.getOutputStream());

        //While the loop should be running (as determined by a boolean value)
        while(run) {
            //While there is no incoming data, sleep the thread to save resources
            while(in.available() == 0) {
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            //Store the incoming data in a string
            String textIn = in.readUTF();
            //Send it to all clients
            sendAll(textIn);
        }

        //Close datastreams and socket to prevent memory leaks
        in.close();
        out.close();
        sock.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

}

1 Ответ

0 голосов
/ 22 сентября 2018

Как и на стороне сервера, вы можете использовать отдельный поток для обработки входящих данных на стороне клиента.Таким образом, ожидание пользовательского ввода в консоли не будет блокировать входящий поток данных.

Вот идея, как вы могли бы реализовать это.

Новое ClientConnection:

package client;

import java.io.DataInputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.SocketException;

public class ClientConnection extends Thread {

    DataInputStream din = null;

    public ClientConnection(Socket socket) throws IOException {
        this.setName("Client-Thread");
        this.din = new DataInputStream(socket.getInputStream());
    }

    public void run() {

        boolean run = true;

        while (run) {

            // While there's nothing to read from the input stream, save resources
            try {

                // When there's incoming data, print it to the console
                String reply = din.readUTF();
                System.out.println(reply);

                run = this.isAlive();

            } catch (SocketException e) {
                System.out.println("Disconnected");
                run = false;
            } catch (IOException e) {
                e.printStackTrace();
            }



        }

        try {
            din.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

}

А вот переформулированный Клиент:

package client;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;

public class Client {

    // The socket for the client
    Socket sock;

    // The stream to send outgoing data
    DataOutputStream dout;

    public static void main(String[] args) {
        // Create a new client
        new Client();
    }

    public Client() {
        try {
            // Activate the socket to the host and port
            sock = new Socket("localhost", 4444);
            // Open the input and output streams
            dout = new DataOutputStream(sock.getOutputStream());

            //Listening for incoming messages
            ClientConnection client = new ClientConnection(sock);
            client.start();

            // Start listening for user input
            listenIn();


        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void listenIn() {
        // Monitors the console for user input
        Scanner userIn = new Scanner(System.in);

        while (true) {
            // While there is nothing left to read from the console
            while (!userIn.hasNextLine()) {
                try {
                    // Ensures resources aren't constantly being used by listening for input
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            // Get line from user input
            String input = userIn.nextLine();

            // if user exits the client, break the loop and exit the program
            if (input.toLowerCase().equals("quit")) {
                break;
            }

            try {
                // outputs user input to Server
                dout.writeUTF(input);
                // Flushes all data out of the data output stream's buffer space
                dout.flush();
            } catch (IOException e) {
                e.printStackTrace();
                break;
            }
        }

        // Close all the I/O streams and sockets, so there aren't memory leaks
        try {
            dout.close();
            sock.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

На стороне сервера вы также можете рассмотреть возможность удаления отключенных клиентов из списка подключений:

public class ServerConnection extends Thread {
    ...    
    public void run() {
        try {
            ...
        } catch (SocketException e) {
            System.out.println("Client disconnected");
            server.connections.remove(this);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Iнадеюсь, это поможет.

...