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 つのスレッドを使用できることを読みましたが、書き込み機能の使用 (実行中のスレッドで関数を呼び出す方法がわからない) とアクティビティでの関数の呼び出しに問題があります。
すべての助けに感謝します!
よろしく