Witam. Robię prosty chat który w założeniu ma działać tak, że wysłana wiadomość wysyłana jest do serwera który wyśle ją do odpowiedniego klienta. Problem jest taki, że nie wiem jak nadać jakieś identyfikatory dla klientów. Chat programuje na socketach.

- Rejestracja:prawie 15 lat
- Ostatnio:około 4 godziny
- Lokalizacja:Laska, z Polski
- Postów:10056
Kiedy klient się łączy do servera, albo zakłada konto możesz mu nadać identyfikator, jakąś liczbę porządkową.
Podejdź do tego z biznesowego punktu widzenia, skąd użytkownik będzie wiedział do jakiego innego użytkownika będzie wysyłał wiadomość? Po mailu? Nicku? Jakimś identyfikatorze liczbowym?

- Rejestracja:ponad 12 lat
- Ostatnio:ponad 4 lata
- Postów:231
Ja bym zrobił osobną klasę np.Klient w której jest pole Socket (te klienckie) oraz identyfikator. I przyjmijmy że parametrem konstruktora jest Socket. A listę klientów trzymasz w tablicy dynamicznej (ArrayList) o nazwie np. klienci. Wewnątrz konstruktora możesz generować id.
Socket client = server.accept();
klienci.add(client);
- Rejestracja:około 7 lat
- Ostatnio:prawie 6 lat
- Postów:139
A czy taki server...
import java.io.*;
import java.net.*;
import java.time.LocalTime;
import java.time.temporal.ChronoUnit;
import static java.time.LocalDate.now;
public class Server
{
public static void main(String[] args) throws IOException
{
String name = "Server";
LocalTime minutes = LocalTime.now();
minutes = minutes.truncatedTo(ChronoUnit.MINUTES);
try {
ServerSocket s = new ServerSocket(3001);
System.out.println("Czekamy na połączenie...");
Socket server = s.accept();
DataOutputStream dos2 = new DataOutputStream(server.getOutputStream());
dos2.writeUTF(String.valueOf(minutes) + " | " + name + "| " + "Klient został podłączony " + server.getInetAddress().getHostName());
System.out.println(("Klient został podłączony " + server.getInetAddress().getHostName()));
}
catch (Exception e)
{
}
}
}
..da radę obsłużyć wielu klientów na raz? Gdzie dokładnie te identyfikatory zrobić?

- Rejestracja:prawie 9 lat
- Ostatnio:5 miesięcy
- Lokalizacja:Futurama
- Postów:887
Jeżeli chcesz mieć wielu klientów to musisz się bawić w wielowątkowość.
Za to co podkreśliłem w poprzednim poście powinno być srogie lanie i 4 dni bez obiadu. Nie dość, że łapiesz Exception
, czyli może wpaść tam wszystko to na dodatek wyciszasz to. Wyjątki należy obsługiwać.
- Rejestracja:ponad 8 lat
- Ostatnio:dzień
- Postów:216
public class ClientComponent extends Thread {
final static Logger LOGGER = Logger.getLogger(ClientComponent.class);
private final Socket clientSocket;
private final Server server;
private OutputStream outputStream;
public ClientComponent(Server server, Socket socket) {
this.server = server;
this.clientSocket = socket;
LOGGER.info("Created ClientComponent for new client\n");
}
@Override
public void run() {
try {
handleNewClient();
} catch (IOException e) {
LOGGER.error("Error while handling new client\n" + e.toString());
}
}
private void handleNewClient() throws IOException {
InputStream inputStream = clientSocket.getInputStream();
this.outputStream = clientSocket.getOutputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String line;
while((line = bufferedReader.readLine()) != null) {
Message message = new Message(line);
MessageController.getInstance().sendToAll(message);
}
clientSocket.close();
server.getClientComponentSet().remove(this);
LOGGER.info("Client disconnected, current connections count: " + server.getClientComponentSet().size() + "\n");
}
}
public class Server extends Thread {
final static Logger LOGGER = Logger.getLogger(Server.class);
private int port;
private ServerSocket serverSocket;
private volatile boolean shutdown;
private Set<ClientComponent> clientComponentSet;
public Server(int port) {
this.shutdown = false;
this.port = port;
this.clientComponentSet = new HashSet<>();
LOGGER.info("Starting the server...\n");
}
@Override
public void run() {
try {
serverSocket = new ServerSocket(port);
LOGGER.info("Server started\n");
while(!serverSocket.isClosed() && !shutdown) {
Socket clientSocket = serverSocket.accept();
ClientComponent clientComponent = new ClientComponent(this, clientSocket);
clientComponentSet.add(clientComponent);
clientComponent.start();
}
} catch (IOException e) {
if(!shutdown) {
LOGGER.error("Failed to start the server\n" + e.toString() + "\n");
}
}
}
}
- Rejestracja:ponad 8 lat
- Ostatnio:dzień
- Postów:216
To kawałek mojego programu który kiedyś napisałem, nie 100% gotowiec. Pokazuje Ci milion błędów bo w tym kodzie nie ma importów. Poza tym kawałek z MessageController jest również do wywalenia, zapomniałem go wyrzucić a to inna część mojego programu, której tutaj nie wrzuciłem. Wzorując się jednak na moim sposobie możesz osiągnąć to co chciałeś.
- Rejestracja:ponad 8 lat
- Ostatnio:dzień
- Postów:216
Przecież Server i ClientComponent to klasy które sam zrobiłem i Ci wysłałem. Logger możesz całkowicie pominąć i zamienić na Println(), ponieważ nie zaciągnie Ci go automatycznie IntelliJ (musiałbyś dorzucić dependency do tego Loggera którego ja użyłem). Generalnie ten kod to nie jest opcja kopiuj wklej. Przeczytaj go, postaraj się zrozumieć co się tam dzieje i samemu zaimplementuj od 0. W skrócie na lekko uproszczonym przykładzie:
- masz klasę Server która w sobie ma Set czy Listę czy jakąkolwiek kolekcję Clientów, dodatkowo klasa Server dziedziczy po Thread i nadpisuje metodę run() w której:
@Override
public void run() {
try {
serverSocket = new ServerSocket(port); // stworzenie instancji ServerSocket'u na danym porciewhile(!serverSocket.isClosed()) { Socket clientSocket = serverSocket.accept(); //akceptuje przychodzące połączenie ClientComponent clientComponent = new ClientComponent(this, clientSocket); //tworzy nową instancję klasy reprezentującej klienta clientComponentSet.add(clientComponent); // dodaje utworzoną instancję klienta do zbioru klientów clientComponent.start(); } } catch (IOException e) { }
Teraz spójrz na klasę ClientComponent, każda z jej instancji jest po prostu nowym klientem połączonym z Serverem, każda z nich ma dostęp do Output/InputStream'u Servera i może pobierać i wysyłać dane. Teraz chciałeś jakoś zidentyfikować każdego połączonego klienta - wystarczy że dorzucisz sobie jakieś ID w postaci
String username;
- Rejestracja:około 7 lat
- Ostatnio:prawie 6 lat
- Postów:139
Ale co mam zrobić z takim ID?
String "1637623";
Jak pokazać serwerowi, że to jest ten klient? Chodzi mi o mniej więcej coś takiego:
class Client
{
String ID = "Jacek";
//wysyłanie wiadomości X o treści "cześć" do klienta o ID "Andrzej"
}
class Server
{
//przyjście wiadomości X na serwer
//wysłanie wiadomości X do klienta o ID "Andrzej"
}
class Client
{
String ID = "Andrzej";
//przyjście wiadomości X z serwera
System.out.println(X.FromServer(od: Jacek);
}

- Rejestracja:ponad 12 lat
- Ostatnio:ponad 4 lata
- Postów:231
Nie wiem jak masz zrobioną listę Clientów u Serwera, ale ja widzę dwa sposoby. Podczas wysyłania wiadomości kodujesz ją o parametry "autorID" i "adresatID". Potem albo Serwer przeszukuje pętlą z listy klientów i porównuje id, jeśli jest poprawne to wysyła do danego, bądź wysyłasz tą odpowiedź do każdego z klientów i to po ich stronie przechodzi filtracja czy wiadomość jest do nich, jeśli tak to ją wyświetlasz. Pamiętaj że socketami można wysyłać cały obiekt, więc warto stworzyć prostą klasę wiadomość której polami będą właśnie idAdresata, idNadawcy oraz treść wiadomości.
- Rejestracja:około 7 lat
- Ostatnio:prawie 6 lat
- Postów:139
Zrobiłem ArrayList i mam metodę:
lista.add (parametr)
Co mam wstawić jako parametr aby wyszło coś typu:
clientName = "Jacek", ID = 61727, (gniazdo lub coś do komunikowania się)
Czy lepiej do clientName, ID i gniazda zrobić osobne listy?
- Rejestracja:ponad 8 lat
- Ostatnio:dzień
- Postów:216
Klasa reprezentująca Client'a
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;public class Client extends Thread{
private int id;
private Socket socket;
private OutputStream outputStream;
private InputStream inputStream;public Client(int id, Socket socket){ this.id = id; this.socket = socket; } @Override public void run(){ try { outputStream = socket.getOutputStream(); inputStream = socket.getInputStream(); String greetingMessage = "Hello I'm new client with id: " + id; outputStream.write(greetingMessage.getBytes()); } catch (IOException e) { e.printStackTrace(); } }
}
Oraz klasa reprezentująca Server wraz z komentarzem
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;public class Server extends Thread {
private ServerSocket serverSocket;
private List<Client> clientList;public Server(int port) throws IOException { serverSocket = new ServerSocket(port); //tworzysz ServerSocket na wskazanym porcie clientList = new ArrayList<>(); //a tutaj liste w ktorej bedziesz trzymac klientow } @Override public void run() { while(true) { try { Socket clientSocket = serverSocket.accept(); //akcpetujesz przychodzące połączenie i przypisujesz je do nowego Socketu int id = clientList.size(); //generujesz jakieś id Client newClient = new Client(id, clientSocket); //tworzysz nowego clienta i nadajesz mu wygenerowane ID oraz Socket ktorzy wczesniej utworzyles clientList.add(newClient); //dodajesz obiekt tego clienta do listy newClient.start(); //startujesz metodę run() co spowoduje wyslanie powitalnej wiadomosci } catch (IOException e) { e.printStackTrace(); } } }
}
A nawet klasa Main
import java.io.IOException;
public class Main {
public static void main(String args[]) throws IOException {
Server server = new Server(9999);
server.start();
}
}
Przeanalizuj to co się tam dzieje i radziłbym douczyć się podstaw najpierw bo nie bardzo wiem nawet jak odpowiedzieć na Twoje pytania...
edit#
ja za to nie potrafię skleić kodu tak by się nie rozjeżdżał, sry, próbowałem
- Rejestracja:ponad 8 lat
- Ostatnio:dzień
- Postów:216
Naprawdę nie mam już siły próbować. Nic się nie świeci na czerwono. Jak chcesz być pewien że wszystko działa - napisz to od 0, wzorując się na tym co wysłałem. Dostałeś praktycznie 100% gotowca, jeżeli nie potrafisz go przekopiować to naprawdę nie potrafię pomóc.
main() { try { whole_application_logic; } catch (){} }