2015-12-02 6 views
1

Я создаю программу на C с базами клиент-сервер.Перенаправление stdin с FIFO (pipe names)

Я пытаюсь перенаправить stdin на именованный канал, который я создал, и мне удалось разместить клиента в трубку. На стороне сервера я открыл ту же трубку, закрыл stdin и перенаправил stdin, используя dup (также с dup2), в трубу.

Мне нужно прочитать ввод с помощью функции getline. Проблема в том, что он правильно считывает первый ввод, но получает после него только нули. Я добавлю образец к вопросу.

сервер:

#include <sys/types.h> 
#include <sys/stat.h> 
#include <fcntl.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <errno.h> 


main() { 
    char* str; 
    size_t size=0; 
    int pshell_in; 

    unlink("/tmp/par-shell-in"); 
    if(mkfifo("/tmp/par-shell-in", 0777) < 0){ 
     fprintf(stderr, "Error: Could not create pipe\n"); 
     exit(-1); 
    } 

    if((pshell_in = open("/tmp/par-shell-in", O_CREAT | O_RDONLY, S_IRUSR)) < 0){ 
     fprintf(stderr, "Error: Failed to open file\n"); 
     exit(-1); 
    } 

    dup2(pshell_in, 0); 
    close(pshell_in); 



    while(1) { 
     if (getline(&str, &size, stdin)<0) { 
      printf("Oh dear, something went wrong with getline()! %s\n", strerror(errno)); 
      return -1; 
     } 

     printf("%s", str); 
    } 
} 

* Я знаю свою пустую причину я печатал с чтения (вместо того, чтобы перенаправлять) и печатает (нуль).

клиент:

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <sys/stat.h> 
#include <string.h> 
#include <fcntl.h> 

#define VECTORSIZE 7 

int main() { 

    char* buf; 
    int pshell_in; 
    size_t size=0; 

    if((pshell_in = open("/tmp/par-shell-in", O_WRONLY, S_IWUSR)) < 0){ 
     fprintf(stderr, "Error: Failed to open file\n"); 
     exit(-1); 
    } 

    printf("%d\n", pshell_in); 

    while(1) { 
     if (getline(&buf, &size, stdin) < 0) { 
      return -1; 
     } 

     write(pshell_in, buf, 256); 
    } 
} 
  • Я подозреваю, его право, потому что, если я использую чтение на стороне клиента (заменяющий O_WRONLY с O_RDWR) печатает строку, как я напечатал его.

Может ли кто-нибудь помочь мне с этим?

ответ

2

FIFO - забавные вещи. Если процесс пытается открыть его для чтения, он будет блокироваться, пока не появится процесс, который открывает его для записи. И наоборот, если процесс пытается открыть его для записи, он будет блокироваться, пока не появится процесс, который откроет его для чтения. Однако несколько процессов могут открывать его для чтения или записи. Когда больше нет процессов, открытых для чтения, записи будут терпеть неудачу; когда больше нет процессов, открытых для записи, чтения будут терпеть неудачу. И когда операции не выполняются, вам необходимо закрыть и снова открыть FIFO, чтобы продолжить обработку данных заново.

Я сильно подозреваю, что вы столкнулись с проблемами из-за этих поведений.

Кроме того, ваш код для написания кода сомнительный; вы не обращаете внимания на то, сколько данных было прочитано. У вас есть:

while(1) { 
    if (getline(&buf, &size, stdin) < 0) { 
     return -1; 
    } 
    write(pshell_in, buf, 256); 
} 

Если, как вероятно, вы читали меньше, чем 256 символов ввода в строке, то это вполне возможно, что вы идете писать за пределы массива, который был выделен на getline(). Также очевидно, что некоторые или даже большинство из этих данных являются нулевыми байтами. Тем не менее, (null), который вы видите на сервере, обычно указывает, что вы пытаетесь напечатать строку, но передали printf() нулевой указатель. Что бы ни происходило, большинство из них - это неопределенное поведение, которое является Bad Thing ™, и его следует избегать любой ценой.

Вы должны иметь нечто большее, как:

ssize_t nbytes; 

while ((nbytes = getline(&buf, &size, stdin)) > 0) 
{ 
    if (write(pshell_in, buf, nbytes) != nbytes) 
    { 
     fprintf(stderr, "Short write to FIFO\n"); 
     break; 
    } 
} 
free(buf); 

Обратите внимание, как это только пишет столько данных, сколько было прочитано и не предполагает, что 256 байт были доступны для записи.