NSOutputStream没有调用委托的NSStreamEventHasSpaceAvailable

时间:2013-09-24 13:40:05

标签: ios sockets nsoutputstream

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

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

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

我的代码如下:

@implementation CCCommandSocket

@synthesize connectionTimeoutTimer; @synthesize requestTimeoutTimer;

/ *  * 在里面  *  * @params  * ipAddress:摄像机插座的IP地址  * portNumber:摄像机插座的端口地址  *  * @return  * Socket类型的对象,它将连接请求发送到ipAddress,portNumber  *  * / - (id)init {     self = [super init];     如果(自我)     {         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;

}

pragma mark -

pragma建立套接字通信。

/ *  * connectToCamera  *  * / - (void)connectToCamera {     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];
}

}

pragma mark -

pragma getter方法

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

/ *  * getPort  *  * @return  *插座连接的端口号  * / - (int)getPort {     返回港口; }

pragma mark -

pragma处理套接字回调。

  • (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode {

    NSMutableArray * array = [[NSMutableArray alloc] init]; [array 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];

    开关(EVENTCODE) {     case NSStreamEventErrorOccurred:     {         CCLog(LOG_ERROR,@“In Command Socket NSStreamEventErrorOccurred”);         // [自我断开];         // [[ErrorDetails getInstance] reportError:NSStreamEventErrorOccurred];         打破;     }

        //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;
    }
    

    } }

/ *  * 执行  *  * @param  * request:命令通过socket发送到摄像头  *  * @return  *响应:从相机收到的响应  *  * / - (NSString *)executeRequest:(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;

}

pragma mark -

pragma处理连接超时

//启动连接时调用此方法 - (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];

}

  • (无效)handleConnectionTimeout { responseString = @“{\”rval \“: - 103}”; CCLog(LOG_RESPONSE,responseString);

    [self removeRequestFromQueue];

    [self disconnectWithNotification:YES]; [self stopConnectionTimeoutTimer]; }

//启动连接时调用此方法 - (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];

}

  • (无效)handleRequestTimeout { responseString = @“{\”rval \“: - 103}”; CCLog(LOG_RESPONSE,responseString);

    [self connectToCamera]; [self stopRequestTimeoutTimer]; [self removeRequestFromQueue]; }

//成功连接后调用此方法 - (void)stopRequestTimeoutTimer {     if(requestTimeoutTimer)     {         [requestTimeoutTimer invalidate];         requestTimeoutTimer = nil;     } }

- (void)disconnectWithNotification:(BOOL)showNotification {     CCLog(LOG_INFO,@“Socket Disconnected”);     [inputStream close];     [inputStream setDelegate:nil];     [inputStream removeFromRunLoop:[NSRunLoop 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;     }     if(requestTimeoutTimer)     {         [requestTimeoutTimer invalidate];         requestTimeoutTimer = nil;     } }

- (void)handleCommandPortDataReceived {     [互斥锁];     [self stopRequestTimeoutTimer];     @尝试     {         长尺寸= 1024;         uint8_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];

}

@end

1 个答案:

答案 0 :(得分:0)

您正在尝试使用哪个操作系统版本?我有类似的问题,在10.7及以上它一切都很好,但是在10.6及以下我得到了同样的问题你正在做一些调试,但到目前为止还没有提出一个好的解决方案。