select()方法不返回,因此阻塞

时间:2013-12-30 10:21:49

标签: c sockets nonblocking

我是网络编程的初学者。我做了一个简单的UDP服务器和UDP客户端。客户端将消息发送到服务器,服务器打印消息。 一旦客户端停止发送消息,则recvfrom方法被阻止。因此,我尝试使用fcntlselect创建一个非阻塞套接字,但它无效。 以下是我的UDP服务器代码。

#include "udpserver.h"

void start_udp_server(int PORT)
{
    struct sockaddr_in server_addr ;
    sock_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

    FD_ZERO(&master_fds);
    FD_SET(sock_fd, &master_fds);

    bzero(&server_addr, sizeof(server_addr));
    server_addr.sin_family = AF_INET ;
    server_addr.sin_addr.s_addr = htonl(0);
    server_addr.sin_port = htons(PORT);


    // bind the address with the socket
    if (bind(sock_fd, (struct sockaddr *)&server_addr, sizeof(server_addr))<0)
        fprintf(stderr , "error binding the socket to the address\n");
    else
    {
        fprintf(stderr , "bind successful...\n");
        fflush(stdout);
    }


    if (fcntl(sock_fd, F_GETFL) & O_NONBLOCK)
    {
        printf("\nsocket is non-blocking");
    }

    int r =  fcntl(sock_fd, F_SETFL, fcntl(sock_fd, F_GETFL) | O_NONBLOCK);


    printf("r = %d",r);
    if (r < 0)
    {
        printf("error making the socket non-blocking %d",r);
    }

    if (fcntl(sock_fd, F_GETFL) & O_NONBLOCK)
    {
        printf("\nsocket is non-blocking");
    }

    fprintf(stderr , "server listening on port %d %s\n",ntohs(server_addr.sin_port) ,inet_ntoa(server_addr.sin_addr));
    fflush(stdout);

}

int receive_udp_msg()
{
    socklen_t lengthOfClientAddress  = sizeof(client_addr);
    int activity = 0 ;
    int l = 0 ;

    FD_ZERO(&read_fds);
    memcpy(&read_fds, &master_fds, sizeof(master_fds));

    printf("before select\n");
    activity = select(sock_fd + 1 , &read_fds, NULL, NULL, NULL);
    printf("after select\n");
    if (FD_ISSET(sock_fd, &read_fds))
    {
        printf("----activity happened on sock_fd\n");
        l = (int)recvfrom(sock_fd, buffer, 1000, 0, (struct sockaddr *)&client_addr , &lengthOfClientAddress) ;
        printf("received msg\n");
        if (l == - 1)
        {
            fprintf(stderr , "there was error \n");
            fflush(stdout);
            return -1 ;
        }

    }

    return l ;
}

int main()
{
   start_udp_server ;
   int l = 0 ;
   while(1)
   {
     l = receive_udp_msg();
     if(l > 0 )
       print("message received : %s",buffer);
   }

}

当客户端停止发送消息时,程序会打印before select,之后不会打印任何内容。

1 个答案:

答案 0 :(得分:3)

因为您对传递给timeout的{​​{1}}指针使用NULL值,所以调用将阻塞,直到有套接字活动。

select

activity = select(sock_fd + 1 , &read_fds, NULL, NULL, NULL); ^ ^ 的手册页对此进行了详细说明。如果您不想这样做,请向select调用一个非空指针,该指针指向填充了所需超时值的select结构。