Можно ли использовать источник отправки GCD для создания асинхронного соединения() в сокете?

Вы можете использовать источники отправки GCD для чтения и записи из сокетов, отслеживать прослушивающий сокет для входящих подключений, но я не мог понять, как использовать источник отправки для подключения сокета?

В псевдокоде он выглядит примерно так:

dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE, connectingSocket, ...);
dispatch_source_set_event_handler(source, ^{
  // Socket did connect or not
});
fcntl(connectingSocket, F_SETFL, O_NONBLOCK);
connect(connectingSocket, addr, len);
dispatch_source_resume(source);

Это было бы лучше, чем использовать select().

Ответ 1

Я изначально неправильно разобрал ваш вопрос... извините. Я получаю это сейчас... вы хотите получить EINPROGRESS от connect и указать источник отправки, когда вызов connect требует внимания вместо опроса с помощью select... Это было довольно легко взломать, и, как представляется, работает:

#import <sys/types.h>
#import <sys/socket.h>
#import <netinet/in.h>
#import <arpa/inet.h>

@implementation AppDelegate
{
    dispatch_source_t foo;
}

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {

    int socketFD = socket(PF_INET, SOCK_STREAM, 0);
    if (socketFD == -1)
    {
        socketFD = -1;
        abort();
    }

    int flags = fcntl(socketFD, F_GETFL, 0);
    int status = fcntl(socketFD, F_SETFL, flags | O_NONBLOCK);
    if (status == -1)
    {
        close(socketFD);
        socketFD = -1;
        abort();
    }

    struct sockaddr_in sockaddr4 = {0};
    sockaddr4.sin_len         = sizeof(sockaddr4);
    sockaddr4.sin_family      = AF_INET;
    sockaddr4.sin_port        = htons(22);
    inet_aton("127.0.0.1", &sockaddr4.sin_addr);

    foo = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE, socketFD, 0, dispatch_get_main_queue());
    dispatch_source_set_event_handler(foo, ^{
        if (connect(socketFD, (const struct sockaddr *)&sockaddr4, (socklen_t)sizeof(sockaddr4)))
        {
            int err = errno;
            NSLog(@"errno: %s", strerror(err));
            if (err == ECONNREFUSED)
            {
                abort();
            }
            else if (err == EISCONN)
            {
                // connected -- queue up other work
                DoStuff();

                // Cancel the source so it doesnt keep notifying...
                dispatch_source_cancel(foo);
            }
        }
    });

    dispatch_source_set_cancel_handler(foo, ^{
        NSLog(@"Cancel");
    });

    dispatch_resume(foo);

    // Do initial connect
    if (connect(socketFD, (const struct sockaddr *)&sockaddr4, (socklen_t)sizeof(sockaddr4)))
    {
        if(errno != EINPROGRESS)
        {
            close(socketFD);
            socketFD = -1;
            abort();
        }
    }
}

@end