0

非並行シングルプロセス実装のTCPソケットを備えたサーバーがあります。

int main(int argc, char** argv) {

    int sock_ds, acc_sock_ds, opt, client_addr_l;
    unsigned short port;
    struct sockaddr_in server_addr, client_addr;


    /*Parsing command line: port-number retrieving*/
    /*...*/

    printf("Port number retrieved (%d), server is starting ...\n", port);

    /*TCP Socket creation*/
    sock_ds = socket(AF_INET, SOCK_STREAM, 0); 
    if(sock_ds == -1){
        fprintf(stderr, "Socket creation error\n");
        exit(EXIT_FAILURE);
    }

    /*Server address binding*/
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(port);
    server_addr.sin_addr.s_addr = INADDR_ANY;
    //use setsockopt(2) with OS_REUSEADR ???
    if(bind(sock_ds, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1){
        fprintf(stderr, "Address binding error\n");
        exit(EXIT_FAILURE);
    }

    /*Server with passive socket*/
    if(listen(sock_ds, SOMAXCONN) == -1){
        fprintf(stderr, "Listen call error: %s\n", strerror(errno));
        exit(EXIT_FAILURE);
    }

    printf("Server is ready. Waiting for connections.\n");

        /*Busy-waiting server*/
while(1){

    memset(&client_addr, 0, sizeof(client_addr));
    acc_sock_ds = accept(sock_ds, &client_addr, &client_addr_l);
    /*Connect error management*/
    if(acc_sock_ds == -1){
         errsv = errno;
         if(errsv == 12 || errsv == 23 ){
            /*Fatal errors ENOMEM, ENFILE*/
            fprintf(stderr, "Fatal error on accept\n");
            exit(EXIT_FAILURE);
         }
         else if(errsv == 103 || errsv == 4 || errsv == 71 || errsv == 92 
                 || errsv == 112 || errsv == 113 || errsv == 95 || errsv == 101)
             /*ECONNABORTED, EINTR, EPROTO, ENOPROTOOPT, 
              * EHOSTDOWN, EHOSTUNREACH, EOPNOTSUPP, ENETUNREACH*/
             continue;
         else if(errsv == 100 || errsv == 64){
             /* ENETDOWN - ENONET */
             /*start timeout...*/
             continue;
         }
    }
  }
}

このテストでは、サーバーがaccept(2)失敗しても引き続き呼び出しを行うことを期待していました。私はそのようないくつかの端末エラー状態があることを知っていますEBADF。の値に応じて異なる動作(プロセスの終了)を提供する必要がありerrnoますか?サーバーを停止する必要がある値と、待機を継続できる値はどれですか?

コードを編集しました。errnoを介してエラー処理を行ったことはありません。エラーや提案がある場合は、それらに通知してください。ENETDOWN私は、2つの条件がネットワークのENONET欠如によって暗示されていることに気づきました。これらの状況では、ストールを防ぐためにタイムアウトを期待する必要がありますか?

4

2 に答える 2

2

MacOS Xで文書化されているエラーコードを見るとaccept(2)(そして、ほとんどのPOSIX準拠システムで一貫しているはずです):

  • EBADF-プログラマーエラー-元のsocket呼び出しが成功した場合は発生しません
  • ECONNABORTED- 再試行
  • EFAULT-プログラマーエラー-&client_addrが無効でない限り発生しません
  • EINTR-通話が中断されました。再試行してください
  • EINVAL-「ソケットは接続を受け入れたがらない」-それがどのように発生するかはわかりません。最初に呼び出さなかったことが原因である可能性listen(2)があります(プログラマーエラー)が、一部のOSでは、namelenパラメーターが負であることが原因である可能性もあります(プログラマーエラーもあります) 。
  • EMFILE-プログラマーエラー-プロセスごとのFDが不足しましたが、それらを閉じるのを忘れない限り、それは発生しないはずです。
  • ENFILE-システムのFDが不足しています-これはおそらく致命的です
  • ENOMEM-システムのメモリが不足しました-これはおそらく致命的です
  • ENOTSOCK-プログラマーエラー-ソケットではないFDを渡さない限り発生しません
  • EOPNOTSUPP-プログラマーエラー-そうでないソケットを渡さない限り発生しませんSOCK_STREAM
  • EWOULDBLOCK-プログラマーエラー-ソケットが非ブロッキングとして構成されました

さらに、Linuxシステムは、、、、、、、、、、およびをENETDOWN生成することEPROTOもできるようです。これらは、ループする必要のあるネットワークエラーです。ENOPROTOOPTEHOSTDOWNENONETEHOSTUNREACHEOPNOTSUPPENETUNREACH

要約すると、おそらく次のようにする必要があります。

  • ENFILEまたはのプログラムを終了しますENOMEM
  • ループオンECONNABORTEDEINTR、およびLinuxからの上記のリスト
  • assert()他の何かのデバッグ中-これらのランタイムエラーは、ネットワーク関連のイベントではなく、コードの論理エラーが原因でのみ発生するはずです。
于 2013-03-02T20:29:43.273 に答える
1

文体:

  • コメントに入れる代わりに、シンボリック定数を使用してください
  • 予期しないエラーが発生した場合、少なくともエラー番号を報告してください
  • デフォルト/予期しないケースも処理します

ところで:以下の記号定数のほとんどは存在しないようです。


#include <errno.h>
#include <strings.h>

 /* Busy-waiting server */
while(1){

    memset(&client_addr, 0, sizeof(client_addr));
    acc_sock_ds = accept(sock_ds, &client_addr, &client_addr_l);
    /*Connect error management*/
    if(acc_sock_ds == -1){
        switch(errsv=errno) {
            /*Fatal errors ENOMEN, ENFILE, all others*/
        default :
        case ENOMEM :
        case ENFILE :
            fprintf(stderr, "Fatal error on accept %d(%s)\n"
                , errsv, strerror(errsv)
                );
            exit(EXIT_FAILURE);
            /* normal NON-ERROR error conditions */
        case ECONNABORTED :
        case EINTR :
        case EPROTO :
        case ENOPROTOOPT :
        case EHOSTDOWN :
        case EHOSTUNREACH :
        case EOPNOTSUPP :
        case ENETUNREACH :
             continue;
        case ENETDOWN :
        case ENONET :
             /*start timeout...*/
             continue;
         }
    }
  }
}
于 2013-03-03T12:23:34.260 に答える