NSInputStream:读取:maxLength:在TCP套接字流上返回错误“操作无法完成。坏文件描述符“

问题描述 投票:0回答:1

我试图在Xcode中创建一个简单的TCP服务器,OS X上的Objective-C。

似乎连接已被接受,并且我正在获取我应该通过事件处理获得的所有事件,但是当我尝试从事件内的输入流中读取时,表明有可读取的数据,我收到以下错误消息:

错误域= NSPOSIXErrorDomain代码= 9“操作无法完成。错误的文件描述符”

我的完整调试日志是:

handleConnect: ACCEPT
<< Open Complete
>> Open Complete
<< Has Bytes Available
Error Reading Stream
Error Domain=NSPOSIXErrorDomain Code=9 "The operation couldn’t be completed. Bad file descriptor"
Length: 0
<< Error Occured
Error Domain=NSPOSIXErrorDomain Code=9 "The operation couldn’t be completed. Bad file descriptor"

您可以看到输入和输出流都发送“Open Complete”事件,然后输入流发送“Has Bytes Available”事件,但是从流中读取失败。读取失败后,输入流将发送“Error Occured”事件。

我不知道问题究竟是什么。我想尝试连接Web浏览器。这是我写的代码:

网络服务器:

#import "WebServer.h"

@implementation WebServer

- (id)init {
    self = [super init];

    if (self != nil) {
        connections = nil;
    }

    return self;
}

- (void)start {

    CFSocketRef myipv4cfsock = CFSocketCreate(
                                          kCFAllocatorDefault,
                                          PF_INET,
                                          SOCK_STREAM,
                                          IPPROTO_TCP,
                                          kCFSocketAcceptCallBack, handleConnect, NULL);

    struct sockaddr_in sin;

    memset(&sin, 0, sizeof(sin));
    sin.sin_len = sizeof(sin);
    sin.sin_family = AF_INET;
    sin.sin_port = htons(8080);
    sin.sin_addr.s_addr= INADDR_ANY;

    CFDataRef sincfd = CFDataCreate(
                                kCFAllocatorDefault,
                                (UInt8 *)&sin,
                                sizeof(sin));

    CFSocketSetAddress(myipv4cfsock, sincfd);
    CFRelease(sincfd);

    CFRunLoopSourceRef socketsource = CFSocketCreateRunLoopSource(
                                                              kCFAllocatorDefault,
                                                              myipv4cfsock,
                                                              0);

    CFRunLoopAddSource(
                   CFRunLoopGetCurrent(),
                   socketsource,
                   kCFRunLoopDefaultMode);
}

void handleConnect(CFSocketRef s, CFSocketCallBackType callbackType, CFDataRef address, const void *data, void *info) {

    if (callbackType == kCFSocketAcceptCallBack) {
        printf("handleConnect: ACCEPT\n");

        if (connections == nil) {
            connections = [[NSMutableArray alloc] init];
        }

        CFReadStreamRef rs = NULL;
        CFWriteStreamRef ws = NULL;

        CFStreamCreatePairWithSocket(kCFAllocatorDefault, (CFSocketNativeHandle)data, &rs, &ws);

        WebServerConnection *connection = [[WebServerConnection alloc] initWithInputStream:(__bridge NSInputStream *)rs outputStream:(__bridge NSOutputStream *)ws];
        [connections addObject:connection];

        return;
    }
    else {
        printf("handleConnect: UNKNOWN\n");
    }
}

@end

有人连接时:

#import "WebServerConnection.h"

@implementation WebServerConnection

- (id)init {
    self = [super init];

    if (self != nil) {
        nativeSocket = 0;
        readStream = nil;
        writeStream = nil;
    }

    return self;
}

- (id)initWithInputStream:(NSInputStream *)is outputStream:(NSOutputStream *)os {
    self = [self init];

    if (self != nil) {
        readStream = is;
        writeStream = os;
        [readStream setDelegate:self];
        [writeStream setDelegate:self];
        [readStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
        [writeStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
        [readStream open];
        [writeStream open];

        data = nil;
    }

    return self;
}

- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode {
    NSString *io = @"??";

    if (aStream == readStream) {
        io = @"<<";
    }

    else if (aStream == writeStream) {
        io = @">>";
    }

    switch (eventCode) {
        case NSStreamEventOpenCompleted:
            printf("%s ", [io UTF8String]);
            printf("Open Complete\n");
            break;

        case NSStreamEventHasBytesAvailable:
        {
            printf("%s ", [io UTF8String]);
            printf("Has Bytes Available\n");

            if (data == nil) {
                data = [[NSMutableData alloc] init];
            }

            uint8_t buffer[1024];

            NSInteger actuallyRead = [readStream read:(uint8_t *)buffer maxLength:sizeof(buffer)];

            if (actuallyRead > 0) {
                [data appendBytes:buffer length:actuallyRead];
            }
            else {
                if (actuallyRead == 0) {
                    printf("End of Data\n");
                }
                else {
                    printf("Error Reading Stream\n");
                    NSError *error = [readStream streamError];
                    printf("%s\n", [[error description] UTF8String]);
                }
            }

            printf("Length: %lu\n", [data length]);

            break;
        }

        case NSStreamEventHasSpaceAvailable:
            printf("%s ", [io UTF8String]);
            printf("Has Space Available\n");
            break;

        case NSStreamEventEndEncountered:
            printf("%s ", [io UTF8String]);
            printf("End Encountered\n");
            break;

        case NSStreamEventErrorOccurred:
        {
            printf("%s ", [io UTF8String]);
            printf("Error Occured\n");
            NSError *error = [aStream streamError];
            printf("%s\n", [[error description] UTF8String]);

            [readStream setDelegate:nil];
            [writeStream setDelegate:nil];
            [readStream close];
            [writeStream close];
            [readStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
            [writeStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];

            break;
        }

        case NSStreamEventNone:
        {
            printf("%s ", [io UTF8String]);
            printf("None\n");
            break;
        }

        default:
            printf("%s ", [io UTF8String]);
            printf("Default Clause\n");
            break;
    }
}

@end
objective-c sockets tcp nsstream
1个回答
1
投票

似乎我将错误的数据传递给'CFStreamCreatePairWithSocket()函数。

    CFStreamCreatePairWithSocket(kCFAllocatorDefault, *(CFSocketNativeHandle *)data, &rs, &ws);

请注意,我忘了施放*(CFSocketNativeHandle *)data,只是发送(CFSocketNativeHandle)data

© www.soinside.com 2019 - 2024. All rights reserved.