2012-12-02 75 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

我看过你的评论,谢谢你,可以请看我的新代码吗?都好 –