2013-03-04 3 views
8

複数の端末を接続できるAndroidアプリがあります。 1つのデバイスがグループの所有者として行動し、すべてのクライアントに特定のことを実行するよう指示を出します。私はそれが1人のプレーヤーがホストである無線ハンドヘルドゲームに匹敵すると思います。ソケットを使用してサーバーに接続された複数のクライアントを処理するにはどうすればよいですか?

私はいくつか質問がありますので、私はそれらを簡潔に保つように努めます。ちょうど最初のものへの答えでさえ助けになるでしょう。

まず、ソケットを使用して単一のサーバーと単一のクライアント電話機をペア設定しました。私はAndroidのWi-Fi Directテクノロジー(Described here)を使ってこれを行った。このチュートリアルは役に立ちますが、残念ながら非常に徹底的ではありません。特に、1対多の接続を記述する場合にはそうです。ピアリストが見つかると、ソケット接続を開くことができます。ボタンを押します(私はまだ私の修正コードのまわりで私の頭を取得しようと、思う)以下

public class ServerThread implements Runnable { 

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

クライアントが作成されます。私はそうのように、サーバー(Using this example)のためのスレッドを使用して2つのデバイスを接続することができました:

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.) 
} 

私の最初の質問は、次のようなものです:どうすればより多くのクライアントを接続できますか?私のServerThreadは上記の単一のクライアント変数を参照していますので、さまざまな数を許可する方法はわかりません(私のアプリケーションは2人から10人のユーザーを対象にしています)、私の異なるクライアント間を区別する正しい方法を知っていません。私の唯一の推測は、私は各電話の一意のIPアドレスを使用するということです。

私の2番目の質問は、複数のクライアント/ピアとの接続が確立されたら、どのようにしてそれらに正しく指示を送信して受信するのですか?現在、私の単一のサーバは命令を待っており、それを受信すると応答命令を発行します。私はそれが必要なので、サーバーはボタンのプレスを使用して最初から指示を送ることができ、これらの結果はクライアントデバイス上で見ることができます。

私はすべてをクリアにしたいと思っています!

+1

serversocketからソケットを要求する新しいクライアントごとに、そのクライアントが渡された新しいスレッドをディスパッチして、そのクライアントのinputStreamから入ってくるデータがサーバに送られてくるのはなぜですか? – christopher

+1

新しいスレッドを開始する必要がありますクライアントからのリクエストを実行するたびに、既に送信しているかどうかは関係ありません1つのリクエストで、別のリクエストを送信すると、新しいスレッドが開始され、それらは同じように動作します。 –

+0

groupownerデバイスの観点からは、一度に複数のサーバスレッドが実行されているのでしょうか?どのように私はそれぞれを操作するだろうか? – Chucky

答えて

6

ソケットはスレッドを実行する必要があるため(ほとんどの場合、入力を待機するため)、クライアントごとに新しいスレッドを開始する必要があります。これは、例えば、(この簡略化して)行うこと:

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

私はすでにこのコードを用意しているのですが(私が表示していなかったコード= Pだった)私が必要とするのは、人々が示唆しているように見えるスレッドのリストで動作することを可能にするものです。 – Chucky

+0

@Chuckyは私の編集をチェックします。たとえば、適切な場所やスレッドセーフなコレクションのロックを使うなど、otherMethod()とdoSomethingOnAllThreads()がスレッドセーフであることを確認する必要があります。 – ddmps

+0

バー、私は接続障害のすべての種類の方法を突然取得しています。私はいくつかの種類のソケットが開いていると思うが、どこかでそれを閉じることができないようだ。 – Chucky

2

私はGoogle TVの箱を持っている:ServerThreadは次のようになります

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

。私は2つの携帯電話を持っています。

GoogleTVボックスでは、サーバーを実行します。 サーバーは私ができる

....サーバーは、2つのクライアント

ための2つのソケットを有する第一の装置がサーバに接続し、ソケット番号1 第2他を使用しても、ポート6001 上の一件のServerSocketを有します2台のデバイスからGoogle TVボックスソケットまでの同時投稿のメッセージを投稿し、テレビに表示します。空白の活性を有する新しいAndroidプロジェクトを作成し、にこのコードをコピーして、モバイル・クライアントに

(2つのデバイス)

:私は以下のソリューションを使用して

。 編集テキストとボタンを含むクライアントのレイアウトを作成します。 ANDROIDMANIFEST.XMLでインターネットとアクセスネットワークの許可を設定してください! このファイルのserverIpAddressを、サーバーがアクセス可能な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(); 
       } 
      } 
     }); 
    } 

} 
サーバー用

(グーグルTVボックス)

空白の活性を持つ新しいAndroidプロジェクトを作成し、にこのコードをコピーします。 テキストフィールドのみのレイアウトを作成する 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(); 

     } 

    } 


} 

...とサーバが必要

と呼ばれるサーバープロジェクトに追加するクラスを作成します...ねじ切りメッセージング用の接続ハンドラである:「ConnectionHandler.java」とにこのコードをコピー。非同期接続を処理します。

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

     } 

    } 

} 

これは最適な解決策ではありません。複数の「うまくいかない」コーディング。例えば、System.exit(1)。また、2つのデバイスしかサポートしていません。しかし、それは複数のデバイスで動作し、あなたの目的のためにそれを変更することを確信しています。それは3つのWebソースに基づいて、それを動作させるために自分自身からの追加のattemps。その唯一の私のプロトタイプ....

私は:(彼らにリンクすることはできません...あまり評判に

をあなたが構築し、everthingを実行した場合、それは次のようになります。

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

関連する問題