c - 为什么选择报告读取文件描述符不断准备就绪?

标签 c linux select

为了测试select系统调用,我写了一个程序从客户端接收数据:

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/time.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <libgen.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include <errno.h>

#define BACKLOG 5

int main(int argc, char *argv[])
{
    if (argc <= 2)
    {
        printf("Usage: %s ip_address port_number\r\n", basename(argv[0]));
        return 1;
    }
    const char *ip = argv[1];
    int port = atoi(argv[2]);

    int ret = 0;
    struct sockaddr_in address;
    memset(&address, 0, sizeof(address));
    address.sin_family = AF_INET;
    inet_pton(AF_INET, ip, &address.sin_addr);
    address.sin_port = htons(port);

    int listenfd = socket(AF_INET, SOCK_STREAM, 0);
    assert(listenfd != -1);
    ret = bind(listenfd, (struct sockaddr *)&address, sizeof(address));
    assert(ret != -1);
    ret = listen(listenfd, BACKLOG);
    assert(ret != -1);

    struct sockaddr_in client_address;
    socklen_t client_addrlen = sizeof(client_address);
    int connfd = accept(listenfd, (struct sockaddr *)&client_address, &client_addrlen);
    if (connfd < 0)
    {
        printf("accept failed! errno is %d\r\n", errno);
        close(listenfd);
    }
    else
    {
        printf("accept success!\r\n");
    }

    char buf[1024];
    fd_set read_fds;
    fd_set exception_fds;
    FD_ZERO(&read_fds); 
    FD_ZERO(&exception_fds);

    while (1)
    {
        memset(buf, 0, sizeof(buf));
        FD_ZERO(&read_fds);
        FD_ZERO(&exception_fds);
        FD_SET(connfd, &read_fds);
        FD_SET(connfd, &exception_fds);
        ret = select(connfd + 1, &read_fds, 0, &exception_fds, NULL);
        if (ret < 0)
        {
            printf("selection failed!\r\n");
            break;
        }
        if (FD_ISSET(connfd, &read_fds))
        {
            ret = recv(connfd, buf, sizeof(buf)-1, 0);
            if (ret < 0)
            {
                break;
            }
            printf("received %d bytes of normal data: %s\r\n", strlen(buf), buf);
        }
        else if (FD_ISSET(connfd, &exception_fds))
        {
            ret = recv(connfd, buf, sizeof(buf)-1, MSG_OOB);
            if (ret < 0)
            {
                break;
            }
            printf("received %d bytes of oob data: %s\r\n", strlen(buf), buf);
        }
    }

    close(connfd);
    close(listenfd);
    return 0; 
}

但是,当我从客户端程序发送数据时,上面的服务器程序打印如下: 接受成功!

received 16 bytes of normal data: thisisnormaldata
received 0 bytes of normal data: 
received 0 bytes of normal data: 
received 0 bytes of normal data: 
received 0 bytes of normal data: 
received 0 bytes of normal data: 
received 0 bytes of normal data: 
received 0 bytes of normal data: 
received 0 bytes of normal data: 
received 0 bytes of normal data: 
received 0 bytes of normal data: 
received 0 bytes of normal data: 
received 0 bytes of normal data: 
received 0 bytes of normal data: 
received 0 bytes of normal data: 
received 0 bytes of normal data: 
received 0 bytes of normal data: 
received 0 bytes of normal data: 
received 0 bytes of normal data: 
received 0 bytes of normal data: 
received 0 bytes of normal data: 
received 0 bytes of normal data: 
received 0 bytes of normal data: 
received 0 bytes of normal data: 
received 0 bytes of normal data: 
received 0 bytes of normal data: 
received 0 bytes of normal data: 
received 0 bytes of normal data: 
received 0 bytes of normal data:

(没完没了的“收到o字节的正常数据”)

为什么select系统调用一直报告read fds are ready?

最佳答案

select() 报告您的 FD 一直就绪,因为它一直就绪。它不会阻塞(我想)。

根据 recv() 的文档摘录,考虑不断打印的消息的含义:

Upon successful completion, recv() shall return the length of the message in bytes. If no messages are available to be received and the peer has performed an orderly shutdown, recv() shall return 0.

由于您使用的是流套接字,它确实可以判断另一端何时执行了有序关闭。你的程序告诉你那是发生了什么。只要你问,它愿意告诉你多少次。对于您的程序来说,比再次重复询问更典型的响应是关闭连接的本地端并继续处理其他事情(例如处理其他连接)。

可能你想要 select() listenfd 文件描述符来等待后续连接,虽然我看不出这对你有什么好处,因为此时您没有任何其他工作要做,所以仅执行阻塞 accept() 将是一个问题。

关于c - 为什么选择报告读取文件描述符不断准备就绪?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31232749/

相关文章:

mysql - 对两个 MySQL 查询执行左外连接?

c++ - 理解 UMDH 比较输出

c++ - C 预处理器扩展到另一个类似对象的宏

linux - 分析系统调用

MySQL SELECT 返回字段值发生变化的行

javascript - 如何使用 select2 或任何其他 js 在 select 中搜索选项值

c - 在循环内 fork ,变量随每次迭代而变化

c - 如何使用指针和 malloc 将字符存储到数组中?

linux - 从内核模块读取 dmesg

c - 在 C 中通过串行端口发送十六进制值