2

名前付きパイプを使用してエコー クライアント サーバー アプリを作成したい (私はソケットでそれを行いましたが、今は名前付きパイプで同じことをしたいと思っています)。サーバーはマルチスレッドである必要があります。

初めてプログラムを実行したときは、プログラムが機能すると思っていましたが、すべて問題ありませんでした。サーバーに接続されたすべてのクライアントは、サーバーからメッセージを受け取りました。

しかし、プログラムを 2 回目に実行しようとすると、まだ次のメッセージが表示されます。

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

4

1 に答える 1

1

複数の接続をセットアップするには、接続の複数の独立したインスタンスが必要です。接続のインスタンスは、それ自体をファイル システム内の名前付きエントリとして表す fifo によって表されます。

接続チャネルのこれらのインスタンスを区別するには、それらの識別名が異なる必要があります。あなたのコードではそうではありません。各クライアントは、同じ fifo を使用してサーバーと通信し、vica と通信します。

コードを変更して、fifos のファイル システム エントリがクライアントごとに異なる名前になるようにします。

ソケットを使用してどのように機能したかを考えてみてください。

  • サーバー側には、すべてのクライアント接続を受け入れるリッスン ソケットが1 つあります。
  • 接続を受け入れた結果、特定のクライアントに対して特定のソケットがセットアップされます (二重通信が許可されます)。

fifos を使用してこれを置き換えるには、次のものが必要です。

  • リスニング ソケットの交換用1 個
  • 各クライアント接続を提供する各ソケットの交換。
于 2012-12-02T10:29:03.077 に答える