После прочтения вашего кода, просто случайно он работает для первого экземпляра.
Давайте пройдемся по коду, чтобы увидеть, что происходит:
В gui.java
, высоздайте новый сервер:
_server = new server();
_server.start(4000);
, который, в свою очередь, попытается прослушать данный порт:
server = new ServerSocket(port);
Это, очевидно, не будет работать для второго экземпляра, но вы ловитеполучим IOException
и просто выбросим его:
try {
server = new ServerSocket(port);
while(true) {
socket = server.accept();
new Thread(new ConnectionHandler(socket)).start();
}
} catch(IOException i) {
// Please do something here
}
Итак, у второго экземпляра не будет сервера, который перечисляет порт.
Не следует просто игнорировать исключение, ноэто другая проблема. Таким образом, у вас работает только один сервер. Что хорошо. Один сервер, много клиентов.
В вышеописанном методе есть другая проблема, заключающаяся в том, что этот метод никогда не вернется (за исключением случаев, когда он не может привязаться к порту).
Теперь, когда клиент отправляет вам данные, сервер получит их здесь:
while (!line.equals("Over")) {
try {
line = in.readUTF();
app.area.append(line+"\n");
} catch(IOException i) {
System.out.println(i);
}
}
Единственное, что вы делаете с полученными данными, это добавляете их в графический интерфейс.
Другие клиенты не увидят это сообщение.
Вы должны отправить данные всем другим клиентам. Что требует, чтобы вы держали список всех подключенных клиентов вокруг.
И в этот момент все усложняется:
У вас общее изменяемое состояние, к которому обращается более одного потока.
Что означаетВы должны использовать синхронизацию.
Хорошо, давайте сделаем это:
Добавьте List<ConnectionHandler>
к вашему классу сервера:
List<ConnectionHandler> clients = new ArrayList<>();
Ив качестве примера: блокировка:
Object lock = new Object();
Затем нам нужно добавить любого нового подключенного клиента в этот список:
socket = server.accept();
ConnectionHandler client = new ConnectionHandler(this, socket)
synchronized (lock) {
clients.add(client);
}
new Thread(client).start();
Теперь нам просто нужен метод для распределения всех входящих сообщений в классе сервера:
void distributeMessage(String message) {
List<ConnectionHandler> clientsCopy;
synchronized (lock) {
clientsCopy = new ArrayList<>(clients);
}
for (ConnectionHandler client : clientsCopy) {
client.sendMessage(message);
}
}
Теперь нам нужно изменить ConnectionHandler, и мы начнем с очистки полей:
private Socket socket;
private DataInputStream in;
private DataOutputStream out;
private server server;
Это все необходимые нам поля.
Далее нам нужно изменить конструктор этого класса:
public ConnectionHandler(server server, Socket socket) {
this.server = server;
this.socket = socket;
this.in = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
this.out = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));
}
Всеполя должны быть инициализированы в конструкторе, если это возможно.
Затем мы должны добавить наш новый sendMessage(String message)
метод:
public void sendMessage(String message) {
try {
out.writeUTF(message);
out.flush();
} catch (IOException e) {
// TODO: Here you HAVE to check if the connection was closed
// And if it was closed, call a method in the server class to
// remove this client.
e.printStackTrace();
}
}
Почтисделанный. Теперь клиенты на самом деле должны слушать сообщение, которое они получают. Я оставляю это на ваше усмотрение. В основном это то же самое, что вы делали на своем сервере раньше.