当前位置: 首页 > 知识库问答 >
问题:

NSOutputStream未调用委托的NSStreamEventhassspaceAvailable

史英飙
2023-03-14

我使用输入和输出流实现了套接字。外部架构负责一次发送一个请求进行写入。

然而,如果任何请求没有返回no HasBytesAvailable,我需要从队列中删除该请求并通知请求超时。

对于所有其他请求,我能够正确地发送/接收数据,但如果任何一个请求超时,那么在此之后,hasspaceavable将永远不会被调用。

我的代码如下:

@CCCommandSocket的实现

@合成连接TimeoutTimer;@合成请求TimeoutTimer;

/**init**@params*ipAddress:camera socket的ip地址*portNumber:camera socket的端口地址**@return*socket类型的对象,它将向ipAddress发送连接请求,portNumber**/-(id)init{self=[super init];if(self){ip=@“192.168.42.1”;port=7878;

    [self performSelectorOnMainThread:@selector(connectToCamera) withObject:nil waitUntilDone:YES];

    bytesReceivedCondition = [[NSCondition alloc] init];
    requestCompletedCondition = [[NSCondition alloc] init];
    requestReadyToProcess = [[NSCondition alloc] init];
    isBytesReceived = false;
    isRequestCompleted = false;
    isRequestReadyToProcess = false;
    responseString = [[NSString alloc] init];
    openBracesCount = 0;

    mutex = [[NSLock alloc] init];
}
return self;

}

/**连接摄像机**/-(void)连接摄像机{NSString*urlStr=ip;

if (![urlStr isEqualToString:@""])
{

    NSURL *website = [NSURL URLWithString:urlStr];

    if (!website)
    {
        NSString* messageString = [NSString stringWithFormat:@"%@ is not a valid URL",website];
        CCLog(LOG_ERROR, messageString);
        return;
    }

    CFStreamCreatePairWithSocketToHost(NULL, (__bridge CFStringRef)(urlStr), port, &readStream, &writeStream);

    //cast the CFStreams to NSStreams
    inputStream = (__bridge_transfer NSInputStream *)readStream;
    outputStream = (__bridge_transfer NSOutputStream *)writeStream;

    //set the delegate
    [inputStream setDelegate:self];
    [outputStream setDelegate:self];

    //schedule the stream on a run loop
    [inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    [outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];

    //open the stream
    [inputStream open];
    [outputStream open];

    if(readStream==NULL)
    {
        CCLog(LOG_INFO, @"readstream NULL");
    }

    if(writeStream == NULL)
    {
        CCLog(LOG_INFO, @"writeStream NULL");
    }

    [self startConnectionTimeoutTimer];
}

}

/**getIP**@返回*连接到套接字的IP地址*/-(NSString*)getIP{返回ip;}

/**getPort**@return*套接字连接的端口号*/-(int)getPort{return Port;}

>

  • (void)流:(NSStream*)流句柄事件:(NSStreamEvent)事件代码{

    NSMutableArray*数组=[[NSMutableArray alloc]init];[数组addObject:stream];[array addObject:[NSNumber numberWithInt:eventCode]];

    [self-performSelectorInBackground:@selector(myStream:)withObject:array];}

    (void)myStream:(NSMutableArray*)数组{NSNumber*number=[array objectAtIndex:1];int eventCode=[number intValue];

    switch(eventCode){case nsstreamventerroccurred:{CCLog(LOG_ERROR,@“In Command Socket nsstreamventerroccurred”);//[自断开];//[[ErrorDetails getInstance]报告错误:nsstreamventerroccurred];中断;}

        //Read from stream
    case NSStreamEventHasBytesAvailable:
    {
    
        CCLog(LOG_INFO, @"In Command Socket NSStreamEventHasBytesAvailable");
        [self handleCommandPortDataReceived];
        break;
    }
    
        //Write to stream
    case NSStreamEventHasSpaceAvailable:
    {
        @synchronized(self)
        {
            [requestReadyToProcess lock];
            while (isRequestReadyToProcess == false)
            {
                [requestReadyToProcess wait];
            }
            [requestReadyToProcess unlock];
    
            CCLog(LOG_INFO,@"In Command Socket NSStreamEventHasSpaceAvailable");
    
            @try
            {
                @synchronized(requestString)
                {
                    if(requestString != nil)
                    {
                        if(outputStream != nil)
                        {
                            int dataSent;
    
                            uint8_t* data = (uint8_t *)[requestString cStringUsingEncoding:NSUTF8StringEncoding];
                            responseString = @"";
    
                            //[requestReadyToProcess lock];
                            isRequestReadyToProcess = false;
                            //[requestReadyToProcess signal];
                            dataSent = [outputStream write:data maxLength:strlen((char*)data)];
    
                            if(dataSent != -1)
                            {
                                NSString* message = [NSString stringWithFormat:@"Bytes written %d for request\n %@",dataSent, requestString];
                                CCLog(LOG_REQUEST, message);
                                requestString = nil;
                                isBytesReceived = false;
                                [bytesReceivedCondition lock];
    
                                while (isBytesReceived ==false)
                                {
                                    [bytesReceivedCondition wait];
                                }
                                [requestCompletedCondition lock];
                                isRequestCompleted = true;
                                [requestCompletedCondition signal];
                                [requestCompletedCondition unlock];
                                [bytesReceivedCondition unlock];
                            }
                            else
                            {
                                CCLog(LOG_INFO, @"Command Socket : Request not sent (dataSent == -1)");
                                responseString = @"{ \"rval\": -104}";
                                CCLog(LOG_RESPONSE, responseString);
    
                                [self removeRequestFromQueue];
                            }
                        }
                        else
                        {
                            CCLog(LOG_INFO, @"in else :(outputStream != nil)");
                        }
                    }
                }
            }
            @catch (NSException *e)
            {
                CCLog(LOG_WARNING, e.description);
            }
        }
        break;
    }
    case NSStreamEventNone:
    {
        CCLog(LOG_INFO, @"In Command Socket NSStreamEventNone");
        break;
    }
    case NSStreamEventOpenCompleted:
    {
        CCLog(LOG_INFO, @"In Command Socket NSStreamEventOpenCompleted");
        [self stopConnectionTimeoutTimer];
        break;
    }
    case NSStreamEventEndEncountered:
    {
        CCLog(LOG_INFO, @"Command Socket NSStreamEventEndEncountered");
    
        [self disconnectWithNotification:YES];
        break;
    }
    

    }}

    /**执行**@参数*请求:通过套接字发送到摄像机的命令**@返回*响应:从摄像机收到的响应 * */ -(NSString*)执行请求:(NSString*)请求{CCLog(LOG_INFO,@"命令套接字执行请求");

    [self performSelectorOnMainThread:@selector(startRequestTimeoutTimer) withObject:nil waitUntilDone:NO];
    
    isRequestCompleted = false;
    requestString = request;
    responseString = @"";
    
    [requestReadyToProcess lock];
    isRequestReadyToProcess = true;
    [requestReadyToProcess signal];
    [requestReadyToProcess unlock];
    
    [requestCompletedCondition lock];
    while (isRequestCompleted ==false)
    {
        [requestCompletedCondition wait];
    }
    
    CCLog(LOG_INFO, @"Command Socket Execute request : request completed");
    [requestCompletedCondition unlock];
    CCLog(LOG_RESPONSE, responseString);
    return responseString;
    

    }

    //当您启动连接时调用它-(void)startConnectionTimeoutTimer{[self-stopConnectionTimeoutTimer];//或者确保在调用此方法之前停止任何现有计时器

    NSTimeInterval interval = 10.0; // Measured in seconds, is a double
    
    self.connectionTimeoutTimer = [NSTimer scheduledTimerWithTimeInterval:interval
                                                                   target:self
                                                                 selector:@selector(handleConnectionTimeout)
                                                                 userInfo:nil
                                                                  repeats:NO];
    

    }

    >

  • (void)handleConnectionTimeout{responseString=@“{”rval\“:-103}”;CCLog(LOG_响应,responseString);

    [自删除队列中的请求];

    [自断开与通知:是];[自停止连接超时];}

    //在启动连接时调用它—(void)startRequestTimeoutTimer{[self stopRequestTimeoutTimer];//或者确保在调用此方法之前停止任何现有计时器

    NSTimeInterval interval = 20.0; // Measured in seconds, is a double
    
    self.requestTimeoutTimer = [NSTimer scheduledTimerWithTimeInterval:interval
                                                                   target:self
                                                                 selector:@selector(handleRequestTimeout)
                                                                 userInfo:nil
                                                                  repeats:NO];
    

    }

    >

    [自连接摄像机];[自停止请求超时器];[self-removequestfromqueue];}

    //成功连接时调用此函数-(void)stopRequestTimeoutTimer{if(requestTimeoutTimer){[requestTimeoutTimer invalidate];requestTimeoutTimer=nil;}}}

    -(void)disconnectWithNotification:(BOOL)shownnotification{CCLog(LOG_INFO,@“Socket Disconnected”);[inputStream close];[inputStream setDelegate:nil];[inputStream removeFromRunLoop:[nsrunlop currentRunLoop]forMode:NSDefaultRunLoopMode];inputStream=nil;

    [outputStream close];
    [outputStream setDelegate:nil];
    [outputStream removeFromRunLoop:[NSRunLoop currentRunLoop]
                            forMode:NSDefaultRunLoopMode];
    outputStream = nil;
    [[CCCore getInstance] disconnectWithNotification:showNotification];
    

    }

    //成功连接时调用此函数-(void)stopConnectionTimeoutTimer{if(connectionTimeoutTimer){[connectionTimeoutTimer invalidate];connectionTimeoutTimer=nil;}如果(requestTimeoutTimer){[requestTimeoutTimer invalidate];requestTimeoutTimer=nil;}}}

    -(void)handleCommandPortDataReceived{[mutex lock];[self-stopRequestTimeoutTimer];@try{long size=1024;uint8\u t buf[size];unsigned int len=0;

        do
        {
            // read input stream into buffer
            strcpy((char *)buf, "\0");
            len = [inputStream read:buf maxLength:size];
    
            //NSLog(@"Size = %ld Len = %d, Buf = %s",size, len, (char *)buf);
    
            // Following code checks if we have received complete response by matching "{" and "}"
            // from input stream. We continue to form response string unless braces are matched.
            if (len > 0)
            {
                // Create nsdata from buffer
                NSMutableData *_data = [[NSMutableData alloc] init];
                [_data appendBytes:(const void *)buf length:len];
    
                // create temporary string form nsdata
                NSString* currentString = [[NSString alloc] initWithData:_data encoding:NSUTF8StringEncoding];
    
                // check the occurances of { and } in current string
                int currentOpeningBraceCount = [[currentString componentsSeparatedByString:@"{"] count] - 1;
                int currentClosingBraceCount = [[currentString componentsSeparatedByString:@"}"] count] - 1;
    
                openBracesCount = (openBracesCount + currentOpeningBraceCount) - currentClosingBraceCount;
                responseString = [responseString stringByAppendingString:currentString];
    
                //                        NSLog(@"Total:%d currentOpen:%d currentClose:%d\n\n",openBracesCount, currentOpeningBraceCount, currentClosingBraceCount);
                //                        NSLog(@"Current String : %@\n\n",currentString);
                //                        NSLog(@"Final String : %@",finalString);
                //                        NSLog(@"+++++++++++++++++++++++++++++");
            }
            else
                break;
    
        } while (openBracesCount != 0);
    
    
        NSRange range = [responseString rangeOfString:@"get_file_complete"];
        if(range.location == NSNotFound)
        {
            //remove it from queue
            [bytesReceivedCondition lock];
            isBytesReceived = true;
            [bytesReceivedCondition signal];
            [bytesReceivedCondition unlock];
        }
        //responseString = @"";
    
    }
    @catch (NSException* e)
    {
        [self connectToCamera];
    }
    [mutex unlock];
    

    }

    -(void)removeRequestFromQueue{//将其从队列requestString=nil中删除;

    [requestReadyToProcess lock];
    isRequestReadyToProcess = false;
    [requestReadyToProcess unlock];
    
    [requestCompletedCondition lock];
    isRequestCompleted = true;
    [requestCompletedCondition signal];
    [requestCompletedCondition unlock];
    

    }

    @结束

  • 共有1个答案

    刘意
    2023-03-14

    你在哪个操作系统版本上尝试这个??我遇到了类似的问题,在10.7及更高版本中一切都很好,但在10.6及以下版本中,我遇到了与您相同的问题我正在进行一些调试,但到目前为止还没有拿出一个好的解决方案。

     类似资料:
    • 我想在我的应用程序中使用插屏广告,所以我实现了所有必要的委托方法。问题是,如果我使用[self Request estInterstitialAdPresent]来显示广告,只有interstitialAdddLoad:方法被调用。interstitialAdActionddFinish:方法没有被调用... 但是,如果我使用已弃用的[self.interstitialPresinFromView

    • 问题内容: 我对Java中的委托和回调的术语有些误解。 那又如何实现呢? 问题答案: 这是一个回调。根据维基百科: 在计算机编程中,回调是对一段可执行代码的引用,该可执行代码作为参数传递给其他代码。 因此,让我们看一下可执行代码: 在这里,参数是对type对象的引用。由于该引用作为参数传递,因此它是一个回调。 委托由对象内部完成-与方法的调用方式无关。例如,如果变量不是参数,而是实例变量: …那将

    • 本文向大家介绍iOS委托的的作用?相关面试题,主要包含被问及iOS委托的的作用?时的应答技巧和注意事项,需要的朋友参考一下 答案:委托的目的是改变或传递控制链。允许一个类在某些特定时刻通知到其他类,而不需要获取到那些类的指针。可以减少框架复杂度。 另外一点,委托可以理解为java中的回调监听机制的一种类似。

    • 主要内容:类委托,属性委托,标准委托,可观察属性 Observable,把属性储存在映射中,Not Null,局部委托属性,属性委托要求,翻译规则,提供委托委托模式是软件设计模式中的一项基本技巧。在委托模式中,有两个对象参与处理同一个请求,接受请求的对象将请求委托给另一个对象来处理。 Kotlin 直接支持委托模式,更加优雅,简洁。Kotlin 通过关键字 by 实现委托。 类委托 类的委托即一个类中定义的方法实际是调用另一个类的对象的方法来实现的。 以下实例中派生类 Derived 继承了接口

    • 主要内容:声明委托,实例化委托,多播委托(合并委托)C# 中的委托(Delegate)类似于 C 或 C++ 中的函数指针,是一种引用类型,表示对具有特定参数列表和返回类型的方法的引用。委托特别适用于实现事件和回调方法,所有的委托都派生自 System.Delegate 类。在实例化委托时,可以将委托的实例与具有相同返回值类型的方法相关联,这样就可以通过委托来调用方法。另外,使用委托还可以将方法作为参数传递给其他方法, 委托具有以下特点: 委托类似

    • 关于“行为委派”的良好讨论可以在 找到。