CFSocket 在成功连接时崩溃

CFSocket crashes on successful connection

这是我用于 CFSocket 通信的客户端和服务器代码,但在成功连接时此代码崩溃。

Client.m

    -(void)createConnection
    {
        CFSocketContext socketContext = {0,(__bridge void *)(self),NULL,NULL,NULL};

    _socket =  CFSocketCreate(kCFAllocatorDefault, PF_INET, SOCK_STREAM, IPPROTO_TCP, kCFSocketConnectCallBack,(CFSocketCallBack)kCFSocketConnectCallBack, &socketContext);

    if (_socket != nil) {
        struct sockaddr_in addr4;
        memset (& addr4, 0, sizeof (addr4));
        addr4.sin_len = sizeof (addr4);
        addr4.sin_family = AF_INET;
        addr4.sin_port = htons (8888);
        NSString *strAddress = @"xxx.xxx.x.xxx";
        addr4.sin_addr.s_addr = inet_addr ([strAddress UTF8String]);


        CFDataRef address = CFDataCreate (kCFAllocatorDefault, (UInt8 *) & addr4, sizeof (addr4));
        CFSocketConnectToAddress (_socket,address,-1);

        CFSocketEnableCallBacks(_socket, kCFSocketConnectCallBack);

        CFRunLoopRef cRunRef = CFRunLoopGetCurrent ();
        CFRunLoopSourceRef sourceRef = CFSocketCreateRunLoopSource (kCFAllocatorDefault, _socket, 0);
        CFRunLoopAddSource (cRunRef,sourceRef,kCFRunLoopCommonModes);

        char ethadd []= "helloworld";
        CFDataRef Data = CFDataCreate(NULL, (const UInt8*)ethadd, sizeof(ethadd));
        int socket_error = CFSocketSendData (_socket, (CFDataRef) address, (CFDataRef) Data, 10);
        if (socket_error < 0){
            NSLog(@"Data could not be sent!");
            //            return EXIT_FAILURE;
        }
        else NSLog(@"Data Sent");

        CFRelease (sourceRef);
    }
}

void TCPServerConnectCallBack (CFSocketRef socket, CFSocketCallBackType type, CFDataRef address, const void * data, void * info) {
    if (data != NULL) {
        // When the socket is kCFSocketConnectCallBack failure callback failed to return an error code pointer, other returns NULL
        NSLog (@"connection failed");
        return;
    }
    Client * client = (__bridge Client *) info;
   [client readStream];
}


- (void)readStream {
    char buffer [1024];
    while (recv (CFSocketGetNative (_socket), // ??Socket associated with the authority has failed to return -1: INVALID_SOCKET is
                 buffer, sizeof (buffer), 0)) {
        NSLog (@"%@", [NSString stringWithUTF8String: buffer]);
    } 
}

- (void) SendMessage :(NSString *)text {
//    [self createConnection];
    NSString * stringTosend = text;
    char * data = (char *)[stringTosend UTF8String];
    send (CFSocketGetNative (_socket), data, strlen (data) + 1, 0);
}

Server.m

-(void)setupSocket
{
    setupSocket();
}

int setupSocket () {

    _socket = CFSocketCreate (kCFAllocatorDefault, PF_INET, SOCK_STREAM, IPPROTO_TCP, kCFSocketAcceptCallBack, (CFSocketCallBack)kCFSocketAcceptCallBack, NULL);
    if (NULL == _socket) {
        NSLog (@ "Cannot create socket!");
        return 0; 
    }
    int optval = 1;
    setsockopt (CFSocketGetNative (_socket), SOL_SOCKET, SO_REUSEADDR, // ??allow reuse of local address and port
                    (void *) & optval, sizeof (optval));

    struct sockaddr_in addr4;
    memset (& addr4, 0, sizeof (addr4));
    addr4.sin_len = sizeof (addr4);
    addr4.sin_family = AF_INET;
    addr4.sin_port = htons (8888);
    addr4.sin_addr.s_addr = inet_addr ([@"xxx.xxx.x.xxx" UTF8String]);//htlon(INADDR_ANY)
    CFDataRef address = CFDataCreate (kCFAllocatorDefault, (UInt8 *) & addr4, sizeof (addr4));

        if (kCFSocketSuccess != CFSocketSetAddress (_socket, address)) {
            NSLog (@ "Bind to address failed!");
            if (_socket)
                CFRelease (_socket); 
            _socket = NULL;
            return 0;
        }

    CFSocketEnableCallBacks(_socket, kCFSocketAcceptCallBack);

    CFRunLoopRef cfRunLoop = CFRunLoopGetCurrent ();
    CFRunLoopSourceRef source = CFSocketCreateRunLoopSource (kCFAllocatorDefault, _socket, 0);
    CFRunLoopAddSource (cfRunLoop, source, kCFRunLoopCommonModes);

    return 1;
}

void TCPServerAcceptCallBack (CFSocketRef socket, CFSocketCallBackType type, CFDataRef address, const void * data, void * info) {
     if (kCFSocketAcceptCallBack == type) {
        // Local socket handle
        CFSocketNativeHandle nativeSocketHandle = * (CFSocketNativeHandle *) data;
        uint8_t name [SOCK_MAXADDRLEN];
        socklen_t nameLen = sizeof (name);
        if (0 != getpeername (nativeSocketHandle, (struct sockaddr *) name, & nameLen)) {
            NSLog (@"error");
//            Exit (1);
        }
         NSLog (@ "%s connected.", inet_ntoa (((struct sockaddr_in *) name) -> sin_addr));

         CFReadStreamRef iStream;
         CFWriteStreamRef oStream;

         CFReadStreamClientCallBack readStream;
         CFReadStreamClientCallBack writeStream;
         CFWriteStreamRef wStream;
         // Create a socket connection can read and write
         CFStreamCreatePairWithSocket (kCFAllocatorDefault, nativeSocketHandle, &iStream, & oStream);
         if (iStream && oStream) {
             CFStreamClientContext streamContext = {0, NULL, NULL, NULL};
             if (! CFReadStreamSetClient (iStream, kCFStreamEventHasBytesAvailable,
                                          readStream, // callback function is called when the data readable
                                          &streamContext)) {
//                 Exit (1);
             }

             if (! CFReadStreamSetClient (iStream, kCFStreamEventCanAcceptBytes, writeStream, &streamContext)) {
//                 Exit (1);
             }

             CFReadStreamScheduleWithRunLoop (iStream, CFRunLoopGetCurrent (), kCFRunLoopCommonModes);
             CFWriteStreamScheduleWithRunLoop (wStream, CFRunLoopGetCurrent (), kCFRunLoopCommonModes);
             CFReadStreamOpen (iStream);
             CFWriteStreamOpen (wStream); 
         }
         else
         {
             close (nativeSocketHandle); 
         } 
     } 
}

// Read data
void readStream (CFReadStreamRef stream, CFStreamEventType eventType, void * clientCallBackInfo) {
    UInt8 buff [255];
    CFReadStreamRead (stream, buff, 255);
    printf ("received:%s", buff);
}

void writeStream (CFWriteStreamRef stream, CFStreamEventType eventType, void * clientCallBackInfo) {
    outputStream = stream;
}

//int main()
//{
//    char * str = "nihao";
//    UInt8 buff [255];
//    if (outputStream != NULL) {
//        CFWriteStreamWrite (outputStream, buff, strlen (str) + 1);
//    }
//    else
//    {
//        NSLog (@ "Cannot send data!");
//    }
//}

// Open up a thread in the thread function
void runLoopInThread () {
    int res = setupSocket ();
    if (res) {
        EXIT_FAILURE;
    }
    CFRunLoopRun (); // run the current thread CFRunLoop of objects
}

在上面的代码中,当 CFSocketConnectToAddress 在客户端中执行时服务器崩溃,之后客户端应用程序也崩溃。

处理 CFSockets 将使您进入处理 POSIX 基础和东西的世界。如果你正在寻找一个简单的 echo/chat 服务器,你应该首先去 NSStream。这要容易得多。这是一个例子:

CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
CFStreamCreatePairWithSocketToHost(NULL, (__bridge CFStringRef)HOST, PORT, &readStream, &writeStream);
inputStream = (__bridge NSInputStream *)readStream;
outputStream = (NSOutputStream *)CFBridgingRelease(writeStream);
[inputStream setDelegate:self];
[outputStream setDelegate:self];
[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[inputStream open];
[outputStream open];

并像这样处理输入:

- (void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent {
switch (streamEvent) {
    case NSStreamEventOpenCompleted:
        NSLog(@"Stream opened");
        break;
    case NSStreamEventHasBytesAvailable:
        if (theStream == inputStream) {
            uint8_t buffer[100240];
            NSInteger len;
            while ([inputStream hasBytesAvailable]) {
                len = [inputStream read:buffer maxLength:sizeof(buffer)];
                if (len > 0) {
                    NSString *output = [[NSString alloc] initWithBytes:buffer length:len encoding:NSASCIIStringEncoding];
                    if (nil != output) {
                        NSLog(@"Server Response: %@", output);
                        [self stream:theStream didRecieveResponse:output];
                    }
                }
            }
        }
        break;
    case NSStreamEventErrorOccurred:
        [self requestDidFailWithResults:@"Can not connect to the host!" andError:theStream.streamError];
        [theStream close];
        [theStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
        theStream = nil;
        break;
    case NSStreamEventEndEncountered:
        [self requestDidFailWithResults:@"Request ended" andError:theStream.streamError];
        [theStream close];
        [theStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
        theStream = nil;
        break;
    case NSStreamEventHasSpaceAvailable:
        NSLog(@"OutStream is ready");
        break;
    default:
        [self requestDidFailWithResults:@"Unknown event" andError:theStream.streamError];
}

}

_socket = CFSocketCreate (kCFAllocatorDefault, PF_INET, SOCK_STREAM, IPPROTO_TCP, kCFSocketAcceptCallBack, (CFSocketCallBack)kCFSocketAcceptCallBack, NULL);

在上面的方法中,我必须传递我的回调方法而不是“(CFSocketCallBack)kCFSocketAcceptCallBack”。这解决了我的问题。