2

ソケット関数への連続した呼び出し中にerrno値が更新されない場合、問題によって何が可能でしょうか?

socket (AF_INET, -1, 0);
socket (AF_INET, SOCK_STREAM, -1);

1つ目はerrno=EINVALである必要があります2つ目はerrno=EPROTONOSUPPORTである必要があります


@JonathanLefflerによって以下に提供されるコードから、cygwinからの出力は次のようになります。

*$ ./socket.exe
Error from socket(AF_INET, -1, 0): 124 (Socket type not supported)
-- errno = 124 (Socket type not supported)
Error from socket(AF_INET, SOCK_STREAM, -1): 123 (Protocol not supported)
-- errno = 123 (Protocol not supported)
socket(AF_INET, SOCK_STREAM, 0) succeeded (fd = 3)
-- errno = 123 (Protocol not supported)*

以下のコードは、ソケットを作成する前にソケットfd0を作成するように編集されています

int fd0 = socket(AF_INET, SOCK_STREAM, 0);
if (fd0 < 0)
    printf("Error from socket(AF_INET, SOCK_STREAM, 0): %d (%s)\n", errno, strerror(errno));
else
{
    printf("socket(AF_INET, SOCK_STREAM, 0) succeeded (fd = %d)\n", fd0);
    close(fd0);
}
printf("-- errno = %d (%s)\n", errno, strerror(errno));

int fd1 = socket(AF_INET, -1, 0);
.....

結果は次のとおりです。

*$ ./socket.exe
socket(AF_INET, SOCK_STREAM, 0) succeeded (fd = 3)
-- errno = 0 (No error)
Error from socket(AF_INET, -1, 0): 124 (Socket type not supported)
-- errno = 124 (Socket type not supported)
Error from socket(AF_INET, SOCK_STREAM, -1): 123 (Protocol not supported)
-- errno = 123 (Protocol not supported)
socket(AF_INET, SOCK_STREAM, 0) succeeded (fd = 3)
-- errno = 123 (Protocol not supported)*

最初と最後のソケット作成は同じerrno値を持つ必要があります。


しかし、この出力はどのように説明できますか?5番目と6番目のソケット作成のerrno値は同じですが、エラーの原因は異なります。

$ ./test_select.exe
[1] ierr = 124, iSocket = -1 socket(AF_INET, -1, 0);
 : Socket type not supported
[2] ierr = 124, iSocket = -1 socket(AF_INET, -1, 0);
 : Socket type not supported
[3] ierr = 124, iSocket = 3 socket(AF_INET, SOCK_STREAM, 0);
 : Socket type not supported
[4] ierr = 124, iSocket = -1 socket (AF_INET, -1, 0);
 : Socket type not supported
[5] ierr = 123, iSocket = -1 socket (AF_INET, SOCK_STREAM, -1);
 : Protocol not supported
[6] ierr = 123, iSocket = -1 socket (AF_INET, -1, 0)
 : Protocol not supported
[7] ierr = 124, iSocket = -1 socket(AF_INET, SOCK_STREAM, -1)
 : Protocol not supported

実際のコードは次のとおりです。

   sockfd = socket(AF_INET, -1, 0);
    err = errno;
    printf("[1] err = %d, sockfd = %d socket(AF_INET, -1, 0);\n", err, sockfd);
    perror(" ");
    sockfd = socket(AF_INET, -1, 0);
     err = errno;
    printf("[2] err = %d, sockfd = %d socket(AF_INET, -1, 0);\n", err, sockfd);
    perror(" ");
     sockfd = socket(AF_INET, SOCK_STREAM, 0);
    err = errno;
    printf("[3] err = %d, sockfd = %d socket(AF_INET, SOCK_STREAM, 0);\n", err, sockfd);
    perror(" ");
    close(sockfd);
    sockfd = socket(AF_INET, -1, 0);
    err = errno;
    printf("[4] err = %d, sockfd = %d socket (AF_INET, -1, 0);\n", err, sockfd);
    perror(" ");
    sockfd = socket(AF_INET, SOCK_STREAM, -1);
    err = errno;
    printf("[5] err = %d, sockfd = %d socket (AF_INET, SOCK_STREAM, -1);\n", err, sockfd);
    perror(" ");
    sockfd = socket(AF_INET, -1, 0);
    err = errno;
    printf("[6] err = %d, sockfd = %d socket (AF_INET, -1, 0)\n", err, sockfd);
    perror(" ");
    err = errno;
    sockfd = socket(AF_INET, SOCK_STREAM, -1);
    printf("[7] err = %d, sockfd = %d socket(AF_INET, SOCK_STREAM, -1)\n", err, sockfd);
    perror(" ");
4

2 に答える 2

11

errno標準ライブラリ関数によってクリアされることはなく、設定されるだけです。さらに、その動作を許可しないように文書化されていない標準ライブラリ関数によって誤って設定される可能性があります。

基本的に、唯一の正しい使用方法は、標準ライブラリ関数がエラーを示す値を返したerrno直後にのみ検査し、後で保持する必要がある場合は別の変数に保存することです。

ほとんどのシステム コールでselectは、エラーを示す戻り値は -1 です。つまり、errno-1 が返された場合にのみ検査する必要があります。

于 2012-04-18T14:18:23.297 に答える
9

errnoゼロに設定されるライブラリ関数はありません。ゼロにしたい場合は、プログラムで実行する必要があります。

errno関数が失敗したと言った場合にのみ、意味のある情報をテストできます(それでも、マニュアルページに設定が示されている場合のみerrno)。errno成功した関数によってゼロ以外に設定されていることがわかります。たとえば、Solarisではerrno、ターミナルではなくファイルに書き込むときに、標準のI/O呼び出しの後にENOTTYが見つかることがよくあります。

あなたの例では、関数への特定の誤った呼び出しによって、複数の可能なエラー値のどれが設定されるかについての保証はありません。1つの有効なエラー状態が報告されている限り、報告するエラーを決定するのはシステム次第です。したがって、2番目の呼び出しがEBADFではなくEINVALを返す必要がある理由の説得力のある例を示す必要があります。書かれているあなたの質問には、私たちに説得するのに十分な情報が含まれていません。

また、宣言する唯一の安全な方法errnoは、ヘッダーを使用することです#include <errno.h>。特にスレッド環境では、それは単にではないことがよくありますextern int errno;。たとえば、Mac OS Xでは、次のように定義できます。

extern int * __error(void);
#define errno (*__error())

つまり、__errorは整数へのポインタを返す関数であり、errnoそのポインタを逆参照して変更可能な左辺値になるマクロです。


コード分​​析

与えられたコードは次のとおりです。

socket (AF_INET, -1, 0);
socket (AF_INET, SOCK_STREAM, -1);

実行可能なコードに変換すると、次のようになります。

#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>

int main(void)
{
    int fd1 = socket(AF_INET, -1, 0);
    if (fd1 < 0)
        printf("Error from socket(AF_INET, -1, 0): %d (%s)\n", errno, strerror(errno));
    else
    {
        printf("socket(AF_INET, -1, 0) succeeded (fd = %d)\n", fd1);
        close(fd1);
    }
    printf("-- errno = %d (%s)\n", errno, strerror(errno));

    int fd2 = socket(AF_INET, SOCK_STREAM, -1);
    if (fd2 < 0)
        printf("Error from socket(AF_INET, SOCK_STREAM, -1): %d (%s)\n", errno, strerror(errno));
    else
    {
        printf("socket(AF_INET, SOCK_STREAM, -1) succeeded (fd = %d)\n", fd2);
        close(fd2);
    }
    printf("-- errno = %d (%s)\n", errno, strerror(errno));

    int fd3 = socket(AF_INET, SOCK_STREAM, 0);
    if (fd3 < 0)
        printf("Error from socket(AF_INET, SOCK_STREAM, 0): %d (%s)\n", errno, strerror(errno));
    else
    {
        printf("socket(AF_INET, SOCK_STREAM, 0) succeeded (fd = %d)\n", fd3);
        close(fd3);
    }
    printf("-- errno = %d (%s)\n", errno, strerror(errno));

    return(0);
}

Mac OS X 10.7.3で実行すると、次のようになります。

Error from socket(AF_INET, -1, 0): 43 (Protocol not supported)
-- errno = 43 (Protocol not supported)
Error from socket(AF_INET, SOCK_STREAM, -1): 43 (Protocol not supported)
-- errno = 43 (Protocol not supported)
socket(AF_INET, SOCK_STREAM, 0) succeeded (fd = 3)
-- errno = 43 (Protocol not supported)

前に述べたように、返されるエラーはシステムによって異なります。

于 2012-04-18T14:19:35.510 に答える