GKSession 不会在第二个连接上向对等方发送数据
我有一款运行良好的点对点 iPhone 游戏。我创建了一个表格来显示可用的对等点,并且我可以连接(到目前为止)最多四个设备并从头到尾玩一整轮游戏:
但这是我的问题...
我在一台设备上使用 GKSessionModeClient
创建一个 GKSession
,在另一台设备上使用 GKSessionModeServer
创建。客户端看到服务器,选择连接它,然后服务器批准。当所有对等点连接时,服务器可以点击“开始游戏”。
如果——在服务器开始游戏之前——客户端点击“后退”按钮转到上一个屏幕,自定义对等选择器显示将从视图中弹出,并且会话被“销毁”……
[_gkSession disconnectFromAllPeers];
[_gkSession setAvailable:NO];
[_gkSession setDelegate:nil];
[_gkSession setDataReceiveHandler:nil withContext:nil];
现在,如果客户端返回到对等选择器并再次加入服务器,我再次获得 GKSessionStateConnected 状态,但是当我发送数据到AllPeers:时没有任何内容到达客户端。如果一台设备开始游戏并且三台设备加入,然后服务器点击“开始游戏”,它就可以完美地工作。但如果有人在游戏开始前退出,则重新创建会话并加入将失败。
有什么想法吗?我目前能想到的唯一黑客方法是阻止用户在连接到服务器后点击“后退”,但这很糟糕……如果他们改变主意,他们就必须完全退出应用程序。我对此一筹莫展,因为该应用程序正在运行,而且我喜欢它,除了这个连接问题。这是一种边缘情况,但我可以看到,如果用户在不重新启动应用程序以清除会话的情况下无法开始游戏,他们会感到恼火。
当我可以的时候,我会将其作为赏金。请帮忙!
编辑@byteclub
- 如果满足以下条件,服务器是否正确清理所有相关数据结构: 客户在游戏开始前离开?
如果客户端在服务器接受其连接后离开游戏大厅,则客户端的会话将被破坏:
- (void)destroySession
{
trace(@"destroySession");
self.gameDelegate = nil;
self.lobbyDelegate = nil;
[_gkSession disconnectFromAllPeers];
[_gkSession setAvailable:NO];
[_gkSession setDelegate:nil];
[_gkSession setDataReceiveHandler:nil withContext:nil];
[_peerList removeAllObjects];
}
不过,我不会在服务器设备上调用任何disconnectFromPeers方法。
* 对于以下情况,客户端断开连接清理过程是否有所不同:
游戏已经开始了吗?
稍微,如果客户端断开连接,那么每个人都会收到“对等退出”通知,游戏就会结束。在这种情况下我不担心重新连接。主要是在游戏大厅中,客户端可以“取消”返回到问题所在的主屏幕。在这种情况下,客户端的会话被破坏。如果他们随后返回大厅并分配了新 GKSession,他们仍然可以连接到服务器,但一旦连接,sendDataToAllPeers 就不再起作用。
* 如果在重新连接之前重新启动,您还会遇到问题吗?
客户端,但保持服务器运行 是这样吗?
客户端在任何情况下都可以重新连接。我可以退出,返回,重新启动应用程序并重新连接,没有问题。除非服务器和客户端都重新启动,否则 sendDataToPeers 就会失败。
* 是否完全销毁客户端的 GKSession 对象
当用户点击“后退”时?
是的。 (参见上面的代码)
我意识到从远处调试这可能是疯狂的,但如果您对我可以研究的内容有任何建议,我将不胜感激。
I've got a peer to peer iPhone game working pretty well. I've created a table to display available peers and I can connect (so far) up to four devices and play a full round of a game from start to finish:
But here's my problem...
I create a GKSession
on one device with GKSessionModeClient
and the other with GKSessionModeServer
. The client sees the server, selects to connect it, then the server approves. The server then can tap "start game" when all the peers are connected.
If--before the server starts the game-- the client taps the "back" button to go to the previous screen, the custom peer picker display is popped from the view and the session is "destroyed"...
[_gkSession disconnectFromAllPeers];
[_gkSession setAvailable:NO];
[_gkSession setDelegate:nil];
[_gkSession setDataReceiveHandler:nil withContext:nil];
now, if the client goes back to the peer picker and joins the server again, I get a GKSessionStateConnected
state again, but when I sendDataToAllPeers:
nothing reaches the client. It works flawlessly if one device starts a game and three devices join and then the server taps "start game". But if someone quits out before the game starts, then recreating a session and joining fails.
Any ideas? My only hack I can think of at this point is preventing a user from tapping "back" once they connect to a server, but that kind of sucks...they'd have to quit the app completely if they changed their mind. I'm at my wits end with this one as the app is running as well as I like it except for this connection issue. Kind of an edge case but I can see a user being annoyed if they can't start a game without having to restart the application to get the sessions cleared.
Will make this a bounty when I can. Please help!
Edit @byteclub
- Does the server clean up all of the relevant data structures correctly if
client leaves before game begins?
If the client leaves the game lobby after the server accepts their connection, the client's session is destroyed:
- (void)destroySession
{
trace(@"destroySession");
self.gameDelegate = nil;
self.lobbyDelegate = nil;
[_gkSession disconnectFromAllPeers];
[_gkSession setAvailable:NO];
[_gkSession setDelegate:nil];
[_gkSession setDataReceiveHandler:nil withContext:nil];
[_peerList removeAllObjects];
}
I do not call any disconnectFromPeers methods on the server device though.
* Is the client-disconnect-cleanup procedure different for cases when the
game has been started already?
Slightly, if a client disconnects then everyone receives a "peer quit" notification and the game ends. I don't worry about reconnecting in this case. It's mainly in the game lobby where the client can "Cancel" to go back to the home screen where the problem is. The client's session is destroyed in this case. If they then go back to the lobby and a new GKSession is alloc'ed, they can connect to the server still, but sendDataToAllPeers no longer works once they are connected.
* Do you still have a problem if, before reconnecting, you restart the
client, but leave the server running
as is?
The client can reconnect in any case. I can quit, go back, restart the app and reconnect no problem. Just sendDataToPeers fails unless the server and client are both restarted.
* Do you completely destroy GKSession object on the client side
when user taps "back"?
Yes. (see code above)
I realize this is probably insane to debug from afar but if you have any suggestions for what I could look into, I'd appreciate it.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
如果我没看错的话,看起来你在某些情况下可以正常工作,但在其他情况下则不然。我会检查逻辑以确保每次都以相同(正确)的方式处理客户端连接/断开连接。
一些问题:
If I'm reading this right, it looks like you have the thing working correctly in some cases, but not others. I'd check the logic to make sure client connects/disconnects are handled the same (correct) way every time.
Some questions: