【问题标题】:C: Writing a proper time-outC:写一个适当的超时
【发布时间】:2013-05-05 05:55:45
【问题描述】:

在仔细搜索资源后,我仍然不完全确定如何在 C 中编写适当且可用的计时器函数。我没有使用线程(或可并行代码)。我只是想写一个秒表函数,我可以在经过一小段时间后使用它来触发一些代码。

这是计时器的一种非常常见的用法,在“超时”的情况下,我设置了一个客户端-服务器,客户端正在发送一些数据(带有 sendto(...) 的 UDP 样式和recvfrom(...))。我已经编写了我的系统,以便客户端在我定义的数据包结构中发送一大块数据,然后服务器通过 CRC 对其进行处理,然后发回一个确认数据包 (ACK),表明接收到的消息未损坏。但是,我想实现一个超时,如果客户端在一段时间内没有收到 ACK,客户端会重新发送数据块(当然服务器被操纵来检查重复项)。我想在客户端中嵌套这段定时器代码,不知为何觉得这应该不是那么难。

我从很久以前所做的工作中挖掘出旧的信号处理代码,因为这似乎是我通常认为作为解决方案提到的唯一方法,有人可以指导我如何使用以下信号处理代码不仅接收定时信号,而且触发某种动作。从概念上讲,我觉得它是:“发送数据,启动计时器,计时器到期后执行重新发送,重置计时器......重复直到收到 ACK”。更好的是,这将是编写计时器函数的一种更简单的方法,但鉴于 C 是一种低级语言,这似乎没有太大希望......

#include <sys/time.h>
#include <errno.h>
#include <stdio.h>
#include <signal.h>

extern char *strsignal(int sig);

void timer_handler(int a)
{
  // handle signal
  printf(">>>> signal caught\n");
  printf(">>>>    int parameter = %s\n", (char*) strsignal(a));
}

int main(int argc, char* argv[])
{
  int retval;
  struct itimerval timerValue;
  struct itimerval oldTimerValue;
  struct sigaction action;

  action.sa_handler = &timer_handler;
  action.sa_flags = SA_NODEFER;

  // initialize timer parameters: expires in 5 seconds
  timerValue.it_interval.tv_sec = 5;
  timerValue.it_interval.tv_usec = 0;

  timerValue.it_value.tv_sec = 5;
  timerValue.it_value.tv_usec = 0;

  // install signal handler to catch SIGALRM
  //signal(SIGALRM, timer_handler);
  sigaction(SIGALRM, &action, NULL);

  retval = setitimer(ITIMER_REAL, &timerValue, &oldTimerValue);

  if (-1 == retval)
    perror("Could not set timer");

  while(1);

  return 0;
}

【问题讨论】:

  • 您应该查看select 函数,它允许您等待在套接字处接收数据,以及指定超时值。这听起来像你想要的吗?
  • 感谢@Xymotech。非常感谢,我在“我最终做了什么”的回答中感谢了你,因为你是指出使用“选择”的人。

标签: c timer timeout signals handler


【解决方案1】:

Xymotech 提供了我需要的确切功能,在咨询了“select”的 API 之后,其中包括一个小的使用示例,我修改了那里的代码以适应我的需要并编写了一个套接字计时器(对于读取,它非常简单扩展到写入等,因为“选择”具有启用这种检查的参数)。确保您已包含“选择”API 指定的以下库:

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <stdio.h>

以下是我从 API 示例创建的 waittoread(...) 函数,并且运行良好。这在我的特定问题的领域中效果很好,但是,如果有人正在寻找更通用的计时器(即不仅仅是用于定时套接字读取和写入或文件描述符),请咨询信号处理(有点符合我的代码的精神)发布在我最初的问题中)。

#define S1READY 0x01 // necessary for the function's bitwise OR operation
int waittoread(int s1, int timeout_value){
   fd_set fds; // create set of sockets to be waited on
   struct timeval timeout; // the time-out value
   int rc; // # of sockets that are ready before timer expires
   int result;

   /* Set time limit. */
   timeout.tv_sec = timeout_value;
   timeout.tv_usec = 0;
   /* Create a descriptor set containing the socket.  */
   FD_ZERO(&fds); // MACRO to reset the socket storage set so new ones can be added
   FD_SET(s1, &fds); // add the socket descriptor into the socket set to wait on
   rc = select(sizeof(fds)*4, &fds, NULL, NULL, &timeout); // build the socket-wait system
   // another way of calling select that would be a better approach:
   // rc = select(s1 + 1), &fds, NULL, NULL, &timeout);
   if (rc==-1) {
      perror("Error:  Call to select failed.");
      return -1;
   }
   result = 0;
   if (rc > 0){
      if (FD_ISSET(s1, &fds)) result |= S1READY;  // if the result is non-zero, perform a BIT-wise OR to extract the true socket count #
   }
   return result;
}

【讨论】:

  • select 的第一个参数应该是您要等待的最大文件描述符的加一。所以在这种情况下,你应该使用s1+1
  • 你是对的,有趣的是两者都可以工作,因为上面的代码工作得很好(产生了相同的结果)。但是,按照您建议的方式进行操作确实有意义(我只是遵循在线资源中示例的精神)。在我测试时,我将在评论中使用您的方法更新上述内容,并且效果也很好。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-12-30
  • 2016-01-07
  • 1970-01-01
  • 2021-08-25
  • 1970-01-01
  • 1970-01-01
  • 2017-07-29
相关资源
最近更新 更多