Recvfrom null缓冲区返回errno EFAULT?
我正在编程一个UDP非阻塞套接字,我有这个函数Recvfrom null缓冲区返回errno EFAULT?,c,sockets,null,asyncsocket,errno,C,Sockets,Null,Asyncsocket,Errno,我正在编程一个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", strerr
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));
}
}
void recvflush(int sockfd){
ssize_t num;
while(errno!=ewooldblock){
num=recvfrom(sockfd,NULL,maxpack,0,NULL,NULL);
if(num<0&&errno!=ewooldblock)
错误(“recvfrom()失败”,strerror(errno));
}
}
刷新接收缓冲区。然而,当我调用它时,它返回EFAULT(坏地址),并且我确保在调用时设置了sockfd。救命啊
谢谢您是否有理由认为给NULL
指针指向recvfrom
会导致它刷新消息?您告诉它您的缓冲区是maxpack
字节长的,但随后您给了它一个无效的指针,因此EFAULT
是正确的且预期的errno
您应该能够提供零长度来丢弃排队消息:根据recvfrom(2)
手册页,如果提供的缓冲区长度对于消息来说太短,剩余的数据字节将被丢弃;这应该包括丢弃所有字节
现在,一旦提供了长度为零,还可以提供NULL
指针,因为在这种情况下缓冲区的任何部分都不需要有效。但这并不是因为NULL
指针是专门识别的,而是因为提供的长度不需要它的任何部分来指向有效内存。您是否有理由认为给NULL
指针指向recvfrom
会导致它刷新消息?您告诉它您的缓冲区是maxpack
字节长的,但随后您给了它一个无效的指针,因此EFAULT
是正确的且预期的errno
您应该能够提供零长度来丢弃排队消息:根据recvfrom(2)
手册页,如果提供的缓冲区长度对于消息来说太短,剩余的数据字节将被丢弃;这应该包括丢弃所有字节
现在,一旦提供了长度为零,还可以提供NULL
指针,因为在这种情况下缓冲区的任何部分都不需要有效。但这并不是因为专门识别NULL
指针,而是因为提供的长度不需要它的任何部分来指向有效内存。根据forrecvfrom()
,在以下情况下报告EFAULT
:
EFAULT接收缓冲区指针指向进程的地址空间之外 假设您的
maxpack
变量为>0,recvfrom()
希望能够将字节写入buf
参数所指向的缓冲区,但您正在为该参数传递NULL
,因此出现错误
为什么在调用recvfrom()
之前要检查errno
?您应该先调用recvfrom()
,然后检查是否有错误。并在报告除eWoldBlock
/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);
}
请注意,如果您的套接字不是非阻塞的,则不会报告eWoldBlock
/EAGAIN
,因为调用将阻塞直到数据可用,因此您应该使用select()
或(e)poll()
在进入recvfrom()之前检查套接字是否有任何排队的数据包
循环。对于recvfrom()
,在以下情况下报告EFAULT
:
EFAULT接收缓冲区指针指向进程的地址空间之外 假设您的
maxpack
变量为>0,recvfrom()
希望能够将字节写入buf
参数所指向的缓冲区,但您正在为该参数传递NULL
,因此出现错误
为什么在调用recvfrom()
之前要检查errno
?您应该先调用recvfrom()
,然后检查是否有错误。并在报告除eWoldBlock
/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);
}
请注意,如果您的套接字不是非阻塞的,则不会报告
eWoldBlock
/EAGAIN
,因为调用将阻塞直到数据可用,因此您应该使用select()
或(e)poll()
在进入recvfrom()之前检查套接字是否有任何排队的数据包
循环。你从哪里想到可以将NULL
作为第二个参数传递给recvfrom()
?这就是它崩溃的原因,因为操作系统无法将接收到的数据写入该“地址”。您可能需要分配一个本地缓冲区(char-buf[1500];
)来读取数据,即使您只是将数据扔掉。想想看,由于多余的数据(来自用户提供的缓冲区中太大而无法容纳的数据包)被丢弃,我想您可以使用char-buf[1]进行读取
。您从哪里想到可以将NULL
作为第二个参数传递给recvfrom()
?这就是它崩溃的原因,因为操作系统无法将接收到的数据写入该“地址”。您可能需要分配一个本地缓冲区(char buf[1500];
)来读取数据,即使您只是想扔掉数据