Recvfrom 空缓冲区返回 errno EFAULT?
Recvfrom null buffer returning errno EFAULT?
我正在编写一个 UDP 非阻塞套接字并且我有这个功能
void recvflush(int sockfd) {
ssize_t num;
while (errno != EWOULDBLOCK) {
num = recvfrom(sockfd, NULL, maxpack, 0, NULL, NULL);
if (num < 0 && errno != EWOULDBLOCK)
error("recvfrom() failed", strerror(errno));
}
}
刷新接收缓冲区。但是,当我调用它时它返回 EFAULT(错误地址),并且我确保在我这样做时设置了 sockfd。求助!
谢谢
您是否有理由 期望 将 NULL
指针指向 recvfrom
会导致它刷新消息?你已经告诉它你的缓冲区是 maxpack
字节长,但是你给了它一个无效的指针,所以 EFAULT
是正确的和预期的 errno
.
您应该能够提供零的 length 来丢弃排队的消息:根据 recvfrom(2)
手册页,如果提供的缓冲区长度太短对于一条消息,剩余的数据字节将被丢弃;这应该包括丢弃 all 个字节。
现在,一旦您提供了零长度,您可以也提供一个NULL
指针,因为不需要缓冲区的任何部分是在那种情况下有效。但这并不是因为 NULL
指针被特别识别,而是因为提供的长度不需要它的任何部分指向有效内存。
根据 recvfrom()
的 man page,在以下情况下报告 EFAULT
:
EFAULT
The receive buffer pointer(s) point outside the process's address space.
假设您的 maxpack
变量 > 0,recvfrom()
期望能够将字节写入 buf
参数指向的缓冲区,但您正在传递 NULL
该参数,因此出现错误。
为什么要在调用 recvfrom()
之前检查 errno
?您应该先调用 recvfrom()
,然后检查错误。并在 any 错误 other than EWOULDBLOCK
/EAGAIN
, EINTR
, or [=24] 时停止循环=] 被报道。
此外,请记住 UDP 支持 0 长度数据包,在这种情况下 recvfrom()
将 return 0 而不是 -1,并且不会设置 errno
。确保在循环中也考虑到这一点。
试试这个:
void recvflush(int sockfd) {
ssize_t num;
do {
num = recvfrom(sockfd, NULL, 0, 0, NULL, NULL);
if (num < 0) {
if ((errno == EWOULDBLOCK) || (errno == EAGAIN))
break;
if ((errno != EINTR) && (errno != EMSGSIZE)) {
error("recvfrom() failed", strerror(errno));
break;
}
}
}
while (true);
}
或者,如果 recvfrom()
不接受长度为 0 的缓冲区,则给它一个小缓冲区来写入:
void recvflush(int sockfd) {
ssize_t num;
char c;
do {
num = recvfrom(sockfd, &c, 1, 0, NULL, NULL);
if (num < 0) {
if ((errno == EWOULDBLOCK) || (errno == EAGAIN))
break;
if ((errno != EINTR) && (errno != EMSGSIZE)) {
error("recvfrom() failed", strerror(errno));
break;
}
}
}
while (true);
}
请注意,如果您的套接字不是非阻塞的,那么 EWOULDBLOCK
/EAGAIN
将不会被报告,因为调用将阻塞直到数据可用,因此您应该使用 select()
或 (e)poll()
在进入 recvfrom()
循环之前检查套接字是否有任何排队的数据包。
我正在编写一个 UDP 非阻塞套接字并且我有这个功能
void recvflush(int sockfd) {
ssize_t num;
while (errno != EWOULDBLOCK) {
num = recvfrom(sockfd, NULL, maxpack, 0, NULL, NULL);
if (num < 0 && errno != EWOULDBLOCK)
error("recvfrom() failed", strerror(errno));
}
}
刷新接收缓冲区。但是,当我调用它时它返回 EFAULT(错误地址),并且我确保在我这样做时设置了 sockfd。求助!
谢谢
您是否有理由 期望 将 NULL
指针指向 recvfrom
会导致它刷新消息?你已经告诉它你的缓冲区是 maxpack
字节长,但是你给了它一个无效的指针,所以 EFAULT
是正确的和预期的 errno
.
您应该能够提供零的 length 来丢弃排队的消息:根据 recvfrom(2)
手册页,如果提供的缓冲区长度太短对于一条消息,剩余的数据字节将被丢弃;这应该包括丢弃 all 个字节。
现在,一旦您提供了零长度,您可以也提供一个NULL
指针,因为不需要缓冲区的任何部分是在那种情况下有效。但这并不是因为 NULL
指针被特别识别,而是因为提供的长度不需要它的任何部分指向有效内存。
根据 recvfrom()
的 man page,在以下情况下报告 EFAULT
:
EFAULT
The receive buffer pointer(s) point outside the process's address space.
假设您的 maxpack
变量 > 0,recvfrom()
期望能够将字节写入 buf
参数指向的缓冲区,但您正在传递 NULL
该参数,因此出现错误。
为什么要在调用 recvfrom()
之前检查 errno
?您应该先调用 recvfrom()
,然后检查错误。并在 any 错误 other than EWOULDBLOCK
/EAGAIN
, EINTR
, or [=24] 时停止循环=] 被报道。
此外,请记住 UDP 支持 0 长度数据包,在这种情况下 recvfrom()
将 return 0 而不是 -1,并且不会设置 errno
。确保在循环中也考虑到这一点。
试试这个:
void recvflush(int sockfd) {
ssize_t num;
do {
num = recvfrom(sockfd, NULL, 0, 0, NULL, NULL);
if (num < 0) {
if ((errno == EWOULDBLOCK) || (errno == EAGAIN))
break;
if ((errno != EINTR) && (errno != EMSGSIZE)) {
error("recvfrom() failed", strerror(errno));
break;
}
}
}
while (true);
}
或者,如果 recvfrom()
不接受长度为 0 的缓冲区,则给它一个小缓冲区来写入:
void recvflush(int sockfd) {
ssize_t num;
char c;
do {
num = recvfrom(sockfd, &c, 1, 0, NULL, NULL);
if (num < 0) {
if ((errno == EWOULDBLOCK) || (errno == EAGAIN))
break;
if ((errno != EINTR) && (errno != EMSGSIZE)) {
error("recvfrom() failed", strerror(errno));
break;
}
}
}
while (true);
}
请注意,如果您的套接字不是非阻塞的,那么 EWOULDBLOCK
/EAGAIN
将不会被报告,因为调用将阻塞直到数据可用,因此您应该使用 select()
或 (e)poll()
在进入 recvfrom()
循环之前检查套接字是否有任何排队的数据包。