网络超时检测-setsockopt()

通过setsockopt函数可以一次性设置所有阻塞函数的超时时间,当达到设定的秒数和微秒后,系统会将阻塞操作视为错误,返回值小于0。示例中展示了如何设置SO_RCVTIMEO,以5秒作为超时时间。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

setsockopt()函数
1、使用setsockopt()实现超时检测时相比其他两种方式的特点是:
只要调用setsockopt函数一次,函数下发所有阻塞函数均可使用,且永久有效。
阻塞函数在到达设置的时间时,会被系统认定为错误,使阻塞函数返回值小于0;

#include <sys/socket.h>

int setsockopt(int socket, int level, int option_name,
          const void *option_value, socklen_t option_len);
功能:设置套接字相关的选项信息
参数:
    socket: 文件描述符

    level: 对应协议层
        SOL_SOCKET 应用层
        IPPROTO_TCP TCP层
        IPPROTO_IP IP层

    option_name:选项的名称
        SO_BROADCAST 允许发送广播 int
        SO_REUSEADDR 允许重复使用地址 int
        SO_SNDBUF 获取发送缓冲器大小
        SO_RCVBUF 获取接收缓冲区大小
        SO_RCVTIMEO 设置接收超时时间
        SO_SNDTIMEO 设置发送超时时间

    option_value:对应选项的值

    option_len:大小

返回值:
    成功:0
    失败:-1

SO_RCVTIMEO 设置接收超时时间
+++++++++++++++++++++++++++++++++++++
struct timeval {
int tv_sec; 秒
int tv_usec; 微秒
};
+++++++++++++++++++++++++++++++++++++

//使用setsockopt实现网络超时检测
//setsockopt函数只要调用一次,下方所有的阻塞函数都会使用,并永久有效

struct timeval out_time;
out_time.tv_sec = 5;
out_time.tv_usec = 0;

if(setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &out_time, sizeof(out_time)) < 0)
{
errlog(“fail to setsockopt”);
}

下面上实例:

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>

#define N 128

#define errlog(errmsg) do{perror(errmsg); exit(1);}while(0)

int main(int argc, const char *argv[])
{
    int sockfd;
    struct sockaddr_in serveraddr, clientaddr;
    int acceptfd;
    socklen_t addrlen = sizeof(struct sockaddr_in);

    char buf[N] = {};

    //创建套接字
    if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        errlog("fail to socket");
    }

    //填充网络信息结构体
    //inet_addr 将点分十进制转化成网络字节
    //htons表示将主机字节序转化成网络字节序
    //atoi 将字符串转化成整型数据
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
    serveraddr.sin_port = htons(atoi(argv[2]));

    //将套接字与IP地址和端口号绑定
    if(bind(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0)
    {
        errlog("fail to bind");
    }

    //将套接字设置为被动监听状态
    if(listen(sockfd, 10) < 0)
    {
        errlog("fail to listen");
    }

    //使用setsockopt实现网络超时检测
    //setsockopt函数只要调用一次,下方所有的阻塞函数都会使用,并永久有效

    struct timeval out_time;     // 结构体原型可以用“ vim -t timeval ”来查看
    out_time.tv_sec = 5;          //设置超时检测的时间为5秒
    out_time.tv_usec = 0;

    if(setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &out_time, sizeof(out_time)) < 0)
    {
        errlog("fail to setsockopt");
    }
        //setsockopt函数在调用之后,所有的阻塞等待函数就上了一个计时器,例如设定时间为5秒,在阻塞了4秒后,第5秒
        //仍没有接收到数据的话,系统会认定这个阻塞函数错误。此时,函数(以accept函数为例,其他函数暂未实验)返回
        //失败 -1 ,在返回失败后,进入if(errno == 11)函数内,打印timeout.
        //验证:把if(errno == 11){printf("timeout\n");}删除后,调用函数,程序在阻塞4秒后,在第5秒时,
        //执行了errlog("fail to accept"),在终端打印了错误信息后,退出了程序。
    while(1)
    {
        //接收客户端的连接请求
        if((acceptfd = accept(sockfd, (struct sockaddr *)&clientaddr, &addrlen)) < 0)
        {
            //printf("errno = %d\n", errno); errno =11
            //代表此时超时检测错误信息,不应退出
            if(errno == 11)
            {
                printf("accept timeout ...\n");
            }
            else 
            {
                errlog("fail to accept");
            }
        }
        else
        {

            printf("%s ---> %d\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));

            //与客户端进行通信
            while(1)
            {
                if(recv(acceptfd, buf, N, 0) < 0)
                {
                    //printf("errno = %d\n", errno);
                    if(errno == 11)
                    {
                        printf("recv timeout ...\n");
                    }
                    else 
                    {
                        errlog("fail to recv");
                    }
                }
                else
                {

                    if(strncmp(buf, "quit", 4) == 0)
                    {
                        printf("%s is quited...\n", inet_ntoa(clientaddr.sin_addr));
                        break;
                    }
                    else
                    {
                        printf("from client >>> %s\n", buf);

                        strcat(buf, " from server...");

                        if(send(acceptfd, buf, N, 0) < 0)
                        {
                            errlog("fail to send");
                        }
                    }
                }
            }
        }
    }

    close(sockfd);
    close(acceptfd);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值