定时器实现超时发送/接收和定期检测非活动连接

《Linux高性能服务器编程》阅读笔记:

1. socket的发送/接收超时

 在Linux网络编程基础–socket常用选项中讲道,socket选项SO_RCVTIMEOSO_SNDTIMEO分别用来设置socket接收数据超时和发送数据超时时间,这两个选项仅对与数据接收/发送相关的socket系统调用都有效,具体如下:
这里写图片描述
 在程序中上面的系统调用可以根据其返回值和errno来判断是否超时,进而决定是否开始处理定时任务。
 以客户端的connect()为例,该函数是向客户端发起连接请求,通过三次握手和服务端建立通信连接。需要注意这个操作不一定100%成功,可能某次握手失败了,这时候TCP协议要求重新从第一次开始握手。我们可以通过SO_SNDTIMEO可以设置建立连接过程的超时时间,在超时时间范围内没有成功建立连接则失败返回。

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <errno.h>

int main(void)
{
    const char* ip = "192.168.239.136";
    int port = 9660;
    int ret;

    //创建套接字
    int sockfd = socket(PF_INET, SOCK_STREAM, 0);

    //设置套接字的发送超时时间为10s
    struct timeval timeout;
    timeout.tv_sec = 10;
    timeout.tv_usec = 0;
    socklen_t len = sizeof(timeout);
    ret = setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, &timeout, len);

    //连接目标服务器
    struct sockaddr_in addr;
    bzero(&addr, sizeof(addr));
    addr.sin_family = AF_INET;
    inet_pton(AF_INET, ip, &addr.sin_addr);
    addr.sin_port = htons(port);
    ret = connect(sockfd, (struct sockaddr*)&addr, sizeof(addr));
    if (ret == -1)
    {
        if (errno == EINPROGRESS)
        {
            printf("connect timeout\n");
            return -1;
        }
        printf("errno occur when connect to server\n");
        perror("connect");
        return -1;
    }    

    return 0;
}

2. 服务端处理非活动的连接

 超时事件也是网络程序需要处理的事件,比如下面讲到的服务端定期检验一个客户端连接的活动状态。通常服务器程序需要管理众多定时事件,所以需要程序有效组织这些事件,使之能在预期的时间点触发且不影响程序逻辑。
 在这里我们将所有定时器及对应超时时间存放在升序双向链表中,在超时处理函数中依次处理所有到期的定时器事件,以实现对定时事件的统一管理。升序定时器链表定义如下:

#ifndef LST_TIMER
#define LST_TIMER

#include <time.h>
#define BUFFER_SZ   64

struct cli_data;


//定时器节点和用户数据相互包含,这样可以通过整个程序使用的定时器找到用户数据,也可以通过用户数据找到整个程序使用的定时器链表
//定时器节点
class util_timer
{
public:    
    time_t expire;               /* 任务的超时时间 */
    void (*cb_func)(cli_data* ); /* 任务回调函数 */
    util_timer* pre;
    util_timer* next;
    cli_data *user_data;

    util_timer() : pre(NULL), next(NULL) {}
};

//用户数据结构
struct cli_data
{
    sockaddr_in addr;
    int sockfd;
    char buf[BUFFER_SZ];
    util_timer* timer;
};

//链表操作函数类
class sort_timer_lst
{
public
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值