2011-12-23 4 views
6

Я пытаюсь написать простые клиентские и серверные C-программы, обменивающиеся друг с другом в отдельных терминалах.Правильное соединение клиент-сервер FIFO

Серверу необходимо создать публичный fifo и ждать клиента. Между тем клиент создает свой собственный fifo, через который придет ответ сервера. Задача клиента - отправить серверу имя, созданное в очередь, и получить в результате результат команды ls.

Я искал ответ, например: fifo-server-program, example-of-using-named-pipes-in-linux-bash, how-to-send-a-simple-string-between-two-programs-using-pipes. Я начал с кода из третьей ссылки и медленно менял его.

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

EDIT: У меня это работает! : D Коды ниже, возможно, это поможет кому-то.

server.c код:

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

int main(int argc, char* argv[]) 
{ 
    int fds[2]; 
    char tab[BUFSIZ]; 
    int fd, n; 

    char *myfifo = "/tmp/serwer"; 
    char *myfifo2 = "/tmp/client"; 

    pipe(fds); 
    mkfifo(myfifo,0666); 

    while(1) 
    { 
     fds[0]=open(myfifo2,O_RDONLY); 
     fds[1]=open(myfifo,O_WRONLY); 

     read(fds[0],tab,BUFSIZ); 

     if (strcmp("klient",tab)==0) { 
      printf("Od klienta: %s\n",tab); 
      fd=open(tab,O_WRONLY); 

      if(fork()==0) 
      { 
       dup2(fds[1],1); 
       close(fds[1]); 
       execlp("ls","ls","-l",NULL); 
       close(fds[0]); 
       close(fds[1]); 
      } 
      else 
      { 
       dup2(fds[0],0); 
       n = read(fds[0],tab,BUFSIZ); 
       write(fd,tab,n); 
       close(fds[0]); 
       close(fds[1]); 
      } 
     } 
     memset(tab, 0, sizeof(tab)); 
     close(fd); 
     close(fds[0]); 
     close(fds[1]); 
    } 

    unlink(myfifo); 
    return 0; 
} 

client.c код:

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

int main(int argc, char* argv[]) 
{ 
    int fds[2]; 
    char *myfifo = "/tmp/serwer"; 
    char *myfifo2 = "/tmp/client"; 

    mkfifo(myfifo2,0666); 
    fds[0]=open(myfifo,O_RDONLY); 
    fds[1]=open(myfifo2,O_WRONLY); 

    char tab[BUFSIZ]; 
    memset(tab, 0, sizeof(tab)); 

    write(fds[1],"klient",6); 
    perror("Write:"); //Very crude error check 
    read(fds[0],tab,sizeof(tab)); 
    perror("Read:"); // Very crude error check 

    printf("Odebrano od serwera: %s\n",tab); 

    close(fds[0]); 
    close(fds[1]); 
    unlink(myfifo2); 
    return 0; 
} 
+1

Это не очевидно из этого кода. Вы получили работу ls, или вы просто отправляете небольшие сообщения? Обычная ошибка в этом сценарии заключается в том, что вы зашли в тупик, то есть сервер ожидает ввода, пока клиент ждет ввода. Они ждут вечно, потому что никто ничего не посылает. – Duck

+0

Нет, команда ls пока не работает. Эти программы работают один раз - сервер ждет сообщения, возвращает его клиенту, клиент может закрыть. Когда я хочу отправить другое сообщение, клиент и сервер перестанут отвечать на запросы. – uluroki

ответ

5

Почему вы не просто управлять как ФИФО сервера в сервере? Простое изменение кода для этого делает его работу корректно.

Если вы действительно хотите иметь отношения клиент-сервер, с сервером, обслуживающим множество разных клиентов, сокеты, вероятно, будут лучшим выбором.

client.cpp

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

int main() 
{ 
    int client_to_server; 
    char *myfifo = "/tmp/client_to_server_fifo"; 

    int server_to_client; 
    char *myfifo2 = "/tmp/server_to_client_fifo"; 

    char str[BUFSIZ]; 
    printf("Input message to serwer: "); 
    scanf("%s", str); 


    /* write str to the FIFO */ 
    client_to_server = open(myfifo, O_WRONLY); 
    server_to_client = open(myfifo2, O_RDONLY); 
    write(client_to_server, str, sizeof(str)); 

    perror("Write:"); //Very crude error check 

    read(server_to_client,str,sizeof(str)); 

    perror("Read:"); // Very crude error check 

    printf("...received from the server: %s\n",str); 
    close(client_to_server); 
    close(server_to_client); 

    /* remove the FIFO */ 

    return 0; 
} 

server.cpp

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

int main() 
{ 
    int client_to_server; 
    char *myfifo = "/tmp/client_to_server_fifo"; 

    int server_to_client; 
    char *myfifo2 = "/tmp/server_to_client_fifo"; 

    char buf[BUFSIZ]; 

    /* create the FIFO (named pipe) */ 
    mkfifo(myfifo, 0666); 
    mkfifo(myfifo2, 0666); 

    /* open, read, and display the message from the FIFO */ 
    client_to_server = open(myfifo, O_RDONLY); 
    server_to_client = open(myfifo2, O_WRONLY); 

    printf("Server ON.\n"); 

    while (1) 
    { 
     read(client_to_server, buf, BUFSIZ); 

     if (strcmp("exit",buf)==0) 
     { 
     printf("Server OFF.\n"); 
     break; 
     } 

     else if (strcmp("",buf)!=0) 
     { 
     printf("Received: %s\n", buf); 
     printf("Sending back...\n"); 
     write(server_to_client,buf,BUFSIZ); 
     } 

     /* clean buf from any data */ 
     memset(buf, 0, sizeof(buf)); 
    } 

    close(client_to_server); 
    close(server_to_client); 

    unlink(myfifo); 
    unlink(myfifo2); 
    return 0; 
} 
4

Он работает только один раз из-за того, как работают именованные каналы. Каждый раз, когда вы open именованный канал для чтения вы блокируете до тех пор, пока другой процесс не откроет его для записи. Затем вы соединяетесь и файловый дескриптор соединяет ваши процессы. Как только конец завершает это соединение, это конец этого канала. Для того, чтобы ваш сервер «принял другое соединение», ему необходимо переместить open и close труб в его основной цикл, чтобы он мог снова и снова соединяться.

Смежные вопросы