2013-03-04 12 views
8

Mam aplikację na Androida, która musi umożliwiać łączenie wielu urządzeń. Jedno urządzenie powinno działać jako właściciel grupy i wydawać instrukcje wszystkim klientom, aby wykonywali określone czynności. Przypuszczam, że jest to porównywalne do bezprzewodowej gry przenośnej, w której jeden gracz jest hostem.Jak obsługiwać wielu klientów podłączonych do serwera za pomocą gniazd?

Mam kilka pytań, więc postaram się je skrócić. Pomogłaby nawet odpowiedź na pierwsze.

Po pierwsze, udało mi się sparować pojedynczy serwer i pojedynczy telefon klienta przy użyciu gniazd. Zrobiłem to za pomocą technologii Wi-Fi Direct Androida (Described here). Samouczek jest pomocny, ale niestety niezbyt dokładny, szczególnie w opisie połączeń jeden-do-wielu. Po znalezieniu listy peerów można otwierać połączenia gniazd. Udało mi się połączyć dwa urządzenia za pomocą nici do serwera (Using this example), tak jak poniżej:

public class ServerThread implements Runnable { 

     public void run() { 
      (Code...) 
      client = serverSocket.accept(); 
      (...other code here.) 
     } 
} 

Klient jest tworzony po naciśnięciu przycisku (myślę, wciąż próbuje dostać głowę wokół mojego zmodyfikowanego kodu) :

public class MusicClientThread implements Runnable { 
    Socket socket = new Socket(serverAddr, port); 
    while (connected) { 
      //(Other code here.) 
      while ((line = in.readLine()) != null) { 
      //While there are still messages coming 
      } 
    } 
    socket.close(); 
    //(Other code here too.) 
} 

Przypuszczam, że moje pierwsze pytanie brzmi: w jaki sposób mogę zezwolić na połączenie większej liczby klientów? Moje ServerThread odnosi się do pojedynczej zmiennej klienckiej powyżej, więc nie widzę, w jaki sposób pozwalałbym na zmianę liczby (moja aplikacja ma na celu od 2 do 10 użytkowników) ani nie znam prawidłowego sposobu rozróżniania wszystkich moich różnych klientów. Przypuszczam tylko, że użyłbym unikalnego adresu IP każdego telefonu.

Moje drugie pytanie brzmi: jak już ustanowię połączenie z wieloma klientami/równorzędnymi, w jaki sposób będę wtedy poprawnie wysyłać i odbierać instrukcje? Obecnie mój pojedynczy serwer czeka na instrukcję, a po jej otrzymaniu wydaje instrukcję odpowiedzi. Potrzebuję go, aby serwer mógł wysyłać instrukcje od początku za pomocą naciśnięć przycisków, a ich wynik jest widoczny na urządzeniach klienckich.

Mam nadzieję, że wszystko wyjaśniłem!

+1

Dla każdego nowego klienta, który żąda gniazda z serwera, nie wysyłaj nowego wątku z tym klientem przekazanym do niego.W ten sposób wszystkie dane przychodzące z inputStream tego klienta są wysyłane na serwer – christopher

+1

Musisz rozpocząć nowy wątek za każdym razem, gdy chcesz wykonać żądanie od klienta, nie ma znaczenia, czy już wysłałeś jedna prośba, kiedy wyślesz kolejną, rozpocznie się nowy wątek, który będzie działał symultanicznie. –

+0

Czy więc z perspektywy urządzeń należących do grupy, czy oznacza to, że wątki wielu serwerów działają na tym samym czasie? Jak będę manipulować każdą z nich? – Chucky

Odpowiedz

6

Musisz rozpocząć nowy wątek dla każdego klienta, ponieważ gniazda potrzebują wątku, aby mógł je uruchomić (ponieważ większość czasu czeka na wejście). Może to na przykład być wykonane (w tym sposób uproszczony):

public class ThreadHandler extends Thread { 
     private ArrayList<ServerThread> serverThreads = new ArrayList<ServerThread>(); 
     public void run() { 
      while (!isInterrupted()) { //You should handle interrupts in some way, so that the thread won't keep on forever if you exit the app. 
        (Code...) 
        ServerThread thread = new ServerThread(serverSocket.accept()); 
        serverThreads.add(thread); 
        thread.start(); 
      } 
     } 
     public void doSomethingOnAllThreads() { 
      for (ServerThread serverThread : serverThreads) { 
        serverThread.otherMethod(); 
      } 
     } 
} 

Jeżeli ServerThread wygląda mniej więcej tak:

public class ServerThread extends Thread { 
    private Socket socket; 
    public ServerThread(Socket socket) { 
      this.socket = socket; 
    } 
    public void run() { 
     (...other code here.) 
    } 
    public void otherMethod() { 
      //Signal to the thread that it needs to do something (which should then be handled in the run method) 
    } 
} 
+0

Obawiam się, że już mam ten kod w miejscu (to był kod, którego nie pokazałem = P). Potrzebuję czegoś, co pozwoli mi operować na tej liście wątków, które ludzie sugerują. – Chucky

+0

@Chucky sprawdź moją edycję - będziesz musiał upewnić się, że inne metody() i doSomethingOnAllThreads() są bezpieczne dla wątków, na przykład za pomocą blokad w odpowiednich lokalizacjach lub kolekcjach bezpiecznych dla wątków. – ddmps

+0

Bah, dostaję nagle wszystkie rodzaje metod łączenia połączeń. Myślę, że jest jakiś rodzaj gniazdka, który jest otwarty i nie mogę go zamknąć. – Chucky

2

mam TV Box Google. I mam dwa telefony komórkowe.

W GoogleTV Box prowadzę serwer. Serwer posiada jeden ServerSocket na porcie 6001. Również Server posiada dwa gniazda dla dwóch klientów

Pierwsze urządzenie łączy się z serwerem i korzystających numer gniazda jeden drugi drugi ....

mogę Jednoczesne przesyłanie różnych wiadomości z 2 urządzeń do gniazda Google TV Box i wyświetlanie ich w telewizji.

I stosując następujące rozwiązanie:

dla mobilnego klienta (2 urządzeń)

utworzyć nowy android projekt z pustym aktywności i skopiować ten kod do. utwórz układ dla klienta zawierający edittext i przycisk. UPEWNIJ SIĘ, ŻE USTAWIENIA SIECI I DOSTĘP DO INTERNETU W ANDROIDMANIFEST.XML !!! I edytuj adres serverIpAddress w tym pliku na dostępny serwer IP.

package de.android.googletv.gameclient; 

import java.io.BufferedWriter; 
import java.io.IOException; 
import java.io.OutputStreamWriter; 
import java.io.PrintWriter; 
import java.net.InetAddress; 
import java.net.Socket; 
import java.net.UnknownHostException; 
import java.util.Random; 

import android.app.Activity; 
import android.os.AsyncTask; 
import android.os.Bundle; 
import android.util.Log; 
import android.view.View; 
import android.view.View.OnClickListener; 
import android.widget.Button; 
import android.widget.EditText; 
import android.widget.TextView; 

/** 
* 
* 
* 
*/ 
public class FullscreenActivity extends Activity { 

    private Socket socket; 
    private String serverIpAddress = "192.168.22.253"; // GOOGLE TV IP 
    private static final int PLAYER_1_SERVERPORT = 6001; 

    private Button bt; 
    private TextView tv; 

    String DEVICE_NAME; 


    private class ConnectToServer extends AsyncTask { 

     @Override 
     protected Object doInBackground(Object... params) { 

       System.out.println("connecting to server..."); 

       try { 

        InetAddress serverAddr = InetAddress.getByName(serverIpAddress); 
        socket = new Socket(serverAddr, PLAYER_1_SERVERPORT); 

        } catch (UnknownHostException e1) { 
         System.out.println("ERROR REACHING SERVER! 1"); 
        e1.printStackTrace(); 
        } catch (IOException e1) { 
         System.out.println("ERROR REACHING SERVER! 2"); 
        e1.printStackTrace(); 
        } 

       System.out.println("Done!"); 

       return params; 
     } 

     protected void onPostExecute() { 

     } 

    } 


    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 

     setContentView(R.layout.activity_fullscreen); 

     DEVICE_NAME = android.os.Build.MODEL; 

     Button exit = (Button) findViewById(R.id.dummy_button); 
     exit.setOnClickListener(new OnClickListener() {   
      @Override 
      public void onClick(View v) { 
       System.exit(1);    
      } 
     }); 

     new ConnectToServer().execute(""); 

     tv = (TextView) findViewById(R.id.editText1); 

     bt = (Button) findViewById(R.id.button1); 
     bt.setOnClickListener(new OnClickListener() { 
      public void onClick(View v) { 
       try { 

        Random rnd = new Random();     

        EditText et = (EditText) findViewById(R.id.editText1); 
        String str = DEVICE_NAME + " ID" + rnd.nextInt() + " says: " + et.getText().toString(); 

        PrintWriter out = new PrintWriter(
          new BufferedWriter(
            new OutputStreamWriter(
              socket.getOutputStream())),true 
              ); 
        out.println(str); 

        Log.d("Client", "Client sent message"); 

       } 
       catch (UnknownHostException e) { 
        tv.setText("UnknownHostException"); 
        e.printStackTrace(); 
       } 
       catch (IOException e) { 
        tv.setText("IOException"); 
        e.printStackTrace(); 
       } 
       catch (Exception e) { 
        tv.setText("Exception"); 
        e.printStackTrace(); 
       } 
      } 
     }); 
    } 

} 

dla serwera (pole Google TV)

utworzyć nowy projekt z pustym android aktywności i skopiować ten kod do. utwórz układ z tylko polem tekstowym UPEWNIJ SIĘ, ŻE USTAWIENIA SIECI I DOSTĘP DO INTERNETU W ANDROIDMANIFEST.XML !!!

package de.android.googletv.gameserver; 

import java.io.IOException; 
import java.net.ServerSocket; 
import java.net.Socket; 

import android.app.Activity; 
import android.os.Bundle; 
import android.os.Handler; 
import android.os.Message; 
import android.view.View; 
import android.view.View.OnClickListener; 
import android.widget.Button; 
import android.widget.TextView; 

/** 
* 
* 
* 
*/ 
public class FullscreenActivity extends Activity { 


    // server socket 
    ServerSocket ss_plr1 = null; 
    public static final int SERVERPORT_1 = 6001; 

    int nr_connections = 0; 

    // socket for player1 
    Socket s1; 

    // socket for player2 
    Socket s2; 

    Thread myCommsThread = null; 

    protected static final int MSG_ID = 0x1337; 
    String mClientMsg = ""; 


    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 

     setContentView(R.layout.activity_fullscreen); 

     Button exit = (Button) findViewById(R.id.dummy_button); 
     exit.setOnClickListener(new OnClickListener() {   
      @Override 
      public void onClick(View v) { 
       System.exit(1);    
      } 
     }); 

     TextView tv = (TextView) findViewById(R.id.fullscreen_content); 
     tv.setText("Nothing from client yet"); 

     myCommsThread = new Thread(new CommsThread()); 
     myCommsThread.start(); 
    } 


    @Override 
    protected void onStop() { 
     super.onStop(); 
     try { 
      // make sure you close the socket upon exiting 
      ss_plr1.close();    
     } 
     catch (IOException e) {e.printStackTrace(); } 
    } 

    Handler myUpdateHandler = new Handler() { 
     public void handleMessage(Message msg) { 

      System.out.println("handleMessage("+msg+")"); 

      switch (msg.what) { 

      case MSG_ID: 
       TextView tv = (TextView) findViewById(R.id.fullscreen_content); 
       tv.setText((String)msg.obj); 
       break; 

      default: 
       break; 

      } 
      super.handleMessage(msg); 
     } 
    }; 

    class CommsThread implements Runnable { 

     public void run() { 

      System.out.println("creating new sockets..."); 

      try { 

       ss_plr1 = new ServerSocket(SERVERPORT_1); 

       if (s1 == null) 
        s1 = ss_plr1.accept(); 

       if (s2 == null) 
        s2 = ss_plr1.accept(); 

      } 
      catch (IOException e) {e.printStackTrace();} 

      new Thread(new ConnectionHandler(s1, myUpdateHandler)).start(); 
      new Thread(new ConnectionHandler(s2, myUpdateHandler)).start(); 

     } 

    } 


} 

... i wymagane przez serwer jest do obsługi połączeń gwintowanych wiadomości ...

utworzyć dodatkowe klasy w Project Server o nazwie: „ConnectionHandler.java” i skopiować ten kod do . obsługuje połączenia asynchroniczne.

package de.android.googletv.gameserver; 

import java.io.BufferedReader; 
import java.io.IOException; 
import java.io.InputStreamReader; 
import java.net.Socket; 

import android.os.Handler; 
import android.os.Message; 

public class ConnectionHandler implements Runnable { 

    Socket m_socket; 
    Handler m_updateHandler; 

    public ConnectionHandler(Socket socket, Handler updateHandler) { 
     m_socket = socket; 
     m_updateHandler = updateHandler; 
    } 

    @Override 
    public void run() { 

     while (!Thread.currentThread().isInterrupted()) { 

      try { 

       BufferedReader input = new BufferedReader(new InputStreamReader(m_socket.getInputStream())); 

       String st = null; 
       st = input.readLine(); 

       Message m = new Message(); 
       m.what = 0x1337; 
       m.obj = st; 
       m_updateHandler.sendMessage(m); 

      } 
      catch (IOException e) { e.printStackTrace();} 

     } 

    } 

} 

To nie jest najmilsze rozwiązanie. Wiele "nieładnych" kodowań. Na przykład System.exit (1). A obsługuje tylko dwa urządzenia. Ale działa na więcej niż jednym urządzeniu i jestem pewien, że zmodyfikujesz go dla swoich celów. Jest oparty na trzech źródłach internetowych i dodatkowych próbach od samego siebie, aby to zadziałało. Jej tylko mój prototyp ....

NIE MOGĘ linki do nich :(... do mniejszej renomie

Jeśli zbudować i uruchomić everthing powinno to wyglądać tak:.

https://plus.google.com/u/0/109268217221135029753/posts/3iz6SF1hiJa

Powiązane problemy