1

エコーサーバーを作成するために、次のコードを記述しました(stdoutに書き込んだデータは、PCからサーバーに移動してPCに戻ります)。コードでは、ソケットにSO_LINGERオプションを設定しました。したがって、Ctrl+を押しCてclient.cppがサーバー.cppにFINを送信すると、client.cppのclose()は、server.cppのソケットがFINを返送するまで10秒待機する必要があります

しかし、私が見つけたのは、client.cppがすぐに実行を終了Ctrlし、 +Cが押された後に終了し、close()関数でさえ-1を返さなかったということでした。これは、反対側がl_lingerに記載されている時間より前にFINを送信しない場合に必要です。有効期限が切れます(サーバーがFINを送信しなかったか、tcpdumpにリストされている必要があります。)サーバー側は、端末でCtrl+を押さない限りFINを送信しませんでした。サーバーの端末で+Cを押すまでのtcpdumpは、スクリーンショットに示されています。CtrlC

上記で強調表示されている行は、クライアントのFINです。

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));

    linger lin;
    unsigned int y=sizeof(lin);
    lin.l_onoff=1;
    lin.l_linger=10;
    setsockopt(clifd,SOL_SOCKET, SO_LINGER,(void*)(&lin), y);  

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

        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; 

        if(n>0)
        {
            while(n>0)
            {
                m=fputs(data,stdout);  
                cout<<"m is"<<m<<endl; 
                fflush(stdout);
                n=n-m;
            }
            //cout<<data<<endl;
        }
    }
    int z=close(clifd);
    if(z==-1)
        cout<<"close returned -1 "<<endl; ***//this doesn't get printed***
}

server.cpp:

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

    for(;;)
    {
        n=read(x,data, 100); 
        cout<<"Client sent "<<n<<endl; 

        if(n>0)
        {
            while(n>0)
            {
                m=write(x,data,n);
                n=n-m;
            }
            cout<<"Successfully echoed back to client"<<endl;  
        }
    }//end of for loop
}

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;
    }
}

クライアントのclose()が待機していないのはなぜですか?

4

4 に答える 4

5

クライアントの close() が待機していないのはなぜですか?

close()あなたはあなたのクライアントを呼んでいません。呼び出しのfor直前のループは決して終了しないため、決して発生しません。close()close()

CTRLコンソールに-と入力Cすると、残りのアクションを実行せずに、プログラムがすぐに終了します。

close()は決して呼び出されないため、質問の残りの部分 (待つclose()必要がありますか? 使用する必要がありますclosesocket()か? など) は意味がありません。

for(;;)ループを終了できるようにしたい場合は、次のようなことを試してください。

for(;;)
{
  if(fgets(data, 100,stdin ) == NULL)
    break;
  ... rest of loop goes here ...

次に、クライアント プログラムを実行するときは、CTRL-Cで終了するのではなく、CTRL-Dを行の唯一の文字として入力します。

于 2012-07-11T19:36:55.840 に答える
3

上記の答えを拡張するには、関数を呼び出したい場合はclose()、クライアントに次の比較的簡単な変更を加えます。

#include <signal.h>

volatile bool stop_now = false;

// This function will be called when SIGINT (Ctrl+C)
// is received, and will set this global flag that
// will terminate your loop below.
void app_stopped(int sig)
{
    stop_now = true;
}


int main()
{
   // setup to catch Ctrl+C
   signal(SIGINT, app_stopped);

   ...

   // for(;;)
   // becomes:
   while(!stop_now)
   {
      ...
   }
   ...
}

これで、SIGINTを(経由Ctrl+Cまたは経由でkill -s INT)送信すると、プログラムが正常に停止し、close()関数が呼び出されます。そこからトラブルシューティングを開始できます。

于 2012-07-11T19:44:50.000 に答える
2

MSDNのリファレンスから(msdn を信頼していない場合は、同じ情報をここでlinger見つけることができます)

linger 構造体は、特定のソケットに関する情報を保持します。この情報は、データが送信されるキューに入れられ、ソケットで closesocket 関数が呼び出されたときに、そのソケットがどのように動作するかを指定します。

そのため、FIN が受信されるまでではなく、すべてのデータが送信されるまで待機します。

于 2012-07-11T19:38:45.073 に答える
1

したがって、 client.cpp の close() は、 server.cpp のソケットが FIN を返すまで 10 秒間待機する必要があります。

それは正しくありません。すべての発信データと発信 FIN が送信されるか、タイマーが期限切れになるまで待機する必要があります。着信 FIN を待機することを期待する権利を与えるステートメントはどこにもありません。

于 2012-07-11T23:58:09.010 に答える