1

エコーサーバーを作成するために、次のコードを記述しました(書き込むデータはstdout、PCからサーバーに移動し、PCに戻ります)。問題は、エコーがクライアントの端末に表示されないことです。2つserver.cppのプロセスが実行されているので、サーバーによって接続が受け入れられたことがわかります。コードを直接コピーして実行できるように、完全なコードがここにあります。コードの関連部分は次のとおりです。

server.cpp

void reflect(int x)
{
    int n;
    int m;
    char data[100];
    cout<<"Entered reflect function"<<endl; //this gets displayed

    n=read(x,data, 100); //***execution is not going beyond this point i.e. read is blocking***
    cout<<"Client sent "<<n<<endl; //this doesn't get displayed 

    if(n>0)
    {
        while(n>0)
        {
            m=write(x,data,n);
            n=n-m;
        }
    cout<<"Successfully echoed back to client"<<endl; //this doesn't get displayed 
    }
}

int main()
{
    sockaddr_in serv;
    bzero(&serv, sizeof(serv));
    serv.sin_family=AF_INET;
    serv.sin_port=htons(3345);
    inet_aton("127.0.0.1", &(serv.sin_addr));

    int servfd=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    int x;
    x=bind(servfd, (sockaddr*)(&serv), sizeof(serv));

    cout<<"Bind returned"<<x<<endl; //this displays x as 0

    listen(servfd, 5);
    sockaddr cli;
    int connfd;
    pid_t id=-1;
    socklen_t siz=sizeof(cli);
    for(;;)
    {
        if(connfd=accept(servfd, &cli, &siz)>=0)
             id=fork();

        if(id==0)
             reflect(connfd);

        else 
             continue;
    }
}

client.cpp

int main()
{
    int clifd;
    clifd=socket(AF_INET,SOCK_STREAM, IPPROTO_TCP);
    sockaddr_in serv;
    bzero(&serv, sizeof(serv));
    serv.sin_family=AF_INET;
    serv.sin_port=htons(3345);
    inet_aton("127.0.0.1", &(serv.sin_addr));

    connect(clifd, (sockaddr*)(&serv), sizeof(serv));//blocking call
    int n,m;
    char data[100];
    char recvd[100];
    for(;;)
    {
        fgets(data, 100,stdin );
        n=strlen(data);
        cout<<"You have written "<<n<<endl; //this returns the correct value

        if(n>0)
        {
            while(n>0)
            {  
                 m=write(clifd,data,n);
                 n=n-m;
            }
        }

        n=read(clifd, recvd, 100);
        cout<<"Server echoed back "<<n<<endl; //this doesn't get displayed

        if(n>0)
        {
            while(n>0)
            {
                m=fputs(data,stdout);
                fflush(stdout);
                n=n-m;
            }
            //cout<<data<<endl;
        }
    }
}
4

4 に答える 4

3

server.cで、次の誤った行を置き換えます。

if( connfd=accept(servfd, &cli, &siz) >=0 )

この正しいもので:

if( (connfd=accept(servfd, &cli, &siz)) >=0 )


余談ですが、どのコンパイラを使用していますか?g ++は、その行を見たときに警告を出力しました。

serv.cc: In function ‘int main()’:
serv.cc:45:43: warning: suggest parentheses around assignment used as truth value [-Wparentheses]

-Wall -Werrorg++またはgccでコンパイルするときは常に使用するようにしています。

于 2012-07-06T15:59:53.837 に答える
1

確かに、クライアント側で100文字を入力していますstdinか?

そうでない場合は、サーバーに100文字未満を書き込んでいますが、サーバーは100文字を想定しているため、サーバー側read()はブロックします。

次のようにクライアントコードを変更することで、これを解決できます。

while (n > 0)
{  
  m = write(clifd, data, sizeof(data));
  ...

別のアプローチは、クライアント->サーバー通信を2つの部分に分割することです。

1エコーするデータのサイズを送信します

2データ自体を送信します

そうすることで、サーバーが読み取る文字数を調整してからエコーバックできるようになります。


以下のこの構成は、によって返される値をチェックしない限り意味がありませwrite()-1

toの呼び出しは、バイトが書き込まwrite()れるまでブロックされるか、エラー時に返されます。後者はあなたの論理を壊します。n-1

while (n > 0)
{
  m=write(fd, data, n);
  n = n - m;
}

次のようなものを試してみてください。

while (n > 0)
{
  m = write(fd, data, n);
  if (0 < m)
    n = n - m;
  else if (errno)
    perror("write()");
}

この問題は、サーバーだけでなくクライアントにも当てはまります。

于 2012-07-06T16:31:04.303 に答える
1

accept無効な引数を使用してserver.cppを呼び出しています。3番目の引数には、2番目の引数が指す構造のサイズが含まれている必要があります。

socklen_t siz = sizeof(cli);
for(;;)
{
    if((connfd=accept(servfd, &cli, &siz))>=0)
    ...
于 2012-07-06T08:26:24.667 に答える
0

いくつかのインデントはいいでしょうが、「mathematician1975」のように異なる関数をチェックして書き直すこともお勧めします。あなたはグーグルでたくさんの例を見つけることができます。また、1つman accept。私はあなたに見てみることをお勧めします:pollまたはselect避けるためにfork

于 2012-07-06T08:28:25.100 に答える