2012-12-02 99 views
2

我想使用命名管道編寫echo客戶端服務器應用程序(我使用套接字完成了工作,但現在我想要 對命名管道執行相同操作。)服務器必須是多線程的。C和C++中的簡單回聲客戶端服務器

我以爲我的程序在我第一次運行時就工作了,這一切都很好。連接到服務器的每個客戶端 都收到來自它的消息。

但是現在,當我試圖運行第二次節目,我仍然得到這個消息:

mkfifo client2server: File exists 

(很多這樣的消息)。這是我的輸出,當我試圖運行./echoserver時:

$ ./echoserver 
Server is working ... 
mkfifo client2server: File exists 
mkfifo client2server: File exists 
mkfifo client2server: File exists 
mkfifo client2server: File exists 
mkfifo client2server: File exists 
mkfifo client2server: File exists 
mkfifo client2server: File exists 
mkfifo client2server: File exists 
mkfifo client2server: File exists 
mkfifo client2server: File exists 
mkfifo client2server: File exists 
mkfifo client2server: File exists 

如何解決它的工作,因爲我想要它?製作一個真正的多線程回顯服務器客戶端應用程序?

繼承人我的代碼:

echoserver.cpp

#include <fcntl.h> 
#include <stdio.h> 
#include <errno.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <unistd.h> 
#include <string.h> 
#include <stdlib.h> 
#include <string> 
#include <sstream> 
using namespace std; 

string toString(int d) 
{ 
    ostringstream ss; 
    ss << d; 
    return ss.str(); 
} 

void* clients_service(void * arg) 
{ 
    int client_id = *((int*)&arg), server2client = -1, buffsize = 255, bytes_read = -1, client2server = -1; 
    client_id++; 
    char buffer[255]; 
    string fifoname = "/tmp/server2client"; 
    fifoname += toString(client_id); 

    string fifoclient = "/tmp/client2server"; 
    fifoclient += toString(client_id); 

    if(mkfifo(fifoclient.c_str(), 0666) == -1) 
    { 
     perror("mkfifo client2server"); 
     fprintf(stderr, "%s\n", strerror(errno)); 
     exit(1); 
    } 

    if((client2server = open(fifoclient.c_str(), O_RDONLY)) == -1) 
    { 
     perror("open client2server"); 
     exit(1); 
    } 

    if(mkfifo(fifoname.c_str(), 0666) == -1) 
    { 
     perror("mkfifo server2client"); 
     exit(1); 
    } 
    if((server2client = open(fifoname.c_str(), O_WRONLY)) == -1) 
    { 
     perror("open server2client"); 
     exit(1); 
    } 

    for(;;) 
{ 

    if ((bytes_read = read(client2server, buffer, buffsize))== -1) 
     { 
      perror("read"); 
      exit(1); 
     } 
     else if (bytes_read == 0) 
     { 
      fprintf(stdout, "Connection closed\n"); 
      break; 
     } 
     buffer[bytes_read] = '\0'; 

     if (strcmp("\\q",buffer)==0) 
     { 
     fprintf(stdout, "Server OFF.\n"); 
     break; 
     } 

     fprintf(stdout, "From client: %s\n", buffer); 
     if ((write(server2client,buffer, strlen(buffer)))== -1) 
     { 
      perror("write"); 
      break; 
     } 

     fprintf(stdout, "Send to client: %s\n", buffer); 

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

close(client2server); 
    close(server2client); 

    unlink(fifoname.c_str()); 
    unlink(fifoclient.c_str()); 

} 

int main(int argc, char **argv) 
{ 
    int clientsCounter = 0; 
    fprintf(stdout, "Server is working ...\n"); 

    while (1) 
    { 
     pthread_t thread; 
     pthread_create(&thread, NULL, clients_service, (void*)&clientsCounter); 
    } 

    return 0; 
} 

編譯如下:g++ -Wall -pthread echoserver.cpp -o echoserver

echoclient.c

#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/client2server"; 

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

    char str[255]; 

    /* write str to the FIFO */ 
    client_to_server = open(myfifo, O_WRONLY); 
    server_to_client = open(myfifo2, O_RDONLY); 
    while(1) 
    { 
     printf("\n> "); 
    scanf("%s", str); 
    write(client_to_server, str, sizeof(str)); 
    read(server_to_client,str,sizeof(str)); 
    printf("From server: %s\n",str); 
    } 

    close(client_to_server); 
    close(server_to_client); 

    /* remove the FIFO */ 
    unlink("/tmp/server2client"); 
    unlink("/tmp/client2server"); 

    return 0; 
} 

像這樣編譯它:gcc echoclient.c -o echoclient

+0

不要將已存在的文件視爲錯誤。 –

+0

客戶端只使用「無編號」的fifos。這預計如何工作? – alk

+0

@alk你知道如何給客戶提供相同的號碼嗎?我不知道如何使它 –

回答

1

要設置多個連接,您需要多個獨立的連接實例。連接的一個實例由一個fifo表示,表示自己是文件系統中的一個命名條目。

爲了區分這些連接通道的實例,它們的標識名稱需要不同。在你的代碼中他們不是。每個cleint使用相同的fifos與服務器和verse vica進行通信。

更改您的代碼,以便爲每個客戶端命名fifos的文件系統條目。

考慮它使用套接字是如何工作的:

  • 一個在服務器端接受所有客戶端連接監聽套接字。
  • 作爲接受連接的結果,設置了特定套接字(允許雙工通信),用於一個特定客戶端)。

要更換此使用的FIFO有需要是:

  • 一個更換爲監聽套接字
  • 替代服務每個客戶端連接每個插座
+0

我以爲我這麼做過:查看'echoserver.cpp'中'clients_service'函數的前七行。我爲每個客戶創建了不同的文件名(每次我給client_service添加一個不同的數字給fifoname - client_id ++。如果它是錯誤的,你能給一些代碼示例嗎? –

+0

你是對的,我不知何故忽略了這部分你的代碼Sry for this。無論如何,當你將一個計數器的地址傳遞給線程函數時,你試圖達到的目標並沒有達到你想要的目標,因爲你不會增加變量的地址,而是增加一個本地變量。計數器在主線程的循環中,如果在線程函數中增加它,你應該使用互斥鎖來保護它的訪問@BrianBrown – alk

+0

我看過你的評論,謝謝你,可以請看我的新代碼嗎?都好 –