4. 编程应用

本节介绍创建使用 keepalive 的应用程序所需的编程代码。这不是一本编程手册,它要求您事先掌握 C 编程和网络概念的知识。我假设您熟悉套接字以及与应用程序的总体方面相关的所有内容。

4.1. 代码何时需要 keepalive 支持

并非所有网络应用程序都需要 keepalive 支持。请记住,这是 TCP keepalive 支持。因此,您可以想象,只有 TCP 套接字才能利用它。

在编写应用程序时,您可以做的最棒的事情是使其尽可能可定制,而不是强制用户做出决定。如果您想考虑用户的满意度,则应实现 keepalive,并让用户通过使用配置参数或命令行开关来决定是否要使用它。

4.2.setsockopt函数调用

要为特定套接字启用 keepalive,您只需在套接字本身上设置特定的套接字选项即可。该函数的原型如下:

  int setsockopt(int s, int level, int optname,
                 const void *optval, socklen_t optlen)
      

第一个参数是套接字,之前使用 socket(2) 创建的;第二个参数必须是SOL_SOCKET,第三个参数必须是SO_KEEPALIVE。第四个参数必须是布尔整数值,指示我们要启用该选项,而最后一个参数是之前传递的值的大小。

根据 manpage,成功时返回 0,错误时返回 -1(并且errno已正确设置)。

在编写应用程序时,您还可以为 keepalive 设置另外三个套接字选项。它们都使用SOL_TCP级别,而不是SOL_SOCKET,它们仅针对当前套接字覆盖系统级变量。如果您先读取而不写入,则将返回当前的系统级参数。

4.3. 代码示例

这是一个小例子,它创建一个套接字,显示 keepalive 已禁用,然后启用它并检查该选项是否已有效设置。

            /* --- begin of keepalive test program --- */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

int main(void);

int main()
{
   int s;
   int optval;
   socklen_t optlen = sizeof(optval);

   /* Create the socket */
   if((s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
      perror("socket()");
      exit(EXIT_FAILURE);
   }

   /* Check the status for the keepalive option */
   if(getsockopt(s, SOL_SOCKET, SO_KEEPALIVE, &optval, &optlen) < 0) {
      perror("getsockopt()");
      close(s);
      exit(EXIT_FAILURE);
   }
   printf("SO_KEEPALIVE is %s\n", (optval ? "ON" : "OFF"));

   /* Set the option active */
   optval = 1;
   optlen = sizeof(optval);
   if(setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, &optval, optlen) < 0) {
      perror("setsockopt()");
      close(s);
      exit(EXIT_FAILURE);
   }
   printf("SO_KEEPALIVE set on socket\n");

   /* Check the status again */
   if(getsockopt(s, SOL_SOCKET, SO_KEEPALIVE, &optval, &optlen) < 0) {
      perror("getsockopt()");
      close(s);
      exit(EXIT_FAILURE);
   }
   printf("SO_KEEPALIVE is %s\n", (optval ? "ON" : "OFF"));

   close(s);

   exit(EXIT_SUCCESS);
}

            /* ---  end of keepalive test program  --- */