Функция getline () ведет себя странно - PullRequest
2 голосов
/ 03 августа 2011

Я пытаюсь эмулировать функциональность telnet, написав программу для прослушивания сокетов и приложение, перенаправляющее консоль в слушатель через сокеты.

На стороне сервера я открыл сокет на своем локальном ip, определенный порт, и начал слушать его следующим образом

sockfd = socket(AF_INET,SOCK_STREAM,0);
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
bind(sockfd,(struct sockaddr*)&serv_addr,sizeof(serv_addr);
listen(sockfd,5);
neewsockfd = accept(sockfd,(struct sockaddr*)&cli_addr,&clien);

Затем я начал читать входящие данные в отдельном потоке, например:

while(1)
{
  bzero(buffer,256);
  n= read(newsockfd,buffer,255);
  if(n>0)
     printf("%s",buffer);
}  

И в основной процедуре после кода прослушивания я добавил следующую часть для отправки данных сокета.

while(1)
{
   bzero(buffer,256);
   getline(&buffer,&t,stdin);
   n=send(newsockfd,buffer,strlen(buffer),MSG_EOR);
}

А для клиентской части я подключился к серверу вот так.

sockfd = socket(AF_INET,SOCK_STREAM,0);
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
inet_pton(AfF_INET,hostip,&serv_addr.sin_addr.s_addr)
serv_addr.sin_port = htons(portno);
connect(sockfd,serv_addr,sizeof(serv_addr));

А затем я скопировал stdin, stdout и stderr в дескриптор sockfd для перенаправления консоли следующим образом.

 dup2(sockfd,STDIN_FILENO);
 dup2(sockfd,STDOUT_FILENO);
 dup2(sockfd,STDERR_FILENO);

 close(sockfd);

И, наконец, у меня есть что-то подобное в клиенте для проверки перенаправления консоли

while(1)
{
   bzero(mystring,256);
   i = getline(&string,&t,stdin);
   printf("Input:%s-%d\n",mystring,i);
}

В приведенном выше коде я ожидаю, что getline будет заблокирован до тех пор, пока я не введу некоторые символы в консоли приложения сервера, но для моей агонии он неоднократно выдает значение 0.

Есть идеи, почему такое поведение?

1 Ответ

2 голосов
/ 03 августа 2011

Смешивание сокетов с stdio(3) - плохая идея TM . И stdin, и stdout имеют линейную буферизацию , см. setbuf(3), и это, вероятно, то, что вас сюда привело. Существует также вопрос безопасности потоков - потоки stdio заблокированы, но поскольку вы уже используете расширения GNU, вы можете попробовать их разблокированные аналоги.

Редактировать 0:

Исходя из вашего вклада в комментарии, я думаю, что это было бы решением:

  • создайте pipe(2) в родительском процессе перед выполнением fork(2)
  • в процессе построения dup2(2) дескриптор файла чтения канала в STDIN после fork(2), но до execve(2)
  • во вновь exec -детском процессе просто прочитайте стандартный ввод
  • в родительском процессе копирование стандартного ввода в дескриптор файла записи канала.

Это должно избежать большей части путаницы.

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