1

Androidアプリ(サーバーとして)とWindows上で実行されているJavaベースのクライアントとの間にtcpソケット接続を実装しようとしています。(以下の短いバージョン、コードなし)

いくつかのセンサー リスナーを使用してゲームの動きを実装しています (レーシング ゲームのこのセンサー ベースの動きは誰もが知っています。

その目的のために、最初のアクティビティから開始されるサービスを実装しました。このサービスは次のように実装されています (クラス全体ではなく、関連するコード スニペットを貼り付けるだけです)。

public class ServerService extends Service {

    ConnectionHandler conHandler;

    @Override
    public void onCreate() {
        startListener();
    }

    private void startListener() {
        conHandler = new ConnectionHandler(this);
        conHandler.execute();
    }

    private void sendMessage(String s)
    {
        conHandler.write(s);
    }

    public void messageNotify(String s) {
        //Log.d("receivedMessage", s);
    }    
}

ConnectionHandler クラス:

public class ConnectionHandler extends AsyncTask<Void, Void, Void>{

    public static int serverport = 11111;
    ServerSocket s;
    Socket c;
    ConnectionListening conListening;
    ConnectionWriting conWriting;
    DataOutputStream dos;
    DataInputStream dis;
    ServerService server;

    public ConnectionHandler(ServerService server)
    {
        this.server = server;
    }

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

        try {
            Log.i("AsyncTank", "doInBackgoung: Creating Socket");
            s = new ServerSocket(serverport);
        } catch (Exception e) {
            Log.i("AsyncTank", "doInBackgoung: Cannot create Socket");
        }
        try {
                    //this is blocking until client connects
            c = s.accept();
            Log.d("ConnectionHandler", "client connected");
            dis = new DataInputStream(c.getInputStream());
            dos = new DataOutputStream(c.getOutputStream());
        } catch (IOException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
            conWriting = new ConnectionWriting(this.c, this.dos);
            conWriting.execute();
            conListening = new ConnectionListening(this.c, this.dis, this.server);
            if(this.c != null)
            {
                Timer timer = new Timer();
                timer.schedule(conListening, 0, 10);
            }

            Log.i("AsyncTank", "doInBackgoung: Socket created, Streams assigned");
        return null;
    }

    public void write(String s)
    {
        conWriting.writeToStream(s);
    }

    public void messageNotify(String s) {
        // TODO method stub 
    }   

}

ConnectionHandler は ConnectionWriting と同様に AsyncTask として実装されているため、tcp メソッドのブロックは通信全体に影響しません。クライアントはサーバーにメッセージを送信できます。このメッセージがいつ到着するかわからないため、10 ミリ秒ごとに実行される TimerTask を使用して、新しいメッセージがあるかどうかを確認します。

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

public class ConnectionWriting extends AsyncTask<Context, Void, Boolean>{

    public DataOutputStream dos;
    Socket c;

    public ConnectionWriting(Socket c, DataOutputStream dos) {
        this.dos = dos;
        this.c = c;
    }

    @Override
    protected Boolean doInBackground(Context... params) {
        return true;
    }   

    public void writeToStream(String s) {
        try {
            if (c != null){
                //Log.i("AsynkTask", "writeToStream");
                dos.writeBytes(s+"\n");
                dos.flush();
                Log.i("AsynkTask", "write: " +s);
            } else {
                Log.i("AsynkTask", "writeToStream : Cannot write to stream, Socket is closed");
            }
        } catch (Exception e) {
            Log.i("AsynkTask", "writeToStream : Writing failed");
        }
    }

}

そして ConnectionListening クラス: public class ConnectionListening extends TimerTask{

    public DataInputStream dis;
    Socket c;
    ServerService server;

    public ConnectionListening(Socket c, DataInputStream dis, ServerService server)
    {
        this.c = c;
        this.dis = dis;
        this.server = server;
    }

    @Override
    public void run() {
        String message = "";
        try {
            if (c != null) {
                //Log.i("AsynkTask", "readFromStream : Reading message");
                message = dis.readLine();
                Log.i("AsynkTask", "read: " + message);
            } else {
                Log.i("AsynkTask", "readFromStream : Cannot Read, Socket is closed");
            }
        } catch (Exception e) { 
            Log.i("AsynkTask", "readFromStream : Writing failed");
        }

        if(message != null)
        {
            this.server.messageNotify(message);
        }

    }


}

私がこの複雑な非同期の方法を選択したのは、サーバーがほぼ連続してクライアントにデータを送信しており、クライアントがデータを送り返さなければならない状況があるためです。tcp ソケットを使用する従来の方法では、非ブロッキング通信を実現することはできません。つまり、サーバーが送信 (書き込み) している場合、読み取り機能がブロックされ、クライアント メッセージを受信することはありません。

簡潔にするために: 私は私のアプローチをテストしましたが、サーバーは常に最初にデータを送信し、次にクライアント メッセージを取得しています。非同期じゃない!? :-/

たぶん、誰でもこの問題を解決するのを手伝ってくれるでしょう。または、そのアプローチを実装するより簡単な方法はありますか? 通信は非同期である必要があります。そして、読み取りは自動的に行われる必要があります(このポーリングアプローチで実装しようとしたもの)。

読み取り用に 1 つのスレッドを使用し、書き込み用に 1 つのスレッドを使用できることを読みましたが、書き込み機能の使用 (実行中のスレッドで関数を呼び出す方法がわからない) とアクティビティでの関数の呼び出しに問題があります。

すべての助けに感謝します!

よろしく

4

0 に答える 0