传入连接如何停止选择等待?

时间:2015-03-27 21:16:40

标签: c

如示例所示,select监视侦听传入连接的服务器的套接字。我使用telnet来测试程序。在程序中,当有listener套接字读取内容时,select应该停止等待。我猜测telnet可能会向服务器发送消息并试图读取它,但我什么也没得到。实际上,当我尝试从telnet读取消息时,程序停止接受新连接。我注释掉了阅读代码的消息。有人可以解释为什么选择在有新连接时停止等待吗?

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/time.h>

#include "../cus_header/cus_header.h"

#define PORT "30000"  // the port users will be connecting to
#define MY_IP "127.0.0.1"
#define BACKLOG 10   // how many pending connections queue will hold
#define MAXLEN 1000

void *get_client_addr(struct sockaddr * sa){
    if(sa->sa_family == AF_INET){
        return &(((struct sockaddr_in *)(sa))->sin_addr);

    }

    return &(((struct sockaddr_in6 *)(sa))->sin6_addr);

}


int main(int argc, char *argv[]){

    struct addrinfo hints, *res, *p;
    struct sockaddr_storage client_addr;
    int client_add_len;
    char client_ip[INET6_ADDRSTRLEN];
    int a;
    int listener, new_fd;
    int yes = 1;
    socklen_t c_addr_size;
    char msg [] = "Hello client\n"; // message to the client
    char *msg_p;
    int msg_len = strlen(msg);



    // load data to struct addrinfo
    memset(&hints, 0, sizeof(hints));
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;

    //create socket
    if((a = getaddrinfo(MY_IP, PORT, &hints, &res)) == -1){
        fprintf(stderr, "Cannot get address info: %s", gai_strerror(a));
        return 1;
    }

    p = res;

    // loop through all the results
    for(p = res; p != NULL; p = p->ai_next){
        // create socket
        if((listener = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1){
            printf("cannot create the socket\n");
            continue;
        }

        if(setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1){
            error("cannot set reused for the socket");

        }
        // bind socket to port
        if(bind(listener, p->ai_addr, p->ai_addrlen) == -1){
            printf("cannot bind the socket\n");
            continue;
        }

        break;

    }

    if(p == NULL){
        error("Cannot create socket or bind the socket to the port");
    }

    freeaddrinfo(res);

    // listen incoming connections
    if(listen(listener, BACKLOG) == -1){
        error("Cannot listen to connection");
    }

    // ready to communicate
    puts("Waiting for connection ...");


    fd_set master_set, copy_master_set;
    int fd_max;

    int client_fd[20]; // store all the new fd here
    // accept connection and talk with clients


    while(1){

        FD_ZERO(&master_set);
        FD_SET(listener, &master_set);
        fd_max = listener;
        copy_master_set  = master_set;

        if(select(fd_max + 1, &copy_master_set, NULL, NULL, NULL) == -1){
            error("Select");
        }

        int i;
        // set all the available client fd
        for(i = 0;i <= fd_max; i++){
            if(FD_ISSET(i, &copy_master_set)){
                if(i == listener){
                    // got a new connection
                    client_add_len = sizeof client_addr;
                    if((new_fd = accept(listener, (struct sockaddr *)&client_addr, &client_add_len)) == -1){
                       error("New connection");
                    }

                    FD_SET(new_fd, &master_set);
                    if(new_fd > fd_max){
                        fd_max = new_fd;
                    }

                    printf("New connection from %s on socket %i\n",
                           inet_ntop(client_addr.ss_family, get_client_addr((struct sockaddr *)&client_addr), client_ip, INET6_ADDRSTRLEN),
                           new_fd);
                    /*
                    char buf[MAXLEN];
                    int b;
                    if((b=recv(listener, buf, MAXLEN, 0)) == -1){
                        error("read message");
                    }else if(b == 0){
                        printf("Message from client: %s", buf);
                    }

                    printf("Message from client: %s", buf);
                    */
                }else{
                // handle clients


                }

            }

        }


    }


    return 0;
}

1 个答案:

答案 0 :(得分:0)

从选择的手册页:

DESCRIPTION
       select() and pselect() allow a program to monitor multiple file
       descriptors, waiting until one or more of the file  descriptors
       become  "ready"  for  some  class of I/O operation (e.g., input
       possible).  A file descriptor is considered ready if it is pos-
       sible   to  perform  the  corresponding  I/O  operation  (e.g.,
       read(2)) without blocking.

在这种情况下,当套接字接收到传入连接时,文件描述符就绪,并且可以执行accept(2)的相应I / O操作。