非阻塞连接不会向kqueue报告完成情况

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

在MacOS中,我设置了一个带有O_NONBLOCK的读写套接字,用于连接远程服务器。我使用kqueue等待并协调I / O事件。对connect()的调用会立即触发EINPROGRESS。不久之后,连接完成。通过从服务器接收数据来确认这一点。

但是,我认为当连接最终完成并变得可写时,kqueue会返回一个kevent?没有这样的事件到来。 connect()的手册页指出:

[EINPROGRESS]套接字无阻塞,无法立即完成连接。通过选择用于写入的套接字,可以选择(2)完成。

(1)这是否意味着我需要使用select()而不是kqueque来接收已完成连接的通知?

(2)顺便说一句,如果我尝试连接到没有在端口上监听的服务器,那么kevent很快就会返回EOF来报告那里什么也没有。

(3)如果我尝试连接到不存在的IP,那么我的kevent在我设置的超时时间(15秒)后超时。

代码如下。编译,启动一个“服务器”,如nc -l 10000,运行带或不带IP地址参数的程序,它将分别远程或本地连接。

#include <sys/event.h>
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    int fd = socket(PF_INET, SOCK_STREAM, 0);
    if (fd < 0) {
        perror("socket");
    }

    int fcntl_flags = fcntl(fd, F_GETFL);
    if (fcntl_flags < 0) {
        perror("fcntl");
    }

    fcntl_flags = fcntl(fd, F_SETFL, fcntl_flags | O_NONBLOCK);
    if (fcntl_flags < 0) {
        perror("fcntl");
    }

    struct sockaddr_in addr_in;
    memset(&addr_in, 0, sizeof addr_in);
    addr_in.sin_family = AF_INET;
    addr_in.sin_port = htons(10000);
    if (!inet_pton(AF_INET, argc > 1 ? argv[1] : "127.0.0.1", &addr_in.sin_addr)) {
        perror("inet_aton");
        exit(EXIT_FAILURE);
    }

    struct kevent change;
    struct kevent event;

//    Create kqueue
    int kq;
    if ((kq = kqueue()) < 0) {
        perror("kqueue");
    }

//    Set read and write on socket
    EV_SET(&change, fd, EVFILT_READ | EVFILT_WRITE, EV_ADD | EV_CLEAR, 0, 0, NULL);

//    Put socket in kqueue, return immediately
    struct timespec tmout = { 0, 0 };
    int nev = kevent(kq, &change, 1, &event, 1, &tmout);
    printf("Number events: %d (should be 0)\n", nev);

//    Connect socket to server
    if (!connect(fd, (struct sockaddr *) &addr_in, sizeof(struct sockaddr))) {
        printf("Connected\n");
    }
    else if (errno == EINPROGRESS) {
        printf("EINPROGRESS\n");
    }

//    Wait for connection to complete
    tmout.tv_sec = 15;
    nev = kevent(kq, &change, 0, &event, 1, &tmout);

    if (nev) {
        printf("Number events: %d, filter: %x, flags: %x, data: %ld\n", nev, event.filter, event.flags, event.data);
    }
    else {
        printf("Timeout\n");
    }

    return 0;
}
c macos connect nonblocking kqueue
1个回答
0
投票

弄清楚了。

EVFILT_READ == ffffffff

EVFILT_WRITE == fffffffe

这使得EVFILT_READ | EVFILT_WRITE == EVFILT_READ

结果是“或” - 将它们放在一起使得kqueue只等待READ事件。标志可以是“或” - 但过滤器不应该。

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