使用select()进行非阻塞I / O

时间:2013-10-15 09:56:39

标签: c sockets select nonblocking

有人可以告诉我为什么以下代码不起作用吗?

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <sys/select.h>
#include <sys/time.h>
#include <errno.h>

int main(int argc, char **argv)
{
    int sockfd, i, new = 0, maxfd, nready, on = 1;
    struct sockaddr_in saddr;
    ssize_t nbytes;
    fd_set rfds, master;
    char buffer[BUFSIZ];

    if(-1 == (sockfd = socket(PF_INET, SOCK_STREAM, 0)))
    {
        perror("socket()");
        exit(EXIT_FAILURE);
    }

    if(-1 == (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on))))
    {
        perror("setsockopt()");
        exit(EXIT_FAILURE);
    }

    if(-1 == (fcntl(sockfd, F_SETFD, O_NONBLOCK)))
    {
        perror("fcntl()");
        close(sockfd);
        exit(EXIT_FAILURE);
    }

    (void)memset(&saddr, '\0', sizeof(struct sockaddr_in));

    saddr.sin_port = htons(1234);
    saddr.sin_addr.s_addr = htonl(INADDR_ANY);
    saddr.sin_family = AF_INET;

    if(-1 == (bind(sockfd, (struct sockaddr*)&saddr, sizeof(saddr))))
    {
        perror("bind()");
        close(sockfd);
        exit(EXIT_FAILURE);
    }

    if(-1 == (listen(sockfd, 32)))
    {
        perror("listen()");
        close(sockfd);
        exit(EXIT_FAILURE);
    }

    FD_ZERO(&rfds);
    FD_ZERO(&master);
    maxfd = sockfd;
    FD_SET(sockfd, &master);

    printf("maxfd = %d\n", maxfd);

    for(;;)
    {
        (void)printf("select()ing...\n");

        (void)memcpy(&rfds, &master, sizeof(master));

        if(-1 == (nready = select(maxfd+1, &rfds, NULL, NULL, NULL)))
        {
            perror("select()");
            close(sockfd);
            exit(EXIT_FAILURE);
        }

        for(i=0; i<FD_SETSIZE; i++)
        {
            if(FD_ISSET(i, &rfds))
            {
                if(i == sockfd)
                {
                    (void)printf("trying to accept new connection(s)\n");

                    for(;;)
                    {
                        new = accept(sockfd, NULL, NULL);

                        if(new < 0)
                        {
                            if(errno != EWOULDBLOCK)
                            {
                                perror("accept()");
                                exit(EXIT_FAILURE);
                            }

                            /* no incomming connection */
                            break;
                        }

                        FD_SET(new, &master);

                        if(maxfd < new)
                            new = maxfd;

                        (void)printf("%d was added to set\n", new);

                    }

                }

                else
                {
                    for(;;)
                    {
                        (void)printf("trying to read data from ready socket(s)\n");

                        while((nbytes = recv(i, buffer, sizeof(buffer), 0)) > 0)
                            printf("%s", buffer);

                        if(nbytes < 0)
                        {
                            if(nbytes != EWOULDBLOCK)
                            {
                                perror("recv()");
                                exit(EXIT_FAILURE);
                            }

                            break;
                        }

                        if(0 == nbytes)
                        {
                            close(i);
                            break;
                        }

                        FD_CLR (i, &master);
                    }

                }


            }
        }


    }

    return 0;
}

它侦听*:1234以获取新连接。它构建良好,没有任何错误或警告,但它不能从准备描述符recv()数据。我找不到问题的根源,有人可以帮助我吗?

1 个答案:

答案 0 :(得分:1)

问题是读取循环,当你读取你收到的字节时,但是当你完成后,你会尝试再次接收,使recv阻止。您需要使套接字无阻塞。不,阻塞/非阻塞状态从被动侦听套接字继承。