Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 使用RealTimeSocket丢失数据_Android_Google Play Services - Fatal编程技术网

Android 使用RealTimeSocket丢失数据

Android 使用RealTimeSocket丢失数据,android,google-play-services,Android,Google Play Services,我正在移植一个游戏,以使用支持多人游戏的Google Play游戏服务。我使用实时套接字而不是实时消息,因为游戏已经有套接字支持 要获取套接字,我调用GamesClient.getRealTimeSocketForParticipant,然后可以像使用普通套接字一样获取输入和输出流 我的问题是,如果设备在调用getRealTimeSocketForParticipant之前收到数据,我将无法读取此数据。例如: Device A calls getRealTimeSocketForParticip

我正在移植一个游戏,以使用支持多人游戏的Google Play游戏服务。我使用实时套接字而不是实时消息,因为游戏已经有套接字支持

要获取套接字,我调用GamesClient.getRealTimeSocketForParticipant,然后可以像使用普通套接字一样获取输入和输出流

我的问题是,如果设备在调用getRealTimeSocketForParticipant之前收到数据,我将无法读取此数据。例如:

Device A calls getRealTimeSocketForParticipant. Device A sends "Hello". Device B calls getRealTimeSocketForParticipant. Device B receives nothing. Device A sends "World". Device B receives "World". 设备A调用getRealTimeSocketForParticipant。 设备A发送“你好”。 设备B调用getRealTimeSocketForParticipant。 设备B没有收到任何信息。 设备A发送“世界”。 设备B接收“世界”。 我修改了一个示例项目(ButtonClicker),并在这里复制了这个问题。我已将代码修改为使用实时套接字,并将StartName方法修改为:

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);
    }
}
字符串mReceivedData=”“;
字节mNextByteToSend=0;
void startName(布尔多人游戏)
{
mMultiplayer=多人游戏;
updateScoreDisplay();
切换到屏幕(R.id.screen\u游戏);
findViewById(R.id.button\u click\u me).setVisibility(View.VISIBLE);
GamesClient=getGamesClient();
字符串myid=mactiveeRoom.getParticipantId(client.getCurrentPlayerId());
ArrayList ID=mactiveeRoom.getParticipantIds();
字符串remoteId=null;
对于(int i=0;i 0)
{
尝试
{
//休眠的设备将丢失第一个字节。
Log.d(标签“5秒后睡觉…”);
线程。睡眠(5*1000);
}
捕获(例外e)
{
}
}
其他的
{
Log.d(标记“无睡眠,立即获取套接字”);
}
尝试
{
final RealTimeSocket rts=client.getRealTimeSocketForParticipant(mRoomId,remoteId);
最终InputStream inStream=rts.getInputStream();
final OutputStream outStream=rts.getOutputStream();
最终文本视图文本视图=((文本视图)findViewById(R.id.score0));
//睡眠(5*1000);在这里睡觉可以最大限度地降低出现问题的风险。
最终处理程序h=新处理程序();
h、 postDelayed(新的Runnable()
{
@凌驾
公开募捐
{
尝试
{
int byteToRead=inStream.available();
对于(int i=0;i 0)
{
Log.d(标签,“接收数据:+mReceivedData”);
textView.setText(mReceivedData);
}
Log.d(标记“发送:”+mNextByteToSend);
扩展流。写入(mNextByteToSend);
mNextByteToSend++;
h、 邮递延迟(本次为1000);
}
捕获(例外e)
{
}
}
}, 1000);
}
捕获(例外e)
{
Log.e(标记“someerror:+e.getMessage(),e);
}
}
该代码确保两个设备中的一个在调用getRealTimeSocketForParticipant之前休眠5秒。对于不睡眠的设备,输出类似于:

No sleep, getting socket now. Sending: 0 Sending: 1 Sending: 2 Sending: 3 Sending: 4 Received data: 0 Sending: 5 Received data: 0 1 Sending: 6 Received data: 0 1 2 不要睡觉,现在就去拿插座。 发送:0 发送:1 发送:2 发送:3 发送:4 收到的数据:0 发送:5 收到的数据:0 1 发送:6 收到的数据:0 1 2 这是意料之中的,没有数据丢失。但对于另一个设备,我得到了以下信息:

Sleeping in 5 seconds... Received data: 4 Sending: 0 Received data: 4 5 Sending: 1 Received data: 4 5 6 Sending: 2 Received data: 4 5 6 7 Sending: 3 五秒钟后睡觉。。。 收到的数据:4 发送:0 收到的数据:4 5 发送:1 收到的数据:4 5 6 发送:2 收到的数据:45 6 7 发送:3
第一个字节丢失。有什么办法可以避免这种情况吗?

如果我正确理解了API,那么通过实时套接字交换的消息是错误的,因此您不能总是保证所有玩家都收到了您发送的所有消息。我找不到有关RealTimeSocket使用的网络协议的信息,但我怀疑它是UDP

如果真的是这样的话,恐怕除了自己实现某种功能之外,你几乎无能为力。选择一个设备(例如ID最低的设备)作为“同步器”,并让它与其他设备创建一个集合。每隔一秒钟发送一条消息(“SYN”),比如“你在哪里?x y z”(当然不是字面意思),直到其他人回答“我在这里!(y)”(“ACK”)。从集合中删除发送响应的设备,直到集合为空。此时,向每个人发送一个“游戏开始了!”并继续

请注意,这些消息中的任何一条都可能丢失:如果“ACK”丢失,下次发送“SYN”时,设备应再次应答。如果“游戏开始”的消息丢失了,不幸的是,设备会一直等待直到收到不同的消息,在这一点上,它应该考虑自己可以自由启动(尽管延迟)。
最后一点注意:即使底层协议是TCP,它仍然不是100%可靠的,没有协议是可靠的。如果您还不知道这个事实,请参阅以了解更多信息。

我有相同的表达式。然而,报告没有提到关于这个案例的任何具体内容,所以我希望我错过了一些东西:-)。我最初的实现是建立在TCP套接字上的,因此它假定数据不会丢失或以错误的顺序接收。然而,除了握手之外,它似乎在RealTimeSockets上工作得足够好,握手是一个恼人但可以解决的问题。@user1883479是的,在这种情况下,你不能有相同的假设。引用您链接的文档:“套接字是不可靠的消息传输,因此数据包可能到达目的地,也可能不到达目的地。但是,完整性是有保证的。也就是说,单个数据包可能会丢失,但数据包不会损坏或截断。数据包很少会无序到达。”