Многопользовательский TCP-чат Java с реализацией графического интерфейсаJAVA

Программисты JAVA общаются здесь
Ответить Пред. темаСлед. тема
Anonymous
 Многопользовательский TCP-чат Java с реализацией графического интерфейса

Сообщение Anonymous »

Как начинающий программист, в настоящее время я работаю над созданием приложения чата на Java, к которому могут присоединиться несколько клиентов. Однако я столкнулся с проблемой, связанной с обновлением списка пользователей, отображаемого в графическом интерфейсе на стороне клиента.
Вот что происходит: когда клиент присоединяется к чату или покидает его, сервер отправляет сообщение, содержащее список клиентов, всем подключенным клиентам. Я пытаюсь обновить список пользователей, отображаемый в графическом интерфейсе на стороне клиента, на основе этого сообщения. Однако я заметил, что иногда список участников четвертого или пятого клиента отображается пустым в их графическом интерфейсе, а иногда список не обновляется правильно при присоединении нового клиента.
Я' Я обдумываю, есть ли более эффективный способ отправить список клиентов непосредственно с сервера и добавить их в список участников клиента, полностью минуя необходимость в сообщении «/members».
Я внедрил правило, исключающее отображение списка «/members» в области чата, поскольку я намерен добавлять имена непосредственно в список участников в графическом интерфейсе на стороне клиента. Я также отделил графический интерфейс от серверной логики, чтобы гарантировать, что графический интерфейс индивидуален для каждого клиента.
Я не уверен, что этот подход является наиболее эффективным, и я Мне нужен совет о том, как решить эти проблемы и улучшить функциональность моего приложения.
Заранее благодарим вас за любую помощь, которую вы можете оказать!
Клиентская часть кода:

Код: Выделить всё

    package TCP;

import javax.swing.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Base64;

public class Client implements Runnable {
private Socket client;
private BufferedReader in;
private PrintWriter out;
private int port;
private String ip;
private boolean done;
private GuiChatt guiChatt;

public Client(GuiChatt guiChatt, String ip, int port) {
this.guiChatt = guiChatt;
this.ip = ip;
this.port = port;
}

@Override
public void run(){
try {
client = new Socket(ip, port);
out = new PrintWriter(client.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(client.getInputStream()));
done = true;

String userName = guiChatt.getUserName();
out.println(userName); //send user join name

InputHandler inHandler = new InputHandler(in);
Thread thread = new Thread(inHandler);
thread.start();

String inMessage;
while (done && (inMessage = in.readLine()) != null) {
guiChatt.addMessage(inMessage);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
shutdown();
}
}

private void shutdown() {
done = true;
try {
if (in != null) {
in.close();
}
if (out != null) {
out.close();
}
if (client != null && !client.isClosed()) {
client.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}

public void sendMessageToServer(String message) {
if (out != null) {
System.out.println("(sendMessage to server Client class)Attempting to send message: " + message);
out.println(message);
if (out.checkError()) {
System.out.println("(sendMessage to server Client class)    Message not sent: " + message);
} else {
System.out.println("(sendMessage to server Client class) Message sent: " + message);
}
}
}

//server message listener gets messeages from the server that other clients have sent
class InputHandler implements Runnable { //asks constantly for new line inputs
BufferedReader in;
public InputHandler(BufferedReader in) {
this.in = in;
}

@Override
public void run() {
try {
String inMessage;
while (done && (inMessage = in.readLine()) != null) {
if (inMessage.startsWith("/members")) {
// Handle /members message
String[] members = inMessage.substring(9).split(",");
System.out.println("Received members list: " + String.join(", ", members)); // Added logging
SwingUtilities.invokeLater(() ->  {
guiChatt.updateMembersList(members);
});
} else if (inMessage.startsWith("/image")) {
// Handle image messages
String imageData = inMessage.substring(7);
byte[] decodedImage = Base64.getDecoder().decode(imageData);
ImageIcon receivedImage = new ImageIcon(decodedImage);
guiChatt.addImage(receivedImage);
} else if (!inMessage.startsWith("/")) { // Skip messages starting with "/"
// Handle regular chat messages
guiChatt.addMessage(inMessage);
}
}
} catch (IOException e) {
e.printStackTrace();
shutdown();
}
}
}
}

```
фрагменты графического интерфейса. связанные со списком

Код: Выделить всё

    private JList membersList;

////
membersListModel = new DefaultListModel();
membersList = new JList(membersListModel);
membersList.setBackground(new Color(46, 46, 46));
membersList.setForeground(Color.WHITE);
membersList.setFont(new Font("Arial", Font.PLAIN, 14));
JScrollPane membersScrollPane = new JScrollPane(membersList);
membersScrollPane.setBorder(null);
membersScrollPane.setPreferredSize(new Dimension(150, messagesScrollPane.getHeight()));

////

public void updateMembersList(String[] members) {
SwingUtilities.invokeLater(() -> {
membersListModel.clear();
for (String member : members) {
membersListModel.addElement(member);
}
});
}
и мой класс сервера:

Код: Выделить всё

    package TCP;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Server implements Runnable {
private ServerSocket serverSocket;
private int port;
private List connectionHandlerList; //this broadcast to all clientsList
private ExecutorService pool;
private Set clientsList;
private boolean done;

public Server(int port) {
this.port = port;
connectionHandlerList = new CopyOnWriteArrayList();
clientsList = Collections.synchronizedSet(new HashSet());
done = false;
}

@Override
public void run(){
try {
serverSocket = new ServerSocket(port);
pool = Executors.newCachedThreadPool(); //maybe add this to the constructor later on for debugging
done = true;
while (done) {
Socket client = serverSocket.accept();
ConnectionHandler handler = new ConnectionHandler(client, this);//for each new client
connectionHandlerList.add(handler);
pool.execute(handler);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
shutdown();
}
}

public void broadcast(String message){
synchronized (connectionHandlerList){
for(ConnectionHandler connectionHandler : connectionHandlerList){
if (connectionHandler != null){
connectionHandler.sendMessage(message);
}
}
}
}

public synchronized void newClient(String client, ConnectionHandler handler){
clientsList.add(client);
broadcast(client + " joined the chat");
updateMembers();
}

public synchronized void leftClient(String client, ConnectionHandler handler) {
clientsList.remove(client);
broadcast(client + " left the chat");
updateMembers();
}

public void updateMembers() {
StringBuilder memberList = new StringBuilder("/members ");
synchronized (clientsList) {
for (String client : clientsList) {
memberList.append(client).append(",");
}
}
if (memberList.length() > 0) {
memberList.setLength(memberList.length() - 1); // Remove the trailing comma
}
System.out.println("Broadcasting members: " + memberList.toString());
broadcast(memberList.toString());
}
public void shutdown() {
done = true;
pool.shutdown();
try {
if (serverSocket != null &&  !serverSocket.isClosed()) {
serverSocket.close();
}
synchronized (connectionHandlerList) {
for (ConnectionHandler connectionHandler : connectionHandlerList) {
connectionHandler.shutdown();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}

//the class below is created for each client
class ConnectionHandler implements Runnable {
private Socket client;
private BufferedReader in; //gets the stream from socket, meaning when client send
private PrintWriter out; //writes out to the  client
private String userName;
private final Server server;

public ConnectionHandler(Socket client, Server server) {
this.client = client;
this.server = server;
}

@Override
public void run() {
try {
out = new PrintWriter(client.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(client.getInputStream()));

//ADD FUNCTIONALITY FOR SENDING AND RECIVNG HERE
userName = in.readLine(); //to get input from streams
server.newClient(userName, this);
//add each client to the list
String message;
while ((message = in.readLine()) != null) {
if (message.startsWith("/image ")) {
server.broadcast("/image " + message.substring(7));
} else {
server.broadcast(userName + ": " + message);
}
}
} catch (IOException e){
e.printStackTrace();
} finally {
//server.leftClient(client, this);
shutdown();
}
}

public void sendMessage(String message) {
out.println(message);
}

public void shutdown() {
try {
if(!client.isClosed()){
client.close();
}
server.leftClient(userName, this);
} catch (IOException e) {
//throw new RuntimeException(e);
e.printStackTrace();
}
}
}

public static void main(String[] args) {
Server server = new Server(12345);
new Thread(server).start();
}

}
Я не уверен, стоит ли включать более длинные фрагменты кода, поскольку мое приложение начинается с запроса пользователей ввести свое имя, IP-адрес и номер порта, прежде чем присоединиться к чату. Должен ли я предоставить этот первоначальный код приглашения вместе с соответствующими частями кода клиента и сервера, которые обрабатывают обмен данными и обновления списков пользователей?
Я попытался реализовать функцию обновления, которая периодически проверяет список подключенных клиентов каждые 10 секунд и соответствующим образом обновляет список участников. Однако я не уверен в его практичности и в том, правильно ли он синхронизирован. Я застрял в этой проблеме несколько дней и, несмотря на поиск решения, мне не удалось найти конкретное решение.

Подробнее здесь: https://stackoverflow.com/questions/785 ... plentation
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «JAVA»