7

複数のデバイスを接続できるようにする必要があるAndroidアプリがあります。1つのデバイスがグループの所有者として機能し、すべてのクライアントに特定のことを行うように指示を出す必要があります。1人のプレイヤーがホストであるワイヤレスハンドヘルドゲームに匹敵すると思います。

いくつか質問があるので、簡潔に保つようにします。最初の答えだけでも役に立ちます。

まず、ソケットを使用して単一のサーバーと単一のクライアント電話を正常にペアリングしました。これは、AndroidのWi-Fi Directテクノロジー(ここで説明)を使用して行いました。チュートリアルは役に立ちますが、残念ながら、特に1対多の接続を説明する場合はあまり徹底的ではありません。ピアリストが見つかると、ソケット接続を開くことができます。次のように、サーバーのスレッドを使用して(この例を使用して)、 2つのデバイスを接続できました。

public class ServerThread implements Runnable {

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

ボタンを押すと、クライアントが作成されます(まだ、変更したコードに頭を悩ませようとしています)。

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番目の質問は、複数のクライアント/ピアとの接続を確立したら、どのようにしてそれらに正しく指示を送受信するのかということです。現在、私の単一サーバーは命令を待機しており、それを受信すると、応答命令を発行します。サーバーがボタンを押すことで最初から命令を送信できるようにするために必要です。これらの結果はクライアントデバイスに表示されます。

私はすべてを明確にしたことを願っています!

4

2 に答える 2

7

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

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

ServerThreadは次のようになります。

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)
    }
}
于 2013-03-04T19:57:01.677 に答える
2

GoogleTVボックスを持っています。そして私は2台の携帯電話を持っています。

GoogleTVBoxでサーバーを実行しています。サーバーには、ポート6001に1つのServerSocketがあります。また、サーバーには、2つのクライアント用に2つのソケットがあります。

最初のデバイスはサーバーに接続し、ソケット番号を1つ2つ使用します。

2台のデバイスからGoogleTVボックスソケットに異なるメッセージを同時に投稿して、テレビに表示することができます。

私は次の解決策を使用しています:

モバイルクライアント向け(2デバイス)

空白のアクティビティを含む新しいAndroidプロジェクトを作成し、このコードをにコピーします。エディットテキストとボタンを含むクライアントのレイアウトを作成します。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ソースと、それを機能させるための私自身の追加の試みに基づいています。その唯一の私のプロトタイプ....

私はそれらにリンクすることはできません:(...評判を下げるために。

すべてをビルドして実行すると、次のようになります。

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

于 2013-04-05T15:40:11.307 に答える