2011-08-12 6 views
2

私は1つの基本的な質問、 を持っている私たちは、パケットを送信するためにNSStreamEventHasSpaceAvailableのを待つ必要があるので、我々はとして、[NSOutputStream write]を呼び出すことができますし、その必要なときに、 NSOutputStreamを書く際の問題。

私は NSStreamが書き込み機能の世話をするべきだと考え、 NSOutputStreamでの作業中。これが正しくない場合...

が、その後、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 

アプリケーションがソケット(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がデータを送信するたびに、アプリケーションは、イベントを受信し続けるだろう期待していたが、私は一度だけ受け取った... :( あなたがイベントを待たない場合は...

答えて

8

を助けてください書き込みコールは、スペースが利用可能になるまでブロックされます。一般的には、非同期で動作するようにコードを設計することを目指したいので、NSStreamEventHasSpaceAvailableを待つことが最善の解決策です。デリゲートがNSStreamEventHasSpaceAvailableイベントを受け取り、 は、ストリームに何も書き込みません

場合、それはより一層 スペースの使用可能なイベントを受信しない:あなたがスペース利用可能通知、see the documentation hereを受信したときについては

NSOutputStream オブジェクトがより多くのバイトを受け取るまで実行ループ。この場合、実行可能なイベントの実行ループは に再起動されます。このシナリオが の実装である可能性がある場合、 が NSStreamEventHasSpaceAvailableイベントを受信したときにストリームに書き込みを行わない場合、デリゲートにフラグを設定させることができます。後で、プログラムに バイト以上の書き込みがある場合は、このフラグをチェックし、設定されている場合は 出力ストリームインスタンスに直接書き込みます。

一度に書き込むバイト数についての指針はありません。 イベントですべてのデータをストリームに書き込むことは可能ですが、これは カーネルの動作やデバイスとソケットの特性などの外部要因によって異なります。最良の方法は、 に、512バイト、1キロバイト(上記の例では )、ページサイズ(4キロバイト)などの適切なバッファサイズを使用することです。

したがって、イベントごとにデータを書き込む限り、NSStreamEventHasSpaceAvailableイベントを定期的に取得する必要があります。

関連する問題