Почему select () останавливает вывод перед этим? - PullRequest
1 голос
/ 26 марта 2020

Я смотрю на Руководство Биджа по сетевому программированию, пытаясь разобраться с функцией select () в C. Я понял это так, что он останавливает все, что идет после него, до тех пор, пока один из файловых дескрипторов в одном из его наборов не станет доступным из-за каких-то внешних средств (например, te lnet). Но я обнаружил, что если в моей программе есть select () (установлен неопределенный тайм-аут), никакие выходные данные из предыдущих частей программы - например, printf, говорящий о том, что сокет связан - не отображаются, пока не вернется select, но если я закомментирую функцию выбора, то все печатается правильно. Вероятно, это то, о чем я раньше ошибался в своей программе, так что это мой код, который я скопировал, чтобы проверить его:

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>

int main()
{
  //sets the address structure
  struct sockaddr_in server_address;
  server_address.sin_family = AF_INET;
  server_address.sin_port = htons(8888);
  server_address.sin_addr.s_addr = INADDR_ANY;

  fd_set master_fds;
  fd_set read_fds;
  int fdmax;

  int listener;
  int clients[10];

  char buffer[256];

  //zeros the file descriptor lists
  FD_ZERO(&master_fds);
  FD_ZERO(&read_fds);

  //gets a socket and binds it
  listener = socket(AF_INET, SOCK_STREAM, 0);
  bind(listener, (struct sockaddr*)&server_address, sizeof(server_address));
  printf("listener bound")

  //make listener listen
  listen(listener, 10);
  printf("listening");

  //add listener to the faster file descriptor set
  FD_SET(listener, &master_fds);

  fdmax = listener;

  read_fds = master_fds;
  select(fdmax + 1, &read_fds, NULL, NULL, NULL);

  return 0;
}

Это немного грязно, но я просто перепроверил. Когда я компилирую и запускаю это, никакой вывод не отображается до тех пор, пока я не введу lnet, когда все вышеперечисленные printfs будут показаны, и программа завершится. Удаление select () заставляет все показывать, когда это необходимо.

Есть ли веская причина, почему это происходит, или я что-то не так сделал выше?

1 Ответ

3 голосов
/ 26 марта 2020

Это почти наверняка, потому что выходные буферы не очищаются до тех пор, пока после вызова select не вернется. Ваши printf вызовы не заканчиваются символом новой строки \n, поэтому даже для буферизации строки (где она сбрасывается после каждой строки) сбрасывание не происходит.

Если вы пишете в терминал устройство, вы можете просто убедиться, что новая строка отправляется после каждого вывода, и она будет сброшена, что-то вроде:

printf("listener bound\n"); // or
puts("listener bound");

Если вы не хотите новую строку ( a) , или если вы перенаправили вывод так, чтобы он был полностью буферизован, а не буферизован строкой (чтобы символы новой строки не имели эффекта), вам нужно будет fflush(stdout) перед вводом select().


(a) Я подозреваю, что вы делаете , потому что в противном случае вы получите довольно уродливое:

listener boundlistening
...