&引用;“对等端重置连接”;iOS6上的GCDAsyncUdpSocket错误
我在使用GCDAsyncUdpSocket时遇到问题。我使用iPad作为一个用户界面应用程序,与另一个应用程序交互——call it Host,后者在单独的Windows机器上运行。这两台机器都位于各自的专用网络上,因此它们位于各自的子网中。在某些情况下,主机向iPad发送UDP数据包,以指示向用户显示哪个屏幕,iPad通过UDP数据包向主机发送用户响应。最后,iPad会定期(2赫兹)向主机发送简单的“心跳”信息 在一段时间内,这一切都很好。然后,显然,iPad突然停止接受来自主机的UDP数据包——后者经历了“由对等方重置连接”错误,而它(iPad)仍在成功发送和主机接收心跳消息 我认为这个问题来自于我对大中央调度(GCD)如何工作的困惑。我的iPad应用程序非常简单;我是根据iOS编程教程编写的(我在这里是初学者,但对Windows、Linux、嵌入式/实时和网络非常有经验)。它基本上由一个主屏幕组成,主屏幕不时地创建第二个屏幕。所以基本结构是这样的:&引用;“对等端重置连接”;iOS6上的GCDAsyncUdpSocket错误,ios,udp,grand-central-dispatch,gcdasyncsocket,Ios,Udp,Grand Central Dispatch,Gcdasyncsocket,我在使用GCDAsyncUdpSocket时遇到问题。我使用iPad作为一个用户界面应用程序,与另一个应用程序交互——call it Host,后者在单独的Windows机器上运行。这两台机器都位于各自的专用网络上,因此它们位于各自的子网中。在某些情况下,主机向iPad发送UDP数据包,以指示向用户显示哪个屏幕,iPad通过UDP数据包向主机发送用户响应。最后,iPad会定期(2赫兹)向主机发送简单的“心跳”信息 在一段时间内,这一切都很好。然后,显然,iPad突然停止接受来自主机的UDP数据包
- main.m
- 代表,m
- MainViewController.m
- PopupViewController.m
# MainViewController.m
- (IBAction)sendResponseOne:(id)sender {
// Send a message to Host
[self sendUdpMessage:1];
// Switch to other view
PopupViewController *vc = [[PopupViewController alloc] init];
[vc setMainScreen:self]; // Used to access UDP from 2nd screen
[self presentViewController:vc animated:NO completion:nil];
}
# PopupViewController.m
- (IBAction)confirmAnswers:(id)sender
{
// Send a message to Host - calls same function as above main screen
[self->mainScr sendUdpMessage:2];
[self dismissViewControllerAnimated:NO completion:nil];
}
现在是sems失败的代码。首先,这里是MainViewController.m的@interface部分:
# From MainViewController.m
@interface MainViewController ()
{
GCDAsyncUdpSocket *udpSocket;
}
@end
以下是创建UDP对象的方式/位置:
# From MainViewController.m
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]))
{
// Setup our socket, using the main dispatch queue
udpSocket = [[GCDAsyncUdpSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
}
return self;
}
以下是我绑定到端口的位置:
# From MainViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
// Start UDP server
int port = 12349;
NSError *error = nil;
if (![udpSocket bindToPort:port error:&error])
{
NSLog(@"Error starting server (bind): %@", error);
return;
}
if (![udpSocket beginReceiving:&error])
{
[udpSocket close];
NSLog(@"Error starting server (recv): %@", error);
return;
}
[self startPingTimer];
isRunning = YES;
}
下面是接收数据包的代码。显然,这个函数可以正常工作一段时间,有时工作几十次,然后意外地失败
# From MainViewController.m
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didReceiveData:(NSData *)data
fromAddress:(NSData *)address
withFilterContext:(id)filterContext
{
if (data.length == sizeof(MyMessage)) {
MyMessage msg;
[data getBytes:&msg length:sizeof(MyMessage)];
msg.magic = ntohl(msg.magic);
msg.msgId = ntohl(msg.msgId);
for (int i = 0; i < 4; ++i) {
msg.values[i] = ntohl(msg.values[i]);
}
if (msg.magic == 0xdeadcafe) {
switch (msg.msgId) {
case imiStateControl:
self->iceState = (IceState)msg.values[0];
break;
default:
break;
}
}
}
}
#来自MainViewController.m
-(void)udpSocket:(GCDAsyncUdpSocket*)sock direceivedata:(NSData*)数据
fromAddress:(NSData*)地址
withFilterContext:(id)filterContext
{
if(data.length==sizeof(MyMessage)){
我的讯息;
[数据获取字节:&消息长度:sizeof(MyMessage)];
msg.magic=ntohl(msg.magic);
msg.msgId=ntohl(msg.msgId);
对于(int i=0;i<4;++i){
msg.values[i]=ntohl(msg.values[i]);
}
如果(msg.magic==0xdeadcafe){
开关(msg.msgId){
病例对照:
self->iceState=(iceState)消息值[0];
打破
违约:
打破
}
}
}
}
我不明白为什么didReceiveData函数在一些随机的时间段(以及随机发送/接收的消息数)内似乎能正常工作。我想知道两件事:
谢谢 听起来好像接收UDP套接字正在关闭或转移到不同的地址/端口对
- 如果它被关闭,传出数据包仍然可以工作的唯一方法是如果实际上有两个套接字。可能接收端绑定到端口12349,发送端绑定到端口0。那么也许GCD会在一段时间后关闭接收。鉴于您对ARP的后续评论,这似乎不太可能,但值得记住
- ARP活动表明iPad的IP地址可能正在改变。如果它要改变,或者如果它要从WiFi接口切换到蜂窝接口,那么它发送的数据包仍然可以通过,但发送到它的数据包将完全按照描述的那样失败
我假设这两个设备之间没有防火墙或NAT。如果有这样的事情,那么一个完全不同的可能性世界就打开了。这篇文章结束了我在
POSIX/GCDAsyncSocket/NSStream/NSNetService
神手中遭受的大约八个小时的折磨。对于遇到此问题的任何人:对等/远程对等断开连接错误导致我的GCDAsyncSocket
连接重置的原因很简单,就是我是通过LAN
上的IP
连接的,而不是使用主机名。(即使用connectToAddress
方法系列而不是connectToHost
方法系列)。我启动了WireShark,下载了X11,所有这些jazz,并确认我正面临着Bob所看到的相同问题——断开连接前后的ARP活动。试图连接到主机而不是地址证实了赛斯对这种情况的看法——这是t