0

名前付きパイプを使用した単純なマルチクライアント サーバーを作成したいだけです。サーバー側に問題があります。読書だけをしていたときは、すべてが素晴らしかったです。ここで、サーバーがメッセージをクライアントに送り返す可能性を追加しました-そして今ではまったく機能していません...

これが私のサーバー コードです(コメント行 /* */ を削除すると、すべてのクライアントから読み取られますが、正常に動作しますが、読み取り専用であることに注意してください)。サーバーにすべてのクライアントへの書き込みを強制する方法は? (概念は、クライアントが最初にサーバークライアントfifonameに送信するというものです。サーバーはそのようなfifoを作成して開き、それに書き込むことができますが、書き込み部分はまだ機能したくありません... :/)

int main (int argc, char *argv[])
{
        int fd_in, fd_out, j, result;
        char buffer[4096];
        const char *myfifo = "./fifo";
        mkfifo(myfifo, 0666 );

        if ((fd_in = open(myfifo, O_RDONLY | O_NONBLOCK)) < 0)
                perror(myfifo);

        printf("Server reads from: %s\n", myfifo);


        for (;;) {

                fd_set fds_r;
                fd_set master;
                FD_ZERO (&fds_r);
                FD_ZERO (&master);
                FD_SET (fd_in, &fds_r);
                master = fds_r;

                if ((result = select(fd_in + 1, &fds_r, NULL, NULL, NULL)) < 0)
                        perror ("select()");

                if (! FD_ISSET(fd_in, &fds_r))
                        continue;
                result = read(fd_in, buffer, 4096);
                printf("FROM CLIENT: %s\n", buffer);

                /*if(startsWith(buffer, "#"))
                {
                    // remove # from message from client
                    string login = removePrefix(buffer);
                    string fifoname = "./fifo";
                    fifoname += login;
                    printf("REGISTERED: %s\n", fifoname.c_str());
                    mkfifo(fifoname.c_str(), 0666);
                    if ((fd_out = open(fifoname.c_str(), O_WRONLY)) < 0)
                            perror(fifoname.c_str());
                    FD_SET (fd_out, &master);

                }
               /* for(j = 0; j <= fd_in; j++) {
                            // send to everyone!
                            if (FD_ISSET(j, &master)) {
                                // except the listener and ourselves
                                if (j != fd_out) {
                                    if (write(j, buffer, sizeof(buffer)) == -1) {
                                        perror("write");
                                    }
                                }
                            }
                        }*/


                memset(buffer, 0, sizeof(buffer));
        }

        fprintf (stderr, "Got EOF!\n");
        close (fd_in);
        return 0;
}

client.cpp

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

int main(int argc, char **argv)
{
   int client_to_server;
   const char *myfifo = "./fifo";

   int server_to_client;
   string f = "./fifo";
   string u(argv[1]);
   f += u;
   const char *myfifo2 = f.c_str();

   char str[BUFSIZ];
   /* write str to the FIFO */
   client_to_server = open(myfifo, O_WRONLY);
   server_to_client = open(myfifo2, O_RDONLY);

   // register message #username
   string reg = "#";
   reg += u;

   printf("Client writes to: %s\n", myfifo);
    printf("Client reads from: %s\n", myfifo2);

   // first write to server, he can now make a fifo called fifo+username
   if(write(client_to_server, reg.c_str(), strlen(reg.c_str())) == -1)
        perror("write:");

   while(1)
    {

   printf("Input message to serwer: ");
   scanf("%s", str);

   if(write(client_to_server, str, sizeof(str))==-1)

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

   if(read(server_to_client,str,sizeof(str))==-1)

   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 
Server reads from: ./fifo
FROM CLIENT: #username
FROM CLIENT: hello
FROM CLIENT: 
FROM CLIENT: ?
FROM CLIENT: 
FROM CLIENT: huh
FROM CLIENT: 

クライアント側:

$ ./CLIENT username
Client writes to: ./fifo
Client reads from: ./fifousername
Input message to serwer: hello
Read:: Bad file descriptor
...received from the server: hello
Input message to serwer: ?
Read:: Bad file descriptor
...received from the server: ?
Input message to serwer: huh
Read:: Bad file descriptor
...received from the server: huh
Input message to serwer: 
4

1 に答える 1

4

まず、open通話のエラーを確認します。それがあなたが尋ねた問題を説明している可能性が最も高いです。

「メッセージ」が何であるかは私にはわかりません。で始まるはず#ですが、サーバーはどのようにしてそれがどこで終わるかを知ることになっていますか?常に4,096バイトですか?

しかし、3つの大きな問題があります。

  1. あなたのコードはどこでもブロックすることは想定されていませんが、記述子を非ブロックに設定していません。

  2. あなたのコードは4,096バイトのメッセージを期待しています。ただし、読み取るバイト数が少ない場合は、残りのバイトを読み取るまで待機せず、代わりにメッセージを壊します。(または、予期するメッセージが何であれ、パイプがアトミックに処理できるバイト数を明らかに超える可能性があります。メッセージの境界を何らかの方法で見つける必要があります。)

  3. コードには、部分的な書き込みを処理する方法がありません。いずれかのクライアントが十分な速度で読み取っていない場合、現在ハングします(上記の問題1が原因)が、それを修正すると、データが破損します。

接続ごとのアプリケーション受信バッファが必要です。接続からデータを読み取るときは、それをアプリケーションバッファに読み込みます。メッセージ全体を受け取ったら、すばらしいメッセージを処理します。それ以外の場合は、残りを読むまで待ちます。固定長のメッセージを使用していない場合は、あるメッセージの終わりと別のメッセージの始まりを読み取る場合を処理する必要があります。

書き込み戦略には2つの選択肢があります。

  1. 接続ごとのアプリケーション書き込みバッファを使用します。接続にデータを送信するときに、すべてのバイトがすぐに送信されない場合は、残りをアプリケーションバッファに保存します。読み取りだけでなく書き込みについても、その記述子の選択を開始します。書き込みヒットが発生した場合は、アプリケーションバッファからの書き込みを試みてください。

  2. カーネルバッファのみを使用してください。部分的な書き込みを取得した場合、カーネルバッファがいっぱいです。クライアントが追いつかないため、クライアントを切断します。

于 2012-12-12T13:41:13.170 に答える