我有一个基本问题,
在使用NSOutputStream
时,我们应该等待NSStreamEventHasSpaceAvailable
发送数据包,以便我们可以在需要时调用[NSOutputStream write]
,
我相信NSStream
应该照顾写函数......
如果这不正确,请提供您对以下逻辑的看法,
=====写在NSOutputStream
=================
有队列添加要发送的数据包
// StreamQueue.h
@interface StreamQueue : NSObject <NSCoding>
{
NSMutableArray * data;
NSRecursiveLock * theLock;
}
#pragma mark �Initialization & Deallocation�
- (id)init;
- (id)initWithQueue:(CommQueue *)queue;
- (id)initWithCoder:(NSCoder *)coder;
- (void)dealloc;
- (void)encodeWithCoder:(NSCoder *)coder;
#pragma mark
#pragma mark �Accessor Methods�
- (int)size;
- (BOOL)isEmpty;
- (id)top;
- (NSArray *)data;
#pragma mark
#pragma mark �Modifier Methods�
- (void)enqueue:(id)object;
- (id)dequeue;
- (void)removeAll;
@end
及其实施
#import "StreamQueue.h"
@implementation StreamQueue
#pragma mark �Initialization & Deallocation�
- (id)init
{
if (self = [super init]) {
data = [[NSMutableArray alloc] init];
theLock = [[NSRecursiveLock alloc] init];
}
return self;
}
- (id)initWithQueue:(StreamQueue *)queue
{
if (self = [super init]) {
data = [[NSMutableArray alloc] initWithArray:[queue data]];
theLock = [[NSRecursiveLock alloc] init];
}
return self;
}
- (id)initWithCoder:(NSCoder *)coder
{
if (self = [super init]) {
data = [[NSMutableArray alloc] initWithArray:[coder decodeObject]];
theLock = [[NSRecursiveLock alloc] init];
}
return self;
}
- (void)dealloc
{
[data release];
[theLock release];
[super dealloc];
}
- (void)encodeWithCoder:(NSCoder *)coder;
{
[coder encodeObject:data];
}
#pragma mark
#pragma mark �Accessor Methods�
- (int)size
{
int size;
[theLock lock];
size = [data count];
[theLock unlock];
return size;
}
- (BOOL)isEmpty
{
BOOL empty;
[theLock lock];
empty = ([data count] == 0);
[theLock unlock];
return empty;
}
- (id)top
{
id object = nil;
[theLock lock];
if (![self isEmpty])
object = [data objectAtIndex:0];
[theLock unlock];
return object;
}
- (NSArray *)data
{
NSArray * array;
[theLock lock];
array = [NSArray arrayWithArray:data];
[theLock unlock];
return array;
}
#pragma mark
#pragma mark �Modifier Methods�
- (void)enqueue:(id)object
{
[theLock lock];
[data addObject:object];
[theLock unlock];
}
- (id)dequeue
{
id object = [self top];
if (object != nil) {
[theLock lock];
[object retain];
[data removeObjectAtIndex:0];
[theLock unlock];
}
return [object autorelease];
}
- (void)removeAll
{
[theLock lock];
while (![self isEmpty])
[data removeObjectAtIndex:0];
[theLock unlock];
}
@end
现在当Application通过套接字(NSStream
)发送内容时,它应该将它添加到队列中,
-(bool)sendRawData:(const uint8_t *)data length:(int)len{
// if still negotiating then don't send data
assert(!networkConnected);
NSData *pData = [NSData dataWithBytes:(const void *)data length:len];
// pToSendPacket is of type StreamQueue
[pToSendPacket enqueue:pData];
return;
}
当我们得到NSHasSpaceAvailableEvent
时,和这段代码
-(void)gotSpaceAvailable{
// is there any pending packets that to be send.
NSData *pData = (NSData *)[pToSendPacket dequeue];
if(pData == nil){
// no pending packets..
return;
}
const uint8_t *data = (const uint8_t *)[pData bytes];
int len = [pData length];
int sendlength = [pOutputStream write:data maxLength:len];
if(sendlength == -1 ){
NSError *theError = [pOutputStream streamError];
NSString *pString = [theError localizedDescription];
int errorCode = [theError code];
return ;
}
}
我希望应用程序会在OutputStream
发送数据时继续接收事件,但我只收到一次...... :(
请帮忙......
答案 0 :(得分:8)
如果您不等待事件,则写入调用将阻塞,直到空间可用。通常,您希望设计代码以便异步工作,因此等待NSStreamEventHasSpaceAvailable是最佳解决方案。
至于何时收到可用空间通知,see the documentation here:
如果委托收到NSStreamEventHasSpaceAvailable事件并且 不向流写入任何内容,它不会进一步接收 从运行循环到NSOutputStream的空间可用事件 对象接收更多字节。发生这种情况时,运行循环是 重新启动空间可用事件。如果可能出现这种情况 你的实现,你可以让委托设置一个标志 收到后不会写入流 NSStreamEventHasSpaceAvailable事件。以后,当你的程序有 要写入更多字节,它可以检查此标志,如果设置,则写入 直接输出流实例。
对于一次写入多少字节没有确切的指导。 虽然可以将所有数据写入流中 事件,这取决于外部因素,如行为 内核以及设备和套接字特性。最好的方法是 使用一些合理的缓冲区大小,例如512字节,1千字节(如 在上面的例子中),或页面大小(4千字节)。
因此,只要您为每个事件写入数据,就应该获得常规的NSStreamEventHasSpaceAvailable事件。