ios - NSOutputStream 总是写入零字节

标签 ios nsstream cfnetwork

完全遵循 Apple 的文档:https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Streams/Streams.html - 我无法让任何网络 NSOutputStream 写入数据。它总是返回一个苹果文档似乎说不应该返回的数字(0 - 苹果声称这是针对固定大小的流,而不是网络流??)。

Apple 的所有示例代码都忽略返回代码(似乎假设它是正数 - 我在网上找到的很多示例都使用无符号类型!这是非常错误的:( )。

我已经成功了:

  1. 带有 kCFSocketAcceptCallBack 的 CFSocketCreate() 和指向我的 handleConnect 函数的指针
  2. CFSocketSetAddress() 带有“any”和手动选择的端口
  3. CFRunLoopAddSource() 开始监听端口

...所有这些都有效,通过远程登录到 IP 地址 + 端口来确认...


...但是,只要遵循 Apple 文档,就会出现严重错误:

void handleConnect (
                 CFSocketRef s,
                 CFSocketCallBackType callbackType,
                 CFDataRef address,
                 const void *data,
                 void *info
                 )
{
    NSLog(@"handleConnect called with callbackType = %li", callbackType);

    (myclass) server = (myclass*) info;

    BOOL canAccept = callbackType & kCFSocketAcceptCallBack;
    BOOL canWrite = callbackType & kCFSocketWriteCallBack;
    BOOL canRead = callbackType & kCFSocketReadCallBack;
    NSLog(@" ... acceptable? %@  .. readable? %@ .. writeable? %@", canAccept?@"yes":@"no", canRead?@"yes":@"no", canWrite?@"yes":@"no" );

    if( canAccept)
    {
        NSLog(@"[%@] Accepted a socket connection from remote host. Address = %@", [server class], addressString );
        /**
         "which means that a new connection has been accepted. In this case, the data parameter of the callback is a pointer to a CFSocketNativeHandle value (an integer socket number) representing the socket.

         To handle the new incoming connections, you can use the CFStream, NSStream, or CFSocket APIs. The stream-based APIs are strongly recommended."
         */

        // "1. Create read and write streams for the socket with the CFStreamCreatePairWithSocket function."
        CFReadStreamRef clientInput = NULL;
        CFWriteStreamRef clientOutput = NULL;

        // for an AcceptCallBack, the data parameter is a pointer to a CFSocketNativeHandle
        CFSocketNativeHandle nativeSocketHandle = *(CFSocketNativeHandle *)data;

        CFStreamCreatePairWithSocket(kCFAllocatorDefault, nativeSocketHandle, &clientInput, &clientOutput);

        // "2. Cast the streams to an NSInputStream object and an NSOutputStream object if you are working in Cocoa."

        // "3. Use the streams as described in “Writing a TCP-Based Client.”
        self.outputBuffer = [NSMutableData dataWithData:[@"Hello" dataWithEncoding:NSUTF8StringEncoding]];
        self.outputBytesWrittenRecently = 0;
        ((NSOutputStream*)output).delegate = self;

        [((NSOutputStream*)output) scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
        [((NSOutputStream*)output) open]; // MUST go last, undocumented Apple bug
    }
}

...以及委托(delegate)方法:

-(void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode
{
    BOOL streamOpened = eventCode & NSStreamEventOpenCompleted;
    BOOL streamReadyToWrite = eventCode & NSStreamEventHasSpaceAvailable;
    BOOL streamReadyToRead = eventCode & NSStreamEventHasBytesAvailable;
    BOOL streamEnded = eventCode & NSStreamEventEndEncountered;
    BOOL streamErrored = eventCode & NSStreamEventErrorOccurred;

    if( streamReadyToWrite )
#define C_BUFFER_IN_MEMORY_SIZE_WRITE ( 4096 ) // Apple vaguely recommends 4k, but I tried numbers down to 100 with no effect
    uint8_t extraCBufferNSStreamSucks[ C_BUFFER_IN_MEMORY_SIZE_WRITE ];
    NSRange rangeOfBytesToAttemptToWriteNext = { self.outputBytesWrittenRecently, MIN( C_BUFFER_IN_MEMORY_SIZE_WRITE, self.outputBuffer.length - self.outputBytesWrittenRecently) };
    [self.outputBuffer getBytes:&extraCBufferNSStreamSucks range:rangeOfBytesToAttemptToWriteNext];

    NSLog(@"About to write data to stream, this might block...");
    NSInteger amountWritten = [self.outputS write:extraCBufferNSStreamSucks maxLength:C_BUFFER_IN_MEMORY_SIZE_WRITE];
    NSLog(@"...finished write data to stream, it might have blocked");
    if( amountWritten > 0 )
    {
        self.outputBytesWrittenRecently += amountWritten;

        NSRange totalWrittenRange = { 0, self.outputBytesWrittenRecently };
        NSLog(@"Written %i bytes: %@", amountWritten, [[[NSString alloc] initWithData:[self.outputBuffer subdataWithRange:totalWrittenRange] encoding:NSUTF8StringEncoding] autorelease] );

        if( self.outputBytesWrittenRecently == self.outputBuffer.length )
        {
            NSLog(@"Finished writing data!");

        }
    }
    else
        NSLog(@"ERROR: failed to write bytes to stream (bytes written = %i)", amountWritten);
}

最佳答案

啊!未记录,但是...如果您的 NSStream 实例变为 nil,Apple 不会返回错误,而是返回成功 - 但随后返回 0 表示写入的字节数。

就我而言,init 方法中的拼写错误意味着我用 nil 覆盖了新捕获的 NSOutputStream 和 NSInputStream。

哎哟。

关于ios - NSOutputStream 总是写入零字节,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17151219/

相关文章:

ios - UITableViewController 与 UITableView

ios - NSStream - 反向 DNS 查找错误

c++ - 如何在 MAC OS X 上的 CMAKE 项目中包含 C 静态库

cocoa - 如何在 Cocoa WebView 中显示(https 请求的)服务器证书信息?

iOS map View - 缩放以固定然后激活标注

ios - 如何在进入后台后杀死 NSTimer 并在应用程序恢复事件后创建一个新计时器?

ios - 隐藏 View 时,自动布局中的 Swift 约束不会改变

ios - Swift 中的无响应流委托(delegate)

ios - 将传入的 NSStream 转换为 View

ios - 不使用iPhone中的CFURLDestroyResource方法从ftp删除文件