Jak przeskoczyć do innego wątku

0

Dzień dobry!

Mam problem z wątkami w Javie, dokładniej to mam program Client-Server i potrzebuje zrobić coś w tym stylu:

Jeśli klient podłączony jako drugi (i = 2) wyśle wiadomość do serwera,
to serwer wysyła klientowi podłączonemu jako pierwszy (i = 1) jakąś wiadomość.

Wielka prośba aby ktoś mi pomógł i nakierował mnie na jakieś rozwiązanie.
Siedzę już nad tym sporo czasu i nie mogę wymyślić rozwiązania.

Kod programów:

Server:

import java.io.*;
import java.net.*;
import java.util.*;

class WatekGracza extends Thread
{
    int numerGracza;
    Socket socket;

    WatekGracza(Socket socket, int nr)
    {
        this.socket = socket;
        numerGracza = nr;
    }

    public void run()
    {
        try {
            PrintWriter out = new PrintWriter(
                        new OutputStreamWriter(
                    socket.getOutputStream()),true);


            BufferedReader in = new BufferedReader(
                                new InputStreamReader(
                                    socket.getInputStream()));

            int liczbaKlienta;

            String komunikat, odpowiedz="";
            while(true)
            {
                komunikat = in.readLine();
                System.out.println("Klient strzelił w:" + komunikat);
                liczbaKlienta = Integer.parseInt(komunikat);
                if(Server.ktosZgadl != -1)
                {
                    odpowiedz = "Przegrales, szybszy byl gracz numer " + Server.ktosZgadl;
                }
                else if(Server.liczba > liczbaKlienta) odpowiedz = "Za mało";
                else if(Server.liczba < liczbaKlienta) odpowiedz = "Za dużo";
                else if(Server.liczba == liczbaKlienta)
                {
                    odpowiedz = "Zgadłeś";
                    Server.ktosZgadl = numerGracza;
                }
                out.println(odpowiedz);
            }//koniec pętli while(true)
        } catch(Exception e) { System.out.println(e);}
    }//koniec funkcji uruchom()
}


public class Server
{
    public static int ktosZgadl = -1;
    public static int liczba;
    public static final int serverPort = 2020;
    private int i;
    ServerSocket s;
    /* Konstruktor próbuje utworzyć gniazdo */
    Server()
    {
        try{
            s = new ServerSocket(serverPort);
            System.out.println("Serwer dziala");
        }catch(Exception e) {
            System.out.println("Nie można utworzyć gniazda");
            System.exit(1);
        }
    }
    
    void uruchom() throws Exception
    {
        Random los = new Random();
        liczba = los.nextInt(101);
        while(true)
        {
            Socket socket = s.accept();
            WatekGracza gracz = new WatekGracza(socket, ++i);
            gracz.start();
        }

    }//koniec funkcji uruchom()


    public static void main(String args[]) throws Exception
    {
        Server server = new Server();
        server.uruchom();
        server.s.close();
    }
}

Client:


import java.io.*;
import java.net.*;
import java.util.*;

public class Client
{
    private Socket socket;

    /* Konstruktor próbuje połączyć się z serwerem */
    Client()
    {
        try {
            socket = new Socket("localhost", 2020);
            System.out.println("Klient dziala");
        }
        catch(IOException e) {
            System.out.println("Uruchom serwer");
            System.exit(1);
        }
     }

     void uruchom() throws Exception
     {
        PrintWriter out = new PrintWriter(
                            new OutputStreamWriter(
                                socket.getOutputStream()),true);
        
        BufferedReader in = new BufferedReader(
                            new InputStreamReader(
                                socket.getInputStream()));
        
        Scanner czytacz = new Scanner(System.in);

        /* 2. Działanie klienta */
        String liczba, odSerwera;
        while(true) {
            System.out.println("Podaj zgadywaną liczbę: ");
            liczba = czytacz.nextLine();
            out.println(liczba);
            
            odSerwera = in.readLine();
            System.out.println(odSerwera);
            if(odSerwera.equals("Zgadłeś") 
            || odSerwera.startsWith("Przegrales"))
                break;
        }
        /* 3. Czynności po zakończeniu współpracy z serwerem */
        socket.close();
     }//koniec funkcji uruchom()

     public static void main(String args[]) throws Exception
     {
        Client client = new Client();
        client.uruchom();
     }
}

Pozdrawiam!

1

Robiłem coś podobnego i zrobiłem tak:

Podczas podłączenia przypisywałem klientowi id według kolejności (klient uzyskiwał tą informacje od razu po połączeniu) po czym każdy wysłany pakiet indeksował klient podczas wysyłania do serwera, serwer oddzielał indeks od pozostałej informacji, potem wysyłał do pozostałych klientów (oprócz do tego który nadał tą wiadomość).

1

Jak wyżej, musisz na serwerze zwyczajnie pamiętać który wątek/który socket służy do komunikacji z danym klientem.

0

Czyli tak jak moim przykładzie, muszę zrobić tablice graczy a później tworzyć na niej nowy socket?

Tak to ma wyglądać? Bo nie za bardzo chce działać.

Socket socket = s.accept();
WatekGracza gracz[i] = new WatekGracza(socket, ++i);
gracz[i].start();
1

o_O

Map<Integer, WatekGracza> gracze = new HashMap<>();
//
WatekGracza gracz = new WatekGracza(socket, i);
gracze.put(i, gracz);
gracz.start();
i++;

I potem mozesz zrobić

WatekGracza graczNumerX = gracze.get(X);
0

Dziękuje za pomoc, a jeśli bym chciał wysłać wiadomość do gracza który otrzymał id 1.

graczNumerX.out.println("Wiadomosc do Gracza 2");
1

Jaja sobie robisz teraz? o_O Musisz w tej swojej klasie WatekGracza zaimplementować metodę która wysyła wiadomość za pomocą socketu...

0

No ok, to nie problem, ale jak rozróżnić do którego socketu wysyłam wiadomość?

1

Nie rozumiem pytania. Przecież każdy WatekGracza ma JEDEN socket. Nic tam nie ma do rozróżniania. Każdy WatekGracza potrafi rozmawiać tylko z jednym, swoim graczem. Gdzie ty widzisz jakiś problem? o_O

0

Powiedzmy, że mam taką sytuacje.
Jeśli serwer otrzyma wiadomość od gracza id:1 wtedy przesyła ją do gracza numer id:2.
Potrzebuje w socketcie gracza id:1 wysłać coś do socketu gracza id:2.
Jest to możliwe?

1

Piszesz aplikacje wielowątkową z komunikacją sieciową w javie nie umiejąc przy tym programować w Javie? Jak to jest w ogóle możliwe? o_O

  1. WatekKlienta 1 odbiera wiadomość.
  2. Przesyła ją do obiektu Serwera (więc wątek musi mieć referencje do serwera!) za pomocą jakiejś metody.
  3. Serwer wyciąga sobie z mapy WatekKlienta 2 i przekazuje mu wiadomość do przesłania
  4. WatekKlienta 2 ma metodę która za pomocą jego socketu przesyła wiadomość do odpowiedniego klienta.

Gdzie tu jest problem?

0

no tylko jak ma wyglądać metoda z punktu 4?
Tylko to mi jest potrzebne.

Co do Javy, cały czas uczę się.

1

To teraz mi powiedz skąd wziąłeś ten kod u góry, bo sam go nie napisałeś...

class WatekGracza extends Thread
{
    private final int numerGracza;
    private final Socket socket;
    private final PrintWriter out;
    private final BufferedReader in;
 
    WatekGracza(Socket socket, int nr)
    {
        this.socket = socket;
        numerGracza = nr;
        out = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()),true);
        in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    }

    public void msgClient(String message){
        out.println(message);
    }
 
    public void run()
    {
        try { 
            int liczbaKlienta;
 
            String komunikat, odpowiedz="";
            while(true)
            {
                komunikat = in.readLine();
                System.out.println("Klient strzelił w:" + komunikat);
                liczbaKlienta = Integer.parseInt(komunikat);
                if(Server.ktosZgadl != -1)
                {
                    odpowiedz = "Przegrales, szybszy byl gracz numer " + Server.ktosZgadl;
                }
                else if(Server.liczba > liczbaKlienta) odpowiedz = "Za mało";
                else if(Server.liczba < liczbaKlienta) odpowiedz = "Za dużo";
                else if(Server.liczba == liczbaKlienta)
                {
                    odpowiedz = "Zgadłeś";
                    Server.ktosZgadl = numerGracza;
                }
                msgClient(odpowiedz);
            }
        } catch(Exception e) { e.printStackTrace();}
    }
}
0

Kod bazowy miałem z książki, resztę sam dopisałem.
Ten kod w działaniu, nie różni się od mojego. Przynajmniej ja tak to widzę.

Obecnie wygląda to tak:
-Mamy do serwera połączonych dwóch graczy.
-Pierwszy gracz wysyła do serwera jakąś liczbę, powiedzmy 5.
-Serwer sprawdza warunki. Okazuje się, że spełnia się warunek serwera: "Server.liczba == liczbaKlienta"
-Serwer wysyła przez funkcję: "msgClient(odpowiedz);" wiadomość do gracza pierwszego: "Zgadłeś".

Ja chciałbym aby wyglądało to tak, żeby w ostatnim punkcie serwer wysłał wiadomość "Zgadłeś" do gracza numer dwa.

Mam już identyfikacje graczy, licznik (private int i), ale chciałbym by podczas wykonywania kodu pierwszego gracza, została wysłana wiadomość do gracza drugiego.

Strasznie mało przykładów z socketami w internecie.

1

Och no ale POMYŚL przez chwilę! Bo póki co to próbujesz "na pałe" coś zrobić... Twój problem nie jest z socketami tylko z brakiem myślenia.

  1. Zrób w klasie Serwer METODĘ "wygrał()" którą wątek klienta wywoła na serwerze kiedy ktoś zgadnie
  2. W tej oto metodzie niech serwer przeiteruje po wszystkich klientach i wyśle im, za pomocą "msg()" które pokazałem u góry, wiadomość jaką tam sobie chcesz.
0

Ok w klasie serwer jest metoda która iteruje wszystkich klientów:

    void wygrał()
    {
        for (int is=0; is<i; is++)
        {
            msgClient("Graczu "+is+", niestety wygrał ktoś inny");
        }
    }

Wywołuje ją gdy ktoś wygrał, tylko, ze ta wiadomość zostanie wysłana (jeśli graczy będzie dwóch) dwa razy do gracza który uruchomi metodę.
A nie do dwóch graczy.

1

Ja tu wcale nie widzę iterowania po klientach. Ja tu widzę jakieś iterowanie po liczbach z d**y. No i ciekawi mnie jak ty z serwera wołasz w ten sposób metodę msgClient skoro ona jest w WątkuKlienta. Ja proponuje jednak faktycznie iterować po klientach, np. za pomocą Map które pokazałem wyżej, a potem na każdym kliencie wywołać msgClient które za ciebie napisałem...

0

Coś w tym stylu:

Iterator<Integer, WatekGracza> keySetIterator = gracze.keySet().iterator();

while(keySetIterator.hasNext()){
  Integer key = keySetIterator.next();
  kay.msgClient("wygral ktos inny");
}

Poza tym, dziękuje, że masz do mnie taką cierpliwość. Naprawdę to doceniam to, że mi odpisujesz i pomagasz.
Dziękuje

1

Ty piszesz w javie 1.2 jakiejś?

for(WatekGracza wg: gracze.keySet()){
    wg.msgClient("wygral ktos inny");
}
0

przy pętli for otrzymuje taki błąd:
incompatible types: Integer cannot be converted to WatekGracza

2

@MaciekPaluch no to teraz tylko siąść i płakać! Bo po co zerknąć do dokumentacji albo pomyśleć? Kluczami są Integery a wartościami są Wątki. Więc nie keySet() tylko values() oczywiście...

0

Podsumowywując

Klasa Server:

Map<Integer, WatekGracza> gracze = new HashMap<>();

Metoda wygral:

void wygral(){
for(WatekGracza wg: gracze.values()){
wg.msgClient("wygral ktos inny");
}}

W metodzie uruchom:

while(true){
Socket socket = s.accept();
WatekGracza gracz = new WatekGracza(socket, i);
gracze.put(i, gracz);
gracz.start();
i++;}

Klasa WatekGracza:
Metoda msgClient:

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

Nie pomieszałem niczego?

1

Jeśli działa to pewnie nie ;]

0

jeśli chce wywołać metodę wygrał w klasie WatekGracza, to muszę ją przekazać przez konstruktor, tak?

1

Metodę? o_O Niby się da, ale ja bym jednak przekazał referencje do Serwera ;]

0
Server.wygral();

tak nie mogę bo *wygral() *nie jest statyczna,
więc jak inaczej?

0

Przekaz do wątku referencje do serwera!

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