【问题标题】:Select() issue in CC 中的 Select() 问题
【发布时间】:2013-10-14 16:25:03
【问题描述】:

所以这是我的问题,我有一个服务器,它在客户端连接时调用此代码,问题是,一旦客户端调用,它就会进入无限循环,我不知道为什么。我希望代码在 Select 上再次等待另一个客户端连接,但是初始触发器继续导致永无止境的循环。

ONE 客户端连接时输出:

Lets startYOOHELLO WORLD WE MATCH
Lets startYOOHELLO WORLD WE MATCH
...
.
.
.
..

【问题讨论】:

  • 您的套接字是可读的(有一些数据要读取),但组件是否真的从那里读取?
  • @barmatat read 返回客户端发送的“hi”或其他内容,所以我知道这很好,但我希望再次阻止选择,以便它可以等待未来的客户端。相反,根据 GDB,在第二次运行时,尽管没有客户端连接,但它以某种方式认为可以进入选择,而不是等待,然后继续前进,而在初始运行时,它在 Select 中等待
  • 好的,select 说你可以在套接字上执行一个操作,所以我的问题是 - 你确定你做了这个操作,然后再回到 select 调用?我的意思是读取所有数据,直到您在那里读取 0 字节或写入数据等。我在您的代码中看不到这一点。
  • @barmatat 是的,我正在这样做,但现在表明这是不必要的,你可以假设我现在在客户端连接时打印一个 hello world,现在我想再次等待另一个客户端连接,这样我就可以再次打印你好世界
  • 您发布到问题的代码选择了可供读取的套接字(有一些数据)。此代码未显示您如何接受新连接或它如何读取内容。从我的角度来看,它会执行您编写的操作-如果 fd_set 中的套接字已准备好读取,它将处于无限循环中。那么您的问题陈述和您发布的代码不一致。

标签: c sockets serversocket


【解决方案1】:

您陷入无限循环的原因是您的无限循环中的you are not accepting new connections from the clients 以及结构数组are not valid any more 中的文件/套接字描述符,因为那些客户端已终止。选择了一个很差的使用 select 的机制。

你应该这样做:

while(1)
{
    FD_ZERO(&readfds);

    //add master socket to set
    FD_SET(master_socket, &readfds);
    max_sd = master_socket;

    //add child sockets to set
    for ( i = 0 ; i < max_clients ; i++) 
    {
        //socket descriptor
        sd = client_socket[i];

        //if valid socket descriptor then add to read list
        if(sd > 0)
            FD_SET( sd , &readfds);

        //highest file descriptor number, need it for the select function
        if(sd > max_sd)
            max_sd = sd;
    }

    //wait for an activity on one of the sockets , timeout is NULL , so wait indefinitely
    activity = select( max_sd + 1 , &readfds , NULL , NULL , NULL);

    if ((activity < 0) && (errno!=EINTR)) 
    {
        printf("select error");
    }

    //If something happened on the master socket , then its an incoming connection
    if (FD_ISSET(master_socket, &readfds)) 
    {
        if ((new_socket = accept(master_socket, (struct sockaddr *)&address, (socklen_t*)&addrlen))<0)
        {
            perror("accept");
            exit(EXIT_FAILURE);
        }

        //inform user of socket number - used in send and receive commands
        printf("New connection , socket fd is %d , ip is : %s , port : %d \n" , new_socket , inet_ntoa(address.sin_addr) , ntohs(address.sin_port));

        //send new connection greeting message
        if( send(new_socket, message, strlen(message), 0) != strlen(message) ) 
        {
            perror("send");
        }

        puts("Welcome message sent successfully");

        //add new socket to array of sockets
        for (i = 0; i < max_clients; i++) 
        {
            //if position is empty
            if( client_socket[i] == 0 )
            {
                client_socket[i] = new_socket;
                printf("Adding to list of sockets as %d\n" , i);

                break;
            }
        }
    }

    //else its some IO operation on some other socket :)
    for (i = 0; i < max_clients; i++) 
    {
        sd = client_socket[i];

        if (FD_ISSET( sd , &readfds)) 
        {
            //Check if it was for closing , and also read the incoming message
            if ((valread = read( sd , buffer, 1024)) == 0)
            {
                //Somebody disconnected , get his details and print
                getpeername(sd , (struct sockaddr*)&address , (socklen_t*)&addrlen);
                printf("Host disconnected , ip %s , port %d \n" , inet_ntoa(address.sin_addr) , ntohs(address.sin_port));

                //Close the socket and mark as 0 in list for reuse
                close( sd );
                client_socket[i] = 0;
            }

            //Echo back the message that came in
            else
            {
                //set the string terminating NULL byte on the end of the data read
                buffer[valread] = '\0';
                send(sd , buffer , strlen(buffer) , 0 );
            }
        }
    }
}

return 0;
} 

【讨论】:

  • 主套接字的用途是什么?
  • 为什么要使用主套接字
  • @user2879618 这是你传递给bind、listen的socket描述符或者只是socket()返回的socket描述符
【解决方案2】:

如果您的服务器只想接受连接,那么您应该只选择原始套接字 FD。您不应该从接受中选择新的 FD。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-08-06
    • 1970-01-01
    • 2011-02-02
    • 1970-01-01
    • 1970-01-01
    • 2016-05-12
    • 1970-01-01
    相关资源
    最近更新 更多