我已经使用输入和输出流实现了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;
}
/ * * 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];
}
}
/ * * getIP * * @return *连接套接字的IP地址 * / - (NSString *)getIP { 返回ip; }
/ * * getPort * * @return *插座连接的端口号 * / - (int)getPort { 返回港口; }
(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;
}
//启动连接时调用此方法 - (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
答案 0 :(得分:0)
您正在尝试使用哪个操作系统版本?我有类似的问题,在10.7及以上它一切都很好,但是在10.6及以下我得到了同样的问题你正在做一些调试,但到目前为止还没有提出一个好的解决方案。