Jak zrobić identyfikatory klientów w prostym chacie na socketach.

0

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.

0

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?

0

Jeżeli robisz serwer na socketach, to i tak musisz otwierać nowe gniazdko dla każdego klienta, więc wystarczy po stronie serwera powiązać obiekt socketa z klientem.

0

A mógłbym prosić jakiś konkretny przykład?
Tak ze dwie linijki kodu. ;-)

???

0

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

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ć?

0
 catch (Exception e)
        {

        }

Będzie lanie...

0

A coś bardziej na temat? ;)

0

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ć.

0

To dopiero zaczątek aplikacji, poprawie to. Zabawa w wielowątkowość jest jest bardzo skomplikowana?, początkujący programista ogranie? 😊

0

Jak zainstalować SQLite? Są jakieś programy po których instalacji SQLite się zainstaluje? Próbowałem z plikami z głównej strony SQLite z jakimś tutorialem ale nie znalazłem u siebie takiego pliku jak gość miał na filmie.

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

A jak mam to uruchomić? Intelij pokazuje milion błędów w kodzie po zaimportowaniu klas które podpowiadał. Muszę poszukać w internecie zaimportować sam czy, co?

0

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ś.

0

@Emdzej93:

import java.io.*;
import java.net.Socket;
import java.util.logging.Logger;

Tyle importów podpowiedział IneliJ. ClientComponent i Server nadal świecą się na czerwono. To też kwestia importów? Jak tak to mógłbyś podesłać odpowiednie?

0

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 porcie

        while(!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;

0

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

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.

0

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?

0

Jedna lista w zupełności wystarczy. Zawierać ona powinna obiekty klasy reprezentującej klienta (w moim przypadku był to ten ClientComponent). Wewnątrz tej klasy możesz stworzyć pola jak ID, username, sockety, itp, itd.

0

Ale jak to ma wyglądać? Z socketami trzeba nowy port utworzyć? ID to tylko ID = 123? Chodzi mi o takie podstawy podstaw.

0

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

https://imgur.com/a/gNlU4

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

0

Wszystko fajnie ale dlaczego w 25 linii Client, (newClient) i .start świecą się na czerwono?

1

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.

1 użytkowników online, w tym zalogowanych: 0, gości: 1