Recvfrom 空缓冲区返回 errno EFAULT?
Posted
技术标签:
【中文标题】Recvfrom 空缓冲区返回 errno EFAULT?【英文标题】:Recvfrom null buffer returning errno EFAULT? 【发布时间】:2018-07-12 23:04:32 【问题描述】:我正在编写一个 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()
的想法?这就是它崩溃的原因,因为操作系统无法将接收到的数据写入该“地址”。您可能必须分配一个本地缓冲区 (char buf[1500];
) 才能读入,即使您只是要将数据丢弃。
想一想,因为多余的数据(来自太大而无法放入用户提供的缓冲区的数据包)被丢弃,我想您可以使用char buf[1]
。
【参考方案1】:
您是否出于某种原因期望将NULL
指针指向recvfrom
会导致它刷新消息?你已经告诉它你的缓冲区是maxpack
字节长,但是你给了它一个无效的指针,所以EFAULT
是正确的和预期的errno
。
您应该能够提供 length 为零来丢弃排队的消息:根据recvfrom(2)
手册页,如果提供的缓冲区长度对于消息来说太短,则剩余数据字节将被丢弃;这应该包括丢弃所有个字节。
现在,一旦您提供了一个零长度,您也可以提供一个NULL
指针,因为在这种情况下不需要缓冲区的任何部分都有效。但这并不是因为 NULL
指针被特别识别,而是因为提供的长度不需要它的任何部分指向有效内存。
【讨论】:
啊,好吧。很好的答案,听起来很完美。我只是想我不妨保留maxpack
字节作为参数,因为无论如何我都将它设置为信号处理程序的全局。我想把 0 但一开始我有点怀疑。谢谢!【参考方案2】:
根据man page 的recvfrom()
,EFAULT
在以下情况下报告:
失败 接收缓冲区指针指向进程地址空间之外。
假设您的 maxpack
变量 > 0,recvfrom()
期望能够将字节写入 buf
参数指向的缓冲区,但您正在为该参数传递 NULL
,因此出现错误.
为什么在调用recvfrom()
之前检查errno
?您应该首先调用recvfrom()
,然后检查错误。并在报告任何错误除了EWOULDBLOCK
/EAGAIN
、EINTR
或EMSGSIZE
时停止循环。
另外,请记住,UDP 支持长度为 0 的数据包,在这种情况下,recvfrom()
将返回 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()
循环之前有任何排队的数据包。
【讨论】:
***.com/questions/2178115/…,但是你的情况是便携的没关系(我认为,无限循环有时很棘手)以上是关于Recvfrom 空缓冲区返回 errno EFAULT?的主要内容,如果未能解决你的问题,请参考以下文章