マルチプレイヤー対応の Google Play ゲーム サービスを使用するためにゲームを移植しています。ゲームはすでにソケットをサポートしているため、リアルタイム メッセージの代わりに RealTimeSocket を使用しています。
ソケットを取得するには、GamesClient.getRealTimeSocketForParticipant を呼び出します。その後、通常のソケットとして使用する入力ストリームと出力ストリームを取得できます。
私の問題は、getRealTimeSocketForParticipant を呼び出す前にデバイスがデータを受信すると、このデータを読み取れないことです。例えば:
デバイス A が getRealTimeSocketForParticipant を呼び出します。 デバイス A が「Hello」を送信します。 デバイス B が getRealTimeSocketForParticipant を呼び出します。 デバイス B は何も受信しません。 デバイス A は「World」を送信します。 デバイス B は「World」を受信します。
サンプル プロジェクト (ButtonClicker) の 1 つを変更し、ここで問題を再現しました。リアルタイム ソケットを使用するようにコードを変更し、startGame メソッドを次のように変更しました。
String mReceivedData = "";
byte mNextByteToSend = 0;
void startGame(boolean multiplayer)
{
mMultiplayer = multiplayer;
updateScoreDisplay();
switchToScreen(R.id.screen_game);
findViewById(R.id.button_click_me).setVisibility(View.VISIBLE);
GamesClient client = getGamesClient();
String myid = mActiveRoom.getParticipantId(client.getCurrentPlayerId());
ArrayList<String> ids = mActiveRoom.getParticipantIds();
String remoteId = null;
for(int i=0; i<ids.size(); i++)
{
String test = ids.get(i);
if( !test.equals(myid) )
{
remoteId = test;
break;
}
}
//One of devices should sleep in 5 seconds before start
if( myid.compareTo(remoteId) > 0 )
{
try
{
//The device that sleeps will loose the first bytes.
Log.d(TAG, "Sleeping in 5 seconds...");
Thread.sleep(5*1000);
}
catch(Exception e)
{
}
}
else
{
Log.d(TAG, "No sleep, getting socket now.");
}
try
{
final RealTimeSocket rts = client.getRealTimeSocketForParticipant(mRoomId, remoteId);
final InputStream inStream = rts.getInputStream();
final OutputStream outStream = rts.getOutputStream();
final TextView textView =((TextView) findViewById(R.id.score0));
//Thread.sleep(5*1000); Having a sleep here instead minimizes the risk to get the problem.
final Handler h = new Handler();
h.postDelayed(new Runnable()
{
@Override
public void run()
{
try
{
int byteToRead = inStream.available();
for(int i=0; i<byteToRead; i++)
{
mReceivedData += " " + inStream.read();
}
if( byteToRead > 0 )
{
Log.d(TAG, "Received data: " + mReceivedData);
textView.setText(mReceivedData);
}
Log.d(TAG, "Sending: " + mNextByteToSend);
outStream.write(mNextByteToSend);
mNextByteToSend++;
h.postDelayed(this, 1000);
}
catch(Exception e)
{
}
}
}, 1000);
}
catch(Exception e)
{
Log.e(TAG, "Some error: " + e.getMessage(), e);
}
}
このコードは、getRealTimeSocketForParticipant への呼び出しの 5 秒前に、2 つのデバイスのいずれかが確実にスリープするようにします。スリープしないデバイスの場合、出力は次のようになります。
スリープなし、ソケットを取得中。 送信: 0 送信: 1 送信: 2 送信: 3 送信: 4 受信データ: 0 送信: 5 受信データ: 0 1 送信: 6 受信データ: 0 1 2
これは予想どおりで、データが失われることはありません。しかし、他のデバイスの場合、次のようになります。
5秒で眠る… 受信データ: 4 送信: 0 受信データ: 4 5 送信: 1 受信データ: 4 5 6 送信: 2 受信データ: 4 5 6 7 送信: 3
最初のバイトは失われます。とにかくこれを回避する方法はありますか?