Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/344.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
&引用;“对等端重置连接”;iOS6上的GCDAsyncUdpSocket错误_Ios_Udp_Grand Central Dispatch_Gcdasyncsocket - Fatal编程技术网

&引用;“对等端重置连接”;iOS6上的GCDAsyncUdpSocket错误

&引用;“对等端重置连接”;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数据包

我在使用GCDAsyncUdpSocket时遇到问题。我使用iPad作为一个用户界面应用程序,与另一个应用程序交互——call it Host,后者在单独的Windows机器上运行。这两台机器都位于各自的专用网络上,因此它们位于各自的子网中。在某些情况下,主机向iPad发送UDP数据包,以指示向用户显示哪个屏幕,iPad通过UDP数据包向主机发送用户响应。最后,iPad会定期(2赫兹)向主机发送简单的“心跳”信息

在一段时间内,这一切都很好。然后,显然,iPad突然停止接受来自主机的UDP数据包——后者经历了“由对等方重置连接”错误,而它(iPad)仍在成功发送和主机接收心跳消息

我认为这个问题来自于我对大中央调度(GCD)如何工作的困惑。我的iPad应用程序非常简单;我是根据iOS编程教程编写的(我在这里是初学者,但对Windows、Linux、嵌入式/实时和网络非常有经验)。它基本上由一个主屏幕组成,主屏幕不时地创建第二个屏幕。所以基本结构是这样的:

  • main.m
  • 代表,m
  • MainViewController.m
  • PopupViewController.m
main.m和Delegate.m是在教程中由Xcode自动创建的,它们没有任何特殊之处。MainViewController.m是我的“主屏幕”,它拥有iPad应用程序使用的GCDAsyncUdpSocket。最后一个文件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消息对我有效吗?我想是的,发送从来没有失败过——即使在接收失败后,它仍能继续工作

  • didReceiveData是如何被调用的,又是如何被破坏的?如果我在Linux或RTOS中,我可能会创建一个等待数据包的显式线程;GCD框架如何决定数据包应该放在哪里

  • 为什么我的应用程序突然停止监听端口?我如何检测/调试它

  • GCDAsyncUdpSocket对象由主屏幕拥有,而不是由Delegate.m模块拥有,这有关系吗

  • 我认为使用主调度队列是否合适?事实上,我这样做是正确的吗

  • 我完全不知所措,所以,当然,任何建议都会非常感激!无需回答所有问题-尤其是如果你对其中一个问题的回答是解决方案


    谢谢

    听起来好像接收UDP套接字正在关闭或转移到不同的地址/端口对

    • 如果它被关闭,传出数据包仍然可以工作的唯一方法是如果实际上有两个套接字。可能接收端绑定到端口12349,发送端绑定到端口0。那么也许GCD会在一段时间后关闭接收。鉴于您对ARP的后续评论,这似乎不太可能,但值得记住

    • ARP活动表明iPad的IP地址可能正在改变。如果它要改变,或者如果它要从WiFi接口切换到蜂窝接口,那么它发送的数据包仍然可以通过,但发送到它的数据包将完全按照描述的那样失败

    无论接收到什么心跳信息,都要让它检查recvfrom地址,并确保它发回的任何信息都能准确到达该地址。当然,还要注意endian(主机与网络字节顺序)


    我假设这两个设备之间没有防火墙或NAT。如果有这样的事情,那么一个完全不同的可能性世界就打开了。

    这篇文章结束了我在
    POSIX/GCDAsyncSocket/NSStream/NSNetService
    神手中遭受的大约八个小时的折磨。对于遇到此问题的任何人:对等/远程对等断开连接错误导致我的
    GCDAsyncSocket
    连接重置的原因很简单,就是我是通过
    LAN
    上的
    IP
    连接的,而不是使用主机名。(即使用
    connectToAddress
    方法系列而不是
    connectToHost
    方法系列)。我启动了WireShark,下载了X11,所有这些jazz,并确认我正面临着Bob所看到的相同问题——断开连接前后的ARP活动。试图连接到主机而不是地址证实了赛斯对这种情况的看法——这是t