【问题标题】:Select system call not scanning more than 2 descriptors选择系统调用不扫描超过 2 个描述符
【发布时间】:2017-11-05 17:52:04
【问题描述】:

我正在编写一个服务于多个客户端(最多 5 个)的服务器程序。当任何客户端连接到服务器时,服务器将描述符存储到一个数组中,并通过 Select 系统调用检查这些描述符中的任何活动。但是,它只从任何 2 个客户端读取,并且根本不服务其余客户端请求。这是服务器的代码

#define NUM_CLIENT 5

void main(int argc,char** argv)
{
 int master_sock, newSocket, err;
 struct sockaddr_in Server_addr, Client_addr;
 char buf[100]; 
 int i=0;
 int activity;

 //socket descriptors for select
 fd_set readfd;
 int client_fd[NUM_CLIENT]={-1,-1,-1,-1,-1};    

 //Socket creation
 master_sock= socket(AF_INET,SOCK_STREAM,0);
 if(master_sock<0){
    perror("socket");
    return;
 }

 //structure filling for listening to the port
 Server_addr.sin_family = AF_INET;
 Server_addr.sin_port = htons(atoi(argv[1]));
 Server_addr.sin_addr.s_addr = INADDR_ANY;

 //Binding to the Address and port filled in structure
 err = bind(master_sock,(struct sockaddr*)&Server_addr,sizeof(Server_addr));
 if(err<0){
    perror("socket");
    return;
 }

 printf("\nlistening to port");
 err = listen(master_sock,NUM_CLIENT);  //to inform, the willlingness to accept connections.
 if(err<0){
    perror("Listen");
    return;
 }
 printf("\nAccepting connection");

 while(1)
 {
    //Select modifies the objects in structure for any activity,
    // So we need to load them again.
    FD_ZERO(&readfd);   //clearing the readfd list
    FD_SET(master_sock,&readfd);    //adding the descriptor for select to listen

    for(i=0;i<NUM_CLIENT;i++){      
        if(client_fd[i] != -1){
            FD_SET(client_fd[i],&readfd);   //Add socket to the list

        }           
    }
    //Descriptors loaded..

    //start Select operation....

    activity = select(NUM_CLIENT+1,&readfd,NULL,NULL,NULL); //wait here until any activiy occurs
    if(activity < 0){
        perror("Select");break;
    }
    printf("\nactivity happened in socket...");

    //If activity related to master socket i.e. New client is trying to connect.
    if( FD_ISSET(master_sock,&readfd) ) {
        printf("\nactivity in master socket...");
        int len = sizeof(Client_addr);

        //Accept the connection
        newSocket = accept(master_sock, (struct sockaddr*)&Client_addr ,&len);  //blocking call
        if(newSocket<0){
            perror("accept");return;
        }
        printf("\nNew connection accepted");    

 //     puts("Receiving data");
        if( recv(newSocket,buf,100,0) > 0 )     //blocking call
            printf("\n%s",buf);
        else
            strcpy(buf,"hey");

//      puts("Sending data");   
        if( send(newSocket,buf,strlen(buf),0) < 0 )
            perror("send");


        //creating client database of descriptors
        for(i=0;i<NUM_CLIENT;i++){
            printf("\nfd[%d] = %d\n",i,client_fd[i]);           
            if(client_fd[i] == -1){
                client_fd[i]= newSocket;
                //FD_SET(newSocket,&readfd);    //Add socket to the list
                //printf("\nfd[%d] = %d\n",i,client_fd[i]);         
                break;
            }

        }

    }

    //If activity(read or write) in other sockets, check it out
    printf("\nChecking Activity in Other File Descriptors\n");
    for(i=0;i<NUM_CLIENT;i++){

        if(FD_ISSET(client_fd[i],&readfd)){

            printf("\nactivity in client %d ...",i);
 //     puts("Receiving data");
            if( recv(client_fd[i],buf,100,0) > 0 )  //blocking call
                puts(buf);  
            else
                strcpy(buf,"hello");
 //     puts("Sending data");   
            if( send(client_fd[i],buf,strlen(buf)+1,0) == -1 )
                perror("send");
                //printf("\n%s",buf);
        }

    }



  }



 }

每个客户端在给定时间休眠后发送和接收数据(通过命令行提供)。示例:client1 5sec ,client2 4sec 等等...

客户端的代码是:

void main(int argc, char** argv)
{
 int fd, err;
 char buf[100],buf2[100];
 struct sockaddr_in server;

 fd = socket(AF_INET,SOCK_STREAM,0);
 if(fd<0){
    perror("socket");return;
 }

I2A(buf,getpid());  //Integer to array conversion, returns array
strcat(buf,"Hello");

printf("%s\n",buf);
server.sin_family = AF_INET;
server.sin_port = htons(atoi(argv[1])); //Host to network
server.sin_addr.s_addr = inet_addr("127.0.0.1");
printf("Connecting with server\n");
if( connect(fd, (struct sockaddr*)&server,sizeof(server) ) < 0) {
    perror("connect");return;
}
printf("Connected with server\n");

while(1){

//  printf("Sending data\n");
 if( send(fd,buf,20,0) < 0)
    perror("send");

 // printf("Receiving data\n"); 
 if( recv(fd,buf2,sizeof(buf2),0) >0 )
    printf("%s\n",buf2);
 sleep(atoi(argv[2]));  
 }

提前致谢。

【问题讨论】:

  • NUM_CLIENT 的名字很糟糕。 listen()的第二个参数是积压队列的长度,不是客户端的数量,和select()的第一个参数没有任何关系。
  • 能否请您指定积压队列的意义,好吗?为什么不能像这里那样是 NUM_client?
  • 文档中已经指定了“积压队列的重要性”,我已经解释了将其称为NUM_CLIENT 有什么问题。我不知道你为什么要我重复一遍。

标签: c linux sockets


【解决方案1】:

这一行是错误的:

activity = select(NUM_CLIENT+1,&readfd,NULL,NULL,NULL); //wait here until any activiy occurs

select() 的第一个参数不应该是 NUM_CLIENT+1,而是最大文件描述符值(在您调用 FD_SET() 的所有文件描述符值中)加一个。

【讨论】:

    猜你喜欢
    • 2014-05-08
    • 2017-02-12
    • 2012-01-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-05
    相关资源
    最近更新 更多