Почему мой интерфейс сокета перестает регистрироваться при вызове select ()? - PullRequest
1 голос
/ 14 декабря 2011

Я написал программу для приема соединений через сокеты TCP (код сервера и клиента ниже) для машины с Linux 2.6.14.Мой дизайн предназначен для игнорирования одних (сокетных) входов и ответа на другие.Проблема в том, что для кода, который я написал, когда я игнорирую (не отвечаю), моя select(2) функция не видит больше данных.

Итак, в приведенном ниже примере, как только я отправляю команду t, сервер, похоже, перестает слышать действия на экземпляре порта.До того момента, когда я отправлю команду t, сервер ответит своим Ok..Код сервера не заморожен, так как он будет принимать новые экземпляры портов и fork(2), но порт, который он не ответил на команду t (test), по-видимому, заморожен.Почему это так?

Вот моя попытка получить полезный захваченный вывод ...

~/test$ ./client-test 192.168.20.171 48884

Ok.  
Ok.
Ok.t






^Z
[1]+  Stopped                 ./client-test 192.168.20.171 48884
~/test$ ./client-test 192.168.20.171 48884

Ok.
Ok.

Вот код моего сервера (код ошибки и #include s удалены):

#define PORT_NUM 48884
#define CLIENT_CMD_LENGTH  256
static void dostuff(int fd)
{
    char buf[CLIENT_CMD_LENGTH];
    char bye[] = "Bye!", ok[] = "Ok.";
    const struct timeval wait_tv = { .tv_usec = 1000000/20, .tv_sec = 0 };
    fd_set read_fd;

    do
    {
        struct timeval tv;
        int n;

        tv = wait_tv;
        FD_ZERO( & read_fd);

        FD_SET(fd, &read_fd);
        if (select(fd+1, &read_fd, NULL, NULL, &tv)==-1)
        {
            /* error */
        }
        else if (FD_ISSET(fd, & read_fd))
        {
            printf(".\n");
            FD_CLR(fd, & read_fd);
            n = read(fd,buf, (sizeof buf) - 1);

            switch (* buf)
            {
                case 'q': write(fd,bye,sizeof bye);
                          return;
                case 't': break; /* Ignore */
                default:  write(fd, ok, sizeof ok);
                          break;
            }
        }
    } while (1);
    return;
}

static void server_work(void)
{
     int sockfd;
     socklen_t clilen;
     struct sockaddr_in serv_addr, cli_addr;

     sockfd = socket(AF_INET, SOCK_STREAM, 0);
     if (sockfd < 0) return;
     memset((char *) &serv_addr, '\0', sizeof(serv_addr));
     serv_addr.sin_family = AF_INET;
     serv_addr.sin_addr.s_addr = INADDR_ANY;
     serv_addr.sin_port = htons(PORT_NUM);
     if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
          return;
     }
     listen(sockfd,5);
     clilen = sizeof(cli_addr);
     while (1) {
        int newsockfd, pid;
         newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
         if (newsockfd < 0)
             continue;
         pid = fork();
         if (pid < 0)
             break;
         if (pid == 0)  {
             close(sockfd);
             dostuff(newsockfd);
             exit(0);
         }
         else close(newsockfd);
     } /* end of while */
     close(sockfd);
     return; /* we never get here */
}

int main( int argc, char *argv[] ) {
    server_work();
    return 0;
}

и мой тестовый клиент ...

void error(const char *msg)
{
    perror(msg);
    exit(0);
}

int main(int argc, char *argv[])
{
    int sockfd, portno, n;
    struct sockaddr_in serv_addr;
    struct hostent *server;

    char buffer[256];
    if (argc < 3) {
       fprintf(stderr,"usage %s hostname port\n", argv[0]);
       exit(0);
    }
    portno = atoi(argv[2]);
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0)
        error("ERROR opening socket");
    server = gethostbyname(argv[1]);
    if (server == NULL) {
        fprintf(stderr,"ERROR, no such host\n");
        exit(0);
    }
    bzero((char *) &serv_addr, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    bcopy((char *)server->h_addr,
         (char *)&serv_addr.sin_addr.s_addr,
         server->h_length);
    serv_addr.sin_port = htons(portno);
    if (connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0)
        error("ERROR connecting");
    do {
    bzero(buffer,256);
    fgets(buffer,255,stdin);
    n = write(sockfd,buffer,strlen(buffer));
    if (n < 0)
         error("ERROR writing to socket");
    bzero(buffer,256);
    n = read(sockfd,buffer,255);
    if (n < 0)
         error("ERROR reading from socket");
    printf("%s",buffer);
    } while (*buffer != 'B');
    close(sockfd);
    return 0;
}

1 Ответ

2 голосов
/ 14 декабря 2011

Это потому, что ваш клиент блокирует чтение сразу после того, как он выполняет свою запись, в то время как сервер ничего не отправляет обратно при получении t и просто возвращается к select(2). Классический тупик.

Либо пропустите чтение на клиенте после отправки команд, которые сервер игнорирует, либо всегда отправляйте подтверждение с сервера.

Примечание: вы предполагаете, что получатель получает точно такой же фрагмент данных, который отправляет отправитель. Неправильно. TCP является байтовым потоком и не сохраняет каких-либо границ сообщений уровня приложения. Вы должны беспокоиться о них сами. Два распространенных способа борьбы с ним: 1) разделители сообщений, такие как нулевой байт или что-то в этом роде, и 2) предварительное ожидание каждого сообщения с его размером.

Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...