在连续调用套接字函数期间未更新errno值时,问题可能是什么?
socket (AF_INET, -1, 0);
socket (AF_INET, SOCK_STREAM, -1);
第一个应该有errno = EINVAL 第二个应该有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)*
编辑下面的代码是为了在创建套接字
之前创建套接字fd0int 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(" ");
答案 0 :(得分:11)
errno
永远不会被标准库函数清除,只能设置。此外,任何标准库函数都可以虚假地设置它,否则不会记录该行为。
基本上,使用errno
的唯一正确方法是仅在标准库函数返回指示错误的值后立即检查它,并在需要时将其保存在另一个变量中为了以后保留它。
对于select
和大多数系统调用,指示错误的返回值为-1,这意味着如果它返回-1,则只应检查errno
。
答案 1 :(得分:9)
没有库函数将errno
设置为零。如果你想让它归零,你的程序必须这样做。
当函数说失败时,您只能有意义地测试errno
以获取信息(即使这样,只有当其手册页指示它设置errno
时)。您可以通过成功的函数将errno
设置为非零。例如,在Solaris上,在写入文件而不是终端时,经常在标准I / O调用后在errno
中找到ENOTTY。
在您的示例中,无法保证给定的错误调用函数将设置多个可能的错误值中的哪一个。只要报告一个有效的错误条件,由系统决定它报告的错误。所以,你需要给出一个令人信服的例子,说明为什么第二个调用应该返回EINVAL而不是EBADF;你写的问题没有包含足够的信息让我们认罪。
另请注意,声明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)
正如我之前所说,返回的错误取决于系统。