c - 非阻塞连接上的 MacOSX select() 行为不正确

标签 c macos sockets

我正在我的跨平台框架中使用套接字层,我试图让连接以非阻塞方式工作。然而,在翻阅文档之后,他们似乎根本没有表现得正确。问题的核心在于,在启动非阻塞连接后,以下选择未能注意到连接已成功,并继续一遍又一遍地超时。

SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
hostent *h = gethostbyname("www.memecode.com");
if (h)
{
    sockaddr_in addr;
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(80);

    if (h->h_addr_list && h->h_addr_list[0])
    {
        memcpy(&addr.sin_addr, h->h_addr_list[0], sizeof(in_addr));

        // Set non blocking
        fcntl(s, F_SETFL, O_NONBLOCK);

        int64 start = LgiCurrentTime();
        int status = connect(s, (sockaddr*) &addr, sizeof(sockaddr_in));
        printf("Initial connect = %i\n", status);
        while (status && (LgiCurrentTime()-start) < 15000)
        {
            //  Do select to wait for connect to finish
            fd_set wr;
            FD_ZERO(&wr);
            FD_SET(s, &wr);
            int TimeoutMs = 1000;
            struct timeval t = {TimeoutMs / 1000, (TimeoutMs % 1000) * 1000};
            errno = 0;
            int64 sel_start = LgiCurrentTime();
            int ret = select(0, 0, &wr, 0, &t);
            int64 sel_end = LgiCurrentTime();
            printf("%i = select(0,%i,0) errno=%i time=%i\n",
                ret,
                FD_ISSET(s, &wr)!=0,
                errno,
                (int)(sel_end-sel_start));

            if (ret > 0 && FD_ISSET(s, &wr))
            {
                // ready for connect to finish...
                status = connect(s, (sockaddr*) &addr, sizeof(sockaddr_in));
                printf("2nd connect = %i\n", status);
                if (status)
                {
                    if (errno == EISCONN)
                    {
                        status = 0;
                        printf("error = EISCONN so we're good.\n");
                    }
                }
            }
            // else still waiting...
        }
    }
    else printf("host addr error.\n");
}
else printf("gethostbyname failed.\n");

当我在最新的 MacOSX Leopard 版本上运行这段代码时,我得到了这样的输出:

Initial connect = -1
0 = select(0,1,0) errno=0 time=1000
0 = select(0,1,0) errno=0 time=1000
0 = select(0,1,0) errno=0 time=1000
0 = select(0,1,0) errno=0 time=1000
0 = select(0,1,0) errno=0 time=1000
0 = select(0,1,0) errno=0 time=1000
0 = select(0,1,0) errno=0 time=1000
0 = select(0,1,0) errno=0 time=1000
0 = select(0,1,0) errno=0 time=1000
0 = select(0,1,0) errno=0 time=1001
0 = select(0,1,0) errno=0 time=1000
0 = select(0,1,0) errno=0 time=1000
0 = select(0,1,0) errno=0 time=1000
0 = select(0,1,0) errno=0 time=1000
0 = select(0,1,0) errno=0 time=1000

当我在选择后删除“ret > 0”条件时,以下连接成功并返回 EISCONN。所以连接在幕后工作,但选择永远不会接受它。根据我对 select 返回值的理解,它包含 fd_set 结构中套接字的数量,如果它们都没有事件,则返回 0。

我的代码有什么问题?

PS LgiCurrentTime() 返回从某个点开始的毫秒数,例如Windows 上的 GetTickCount...我忘记了在 Mac 上的确切实现,但这并不重要...只是时间信息。

最佳答案

我相信 select(..) 的第一个参数应该是最高的文件描述符编号 +1 而不是 0

int ret = select(s+1, 0, &wr, 0, &t);

关于c - 非阻塞连接上的 MacOSX select() 行为不正确,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1250039/

相关文章:

java - .jar 文件无法在某些计算机上运行

macos - OSX中的zsh编译问题

python - 安全直接连接文件传输程序

java - 无法将红蜘蛛 WebSocket 连接到 Java ServerSocket

c - 在 C 中并排打印二维数组

macos - npm install odbc 在 OSX 和 Ubuntu 上失败

html - 如何检查 HTML 文件的语法是否正确?

javascript - Node 和 Socket.IO - 私有(private)聊天(一对一)

c++ - srand(1) 和 srand(0) 有什么区别

c - 使用文件结构 c 将数据从一个程序移动到另一个程序