未调用CFSocket接受回调。我错过了什么?

时间:2014-08-15 12:06:03

标签: ios objective-c sockets callback cfsocket

我目前正在Objective-C中编写一个简单的TCP服务器类,它应该能够绑定并侦听特定端口。我特别是我有一个函数-(void) start,它创建一个CFSockets,将它绑定到指定的端口并将其添加到运行循环中。它看起来像这样:

- (void) start {
    //This function is called after the initialiser

    if([self isStarted]) //if already started, return without doing anything
        return;


    //create a socket
    CFSocketContext socketCtxt = {0, (__bridge void *)self, NULL, NULL, NULL};
    socket = CFSocketCreate(kCFAllocatorDefault, PF_INET, SOCK_STREAM, IPPROTO_TCP, kCFSocketAcceptCallBack, (CFSocketCallBack)&SocketAcceptCallback, &socketCtxt);


    NSAssert(socket, @"Error: Cannot create a socket...");


    int yes = 1;
    setsockopt(CFSocketGetNative(socket), SOL_SOCKET, SO_REUSEADDR, (void *)&yes, sizeof(yes));


//bind it to the desired port
    struct sockaddr_in serverAddress;
    socklen_t nameLen = 0;
    nameLen = sizeof(serverAddress);
    memset(&serverAddress, 0, sizeof(serverAddress));

    serverAddress.sin_len = nameLen;
    serverAddress.sin_family = AF_INET;
    serverAddress.sin_port = htons(self.port);
    serverAddress.sin_addr.s_addr = htonl(INADDR_ANY);

    NSData* address4 = [NSData dataWithBytes:&serverAddress length:nameLen];


    if(kCFSocketSuccess != CFSocketSetAddress(socket, (CFDataRef)address4)) {
        if (socket) CFRelease(socket);
        socket = NULL;
        NSAssert(NO, @"Unable to bind the created socket to the desired port");
    }


    //add to the current run loop
    CFRunLoopSourceRef rls = CFSocketCreateRunLoopSource(kCFAllocatorDefault, socket, 0);


    assert(rls!=0);

    CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopCommonModes);


    //done!

}

我还定义了回调函数SocketAcceptCallback,如下所示:

static void SocketAcceptCallback(CFSocketRef sock, CFSocketCallBackType type, CFDataRef address, const void *data, void *info) {
    //this method is called after a connection is accepted
    //here we bind the received connection to a pair of
    //NSStreams
    if(type == kCFSocketAcceptCallBack){
        CFSocketNativeHandle nativeSocketHandle = *(CFSocketNativeHandle *)data;

        struct sockaddr_in peerAddress;
        socklen_t peerLen = sizeof(peerAddress);
        NSString * peer = nil;

        if (getpeername(nativeSocketHandle, (struct sockaddr *)&peerAddress, (socklen_t *)&peerLen) == 0) {
            peer = [NSString stringWithUTF8String:inet_ntoa(peerAddress.sin_addr)];
        } else {
            peer = @"Generic Peer";
        }


        NSLog(@"%@ has connected", peer);


        //Find corresponding SocketServer object -- it is passed to the callback in the INFO pointer
        SocketServer *obj = (__bridge SocketServer*)info;

        CFReadStreamRef readStream = NULL;
        CFWriteStreamRef writeStream = NULL;
        CFStreamCreatePairWithSocket(NULL, nativeSocketHandle, &readStream, &writeStream);

         if (readStream && writeStream) {
             CFReadStreamSetProperty(readStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
             CFWriteStreamSetProperty(writeStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);


             //bridge to NSStreams
             obj.inputStream = (NSInputStream *)readStream;
             obj.outputStream = (NSOutputStream *)writeStream;

             //set delegates
             [obj.inputStream setDelegate:obj];
             [obj.outputStream setDelegate:obj];

             //schedule the runloops
             [obj.inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
             [obj.outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];

             //open connections
             [obj.inputStream open];
             [obj.outputStream open];


         } else {
             // on any failure, need to destroy the CFSocketNativeHandle
             // since we are not going to use it any more
             close(nativeSocketHandle);
         }

        /*
         if (readStream) CFRelease(readStream);
         if (writeStream) CFRelease(writeStream); */
    }
}

在回调中,我将连接桥接到一对NSStreams,我将其作为我班级中的成员字段,并用于读写。

现在问题:我试图运行此服务器并通过telnet连接到它。它连接,但前面提到的回调没有被调用(我已通过在其中添加诊断NSLog来检查)。我怀疑我没有正确地将套接字添加到运行循环中,但我自己也找不到任何错误。关于它可能是什么的任何想法?

0 个答案:

没有答案