2011-12-23 23 views
6

Próbuję pisać proste programy klienckie i serwerowe C, komunikując się ze sobą w oddzielnych terminalach.Prawidłowe połączenie klient-serwer FIFO

Serwer musi utworzyć publiczną piątkę i czekać na klienta. W międzyczasie klient tworzy swoją własną piątkę, przez którą przyjdzie odpowiedź serwera. Zadaniem klienta jest wysłanie serwerowi nazwy utworzonej przez kolejkę i uzyskanie wyniku polecenia ls.

Poszukałem odpowiedzi, na przykład: fifo-server-program, example-of-using-named-pipes-in-linux-bash, how-to-send-a-simple-string-between-two-programs-using-pipes. Zacząłem od kodu z trzeciego linku i powoli go zmodyfikowałem.

Co mam teraz, to klient pobierający dane od użytkownika, wysyłający go na serwer i odbierający go z powrotem. Ale działa tylko raz. Nie mam pojęcia dlaczego. Ciało głównej funkcji znajduje się poniżej. Będę wdzięczny za każdą pomoc.

EDYTOWANIE: Mam to działa! : D Kody są poniżej, może to komuś pomóc.

Kod 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; 
} 

Kod 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

Nie wynika to z tego kodu. Czy otrzymałeś wyjście ls działające, czy właśnie wysyłasz krótkie wiadomości? Typową pułapką w tym scenariuszu jest to, że zakleszczenie, tj. Serwer czeka na dane wejściowe, podczas gdy klient oczekuje na dane wejściowe. Czekają na zawsze, ponieważ nikt niczego nie wysyła. – Duck

+0

Nie, polecenie ls nie działa jeszcze. Programy te działają raz - serwer czeka na wiadomość, zwraca ją klientowi, klient może zamknąć. Gdy chcę wysłać kolejną wiadomość, zarówno klient, jak i serwer przestają odpowiadać. – uluroki

Odpowiedz

5

Dlaczego nie można po prostu zarządzać zarówno FIFO na serwerze? Po prostu zmiana kodu, aby to zrobić sprawia, że ​​działa poprawnie.

Jeśli rzeczywiście chcesz mieć relację klient-serwer, z serwerem obsługującym wielu różnych klientów, gniazda będą prawdopodobnie lepszym wyborem.

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

Działa tylko raz, ponieważ, jak działa nazwane potoki. Za każdym razem, gdy open jest nazwany potok do odczytu, blokujesz, aż inny proces otworzy go do zapisu. Następnie jesteś sparowany, a deskryptor pliku łączy twoje procesy. Gdy któryś koniec zamknie to połączenie, to koniec tej rury. Aby twój serwer "zaakceptował inne połączenie", musi przenieść open i close rur do swojej głównej pętli, aby mógł być sparowany w kółko.