从null缓冲区返回errno EFAULT吗?

时间:2018-07-12 23:04:33

标签: 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", strerror(errno));
  }
}

刷新接收缓冲区。但是,当我调用它时,它将返回EFAULT(错误地址),并且我确定在设置时已设置了sockfd。救命!

谢谢

2 个答案:

答案 0 :(得分:2)

您是否出于某些原因期望,将NULL指针指向recvfrom会导致它刷新消息?您已经告诉它缓冲区的长度为maxpack个字节,但是随后给了它一个无效的指针,所以EFAULT是正确的和预期的errno

您应该能够提供为零的 length 来丢弃排队的消息:根据recvfrom(2)手册页,如果提供的缓冲区长度对于消息来说太短,则剩余的数据字节将被丢弃;其中应包括丢弃所有所有个字节。

现在,一旦提供了零长度,就可以 提供一个NULL指针,因为在这种情况下,不需要缓冲区的任何部分都有效。但这不是因为NULL指针被特别识别,而是因为提供的长度不需要指向它的任何部分即可指向有效内存。

答案 1 :(得分:0)

根据function logInvoice() { const wb = SpreadsheetApp.getActive(); // 'const' means we will not change what 'wb' means. const sales = wb.getSheetByName("Sales Reports"); var lastSalesRow = sales.getLastRow(); // not 'const' since we will re-assign this primitive. const invoice = wb.getSheetByName("Invoice"); const fullReport = invoice.getDataRange().getValues(); // Gets A1:___ into a 2D JS array const data = [ fullReport[2][4], // E3 fullReport[1][4], // E2 /** I really don't know what you were doing with "=row() + 100000 - 2". If * you were just trying to get a unique identifier, then use the next line: */ // Utilities.getUuid(), fullReport[29][4], // E30 /** * add more elements as needed */ ]; // Write the summary data to the next row in the 'Sales Reports' sheet. // Grabs the cell "A#" and then uses the size of the data to write to determine // the size of the Range required. sales.getRange(++lastSalesRow, 1, data.length, data[0].length).setValues(data); // Reset the Invoice sheet to its blank slate. invoice.getRangeList([ "C6", // R6C3 "B12:C28", "E29" ]).clearContent(); } 的{​​{3}},在以下情况下报告recvfrom()

  

EFAULT
  接收缓冲区指针指向进程的地址空间之外。

假设您的EFAULT变量> 0,则maxpack希望能够将字节写入recvfrom()参数所指向的缓冲区,但是您正在传递{{1} }表示该参数,因此会出错。

为什么在致电buf之前先检查NULL?您应该先致电errno,然后检查错误。并且在报告了任何错误 {em> recvfrom() / recvfrom()EWOULDBLOCKEAGAIN以外的错误时停止循环。 / p>

还要记住,UDP支持长度为0的数据包,在这种情况下,EINTR将返回0而不是-1,并且不会设置EMSGSIZE。确保在循环中也考虑到这一点。

尝试以下方法:

recvfrom()

或者,如果errno不接受长度为0的缓冲区,则给它一个小的缓冲区以写入:

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() / 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); } ,因为该调用将在数据可用之前阻塞,因此应使用EWOULDBLOCKEAGAIN在进入select()循环之前检查套接字是否有排队的数据包。