Witam
Mam problem ze zrobieniem banalnego połącznia klient serwer wielowątkowego. Problem jej to że tak naprawę nie wiem dla kogo i jakich metod powinienem wywoływać nowe wątki. Obecnie robię to na zasadzie że gdy klient się połączy to na serwerze tworze nowy wątek który zajmuje sie za komunikacje tzn za najzwyklejsze echo. Jednak nie działa ale nie mam pomysłu jak to poprawić. Grzebałem w necie znalazłem kilka kodów ale jakos nie mogę przerobić na tak prosty przypadek.
Będę wdzięczny za jakąś pomoc.
Zawsze musisz mieć oddzielny wątek na odbieranie wiadomości od każdego z klientów (dla każdego oddzielny), bo metody odczytu są blokujące. Do wysyłania nie potrzebujesz oddzielnego wątku, no chyba, że chcesz to sobie jakoś kolejkować, czy coś.
Zatem:
Klient: wątek główny + wątek odczytu
Serwer: wątek główny + wątek nasłuchujący na nowe połączenia + n * wątek odczytujący dane od klienta, gdzie n = liczba podłączonych klientów
Ok dzięki postaram się zastosować do tego co napisałeś.
Sorki za post pod postem. Ale dla klienta nie potrzebuje chyba wątków? Bo ja obecnie wychodzę z założenia ze uruchamiam kilka razy klienta.
Nie wiem jak to zrobić. podam kod możę a raczej na pewno gdzieś jest wykonywana mega głupota ale nie mam innej koncepcji.
Kod Klienta:
public class Client {
public static void main(String[] args) {
try{
Socket socket = new Socket("localhost", 2000);
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String odServera = "";
while(true){
String komunikat= JOptionPane.showInputDialog(odServera + ". Co odp: ");
out.println(komunikat);
odServera = in.readLine();
if(odServera.equals(""))
{
socket.close();
}
}
} catch (UnknownHostException e) {
System.out.println(e.getMessage());
System.exit(1);
} catch (IOException e) {
System.out.println("No I/O");
System.exit(1);
}
}
}
Kod Serwera:
public class Server {
public static void main(String[] args) {
new Sluchacz().start();
}
}
class Sluchacz extends Thread
{
public void run()
{
try{
ServerSocket server = new ServerSocket(2000); //utworzenie gniazda
System.out.println("Czekamy na połączenie...");
Socket client = server.accept();
System.out.println("Client został podłączony " + client.getInetAddress().getHostName());
new Wymiana(client).start();
new Sluchacz().start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
class Wymiana extends Thread
{
Socket client;
public Wymiana(Socket client)
{
this.client = client;
}
public void run(){
try{
PrintWriter out = new PrintWriter(client.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
while(true){
String echo = in.readLine();
out.println(echo);
}
}
catch (IOException e) {
e.printStackTrace();
}
}
}
Ogólnie dobrze, ale:
- dla klienta potrzebujesz wątku słuchającego w momencie, gdy chcesz otrzymywać dane od serwera asynchronicznie i bez zamrażania całej aplikacji
- w metodzie run() w Sluchacz daj
while(true) {
// kod
// przy obsłudze wyjątków daj break'a (potem można to poprawić, gdybyś chciał dodać opcję "zakończ nasłuchiwanie na nowych klientów")
}
zamiast tworzyć ciągle nowe wątki i nowe serwery (przy próbie utworzenia drugiego gniazda serwerowego chyba rzuca Ci wyjątkiem, że adres jest już zbindowany ?). Innymi słowy: jedna instancja klasy Słuchacz z pętlą while w run(), która obsługuje kolejne połączenia :)
- klasa Wymiana jest ok, dopoki nie oczekujesz asynchronicznych komunikatów od klienta (czyli takich, że w każdej chwili możesz od niego coś dostać i na to coś należy zareagować jakoś) - bo wtedy powinien być oddzielny wątek, który w kółko odczytuje komunikaty od danego klienta i przekazuje je "dalej" do obslugi
- kod wrzucaj w < code = java > ... < / code > ;)
Ok Wielkie dzięki działa mi poprawnie i nawet asynchronicznie mogę jednocześnie kilka aplikacji obsługiwać.