设置socket超时时间的两种方式

最近在编写fastcgi中,要通过udp请求后台其他服务数据。如果使用阻塞socket,万一由于网络等原因没有数据包返回,那么recvfrom将一直阻塞;如果使用非阻塞socket,后端服务还没有处理完请求返回数据前,recvfrom很可能已经返回了,从而接受不到响应数据包。所以这时就要设置超时时间,如果该socket超时之后仍然没有数据包到来,那么就直接返回。

设置socket超时时间的两种方式:

1、比较简洁的方式:利用setsockopt的SO_RCVTIMEO选项

#include <iostream>
#include <string>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <errno.h>
int main() 
{
    int fd = socket(AF_INET, SOCK_DGRAM, 0);
    if (fd < 0) {
        printf("fait to create socket\n");
        return -1;
    }
    struct timeval timeout_val;
    timeout_val.tv_sec = 5;  // 超时时间
    timeout_val.tv_usec = 0;
    if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeout_val, sizeof(timeout_val))
        < 0) {  
        printf("socket option  SO_RCVTIMEO not support\n");  
        return -1;  
    }
    struct sockaddr_in server_addr;
    bzero(&server_addr, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    server_addr.sin_port = htons(2222);

    char buf[1024] = "aaaaaaaaaa";
    if (sendto(fd, buf, strlen(buf) , 0, (struct sockaddr*)&server_addr,
        sizeof(server_addr)) < 0) {
        printf("fail to sendto\n");
        return -1;
    }
    sockaddr_in peer_addr;
    socklen_t addr_len = sizeof(peer_addr);
    int recv_len = 0;
    bzero(buf, sizeof(buf));
    time_t start_time = time(NULL);
    recv_len = recvfrom(fd, buf, sizeof(buf), 0,
                            reinterpret_cast<sockaddr*>(&peer_addr),
                            &addr_len);
    printf("time_out=%d\n", time(NULL) - start_time);                        
    if (errno == EWOULDBLOCK || errno== EAGAIN)  
        printf("recvfrom timeout\n");  
    else  
        printf("recvfrom err:%d\n", recv_len); 
    return 0;
}

2、稍微复杂的方式:利用select

#include <iostream>
#include <string>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <errno.h>
int main() 
{
    int fd = socket(AF_INET, SOCK_DGRAM, 0);
    if (fd < 0) {
        printf("fait to create socket\n");
        return -1;
    }
    struct sockaddr_in server_addr;
    bzero(&server_addr, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    server_addr.sin_port = htons(2222);

    char buf[1024] = "aaaaaaaaaa";
    if (sendto(fd, buf, strlen(buf) , 0, (struct sockaddr*)&server_addr, sizeof(server_addr))
        < 0) {
        printf("fail to sendto\n");
        return -1;
    }
    sockaddr_in peer_addr;
    socklen_t addr_len = sizeof(peer_addr);
    int recv_len = 0;
    bzero(buf, sizeof(buf));

    fd_set reasfds;
    FD_ZERO(&reasfds);
    FD_SET(fd, &reasfds);
    struct timeval timeout_val;
    timeout_val.tv_sec = 5;
    timeout_val.tv_usec = 0;
    int ret = select(fd+1, &reasfds, NULL, NULL, &timeout_val);
    if (ret > 0) {
        recv_len = recvfrom(fd, buf, sizeof(buf), 0,
                            reinterpret_cast<sockaddr*>(&peer_addr),
                            &addr_len);
        if (recv_len < 0)
            printf("recvfrom err, errno=%d\n", errno);
    } else if (ret == 0) {
        printf("recvfrom timeout\n"); 
    } else {
        printf("select err, errno=%d\n", errno);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值