套接字超时设置

本文介绍了在网络编程中如何为套接字的读写及连接操作设置超时,包括使用alarm信号、select函数以及SO_RCVTIMEO/SO_SNDTIMEO选项的方法,并通过示例代码展示了利用select进行connect超时设置的过程。

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

来源:http://www.cnblogs.com/yuxingfirst/archive/2013/06/06/3120986.html


 我们知道,对于一个套接字的读写(read/write)操作默认是阻塞的,如果当前套接字还不可读/写,那么这个操作会一直阻塞下去,这样对于一个需要高性能的服务器来说,是不能接受的。所以,我们可以在进行读写操作的时候可以指定超时值,这样就读写操作就不至于一直阻塞下去。

  在涉及套接字的I/O操作上设置超时的方法有三种:

    1:调用alarm,它在指定的超时期满时产生SIGALRM信号。这个方法涉及信号处理,而信号处理在不同的实现上存在差异,而且可能干扰进程中现有的alarm调用。

    2:在select中阻塞等待I/O(select有内置的时间限制),依次代替直接阻塞在read或write调用上。(linux2.6以后的内核也可以使用epoll的epoll_wait)

    3:使用较新的SO_RCVTIMEO和SO_SNDTIMEO套接字选项。这个方法的问题在于并非所有的实现都支持这两个套接字选项。

  上述这三个技术都适用于输入和输出操作(read、write,及其变体recv/send, readv/writev, recvfrom,sendto)。不过我们也期待可以用于connect的技术,因为TCP内置的connect超时相当长(典型值为75秒),而我们在写服务器程序的时候,也不会希望一个连接的建立需要花费这么长时间。select可用来在connect上设置超时的先决条件是相应的套接字是非阻塞的,而那两个套接字选项对connect并不适用;同时也应当指出,前两个技术适用于任何描述符,而第三个技术仅仅适用于套接字描述符。

  下边我们主要展示利用select进行connect超时设置的实例(比较常用):  

?
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/select.h>
#include <time.h>
#define PORT 9900
#define MAXDATASIZE 5000
int  main( int  argc, char  **argv)
{
     int  sockfd,nbytes;
     char  buf[1024];
     struct  hostent *he;
     struct  sockaddr_in srvaddr;
     if (argc!=2)
     {
         perror ( "Usage:client hostname\n" );
         return  0;
     }
     if ((he=gethostbyname(argv[1]))==NULL)
     {
         perror ( "gethostbyname" );
         return  0;
     }
     if ((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)
     {
         perror ( "create socket error" );
         return  0;
     }
     bzero(&srvaddr, sizeof (srvaddr));
     srvaddr.sin_family=AF_INET;
     srvaddr.sin_port=htons(PORT);
     srvaddr.sin_addr=*(( struct  in_addr *)he->h_addr);
     fcntl(sockfd, F_SETFL, O_NONBLOCK);
     timeval timeout = {3, 0};
     if (connect(sockfd,( struct  sockaddr *)&srvaddr, sizeof ( struct  sockaddr)) == -1)
     {
         if ( errno  != EINPROGRESS ) {
             close(sockfd);
             perror ( "connect error" );
             return  0;
         }
     }
 
     fd_set readSet;
     FD_ZERO(&readSet);
     FD_ZERO(&writeSet);
     FD_SET(sockfd, &writeSet);
     int  ret = select(sockfd + 1, &readSet, &writeSet, NULL, &timeout);
     printf ( "%d" , ret);   
}   

 在打开套接字然后调用connect的时候,由于我们对套接字设置了O_NONBLOCK选项,所以此时connect不会阻塞,通常是会返回-1,然后errno被设置为EINPROGRESS,表示连接仍在进行中,所以在后边,我们只要将这个套接字注册到select的

可写集合中(writeSet,因为这里是去连接对端服务器),然后在调用select的时候设置超时值,如本例中设置为3秒;那么在3秒后,如果连接仍未建立,那么select将返回0,表示超时;如果在3秒内连接成功建立,套接字变为可写状态,那么select将返回1。

 注:关于另外两种方式,可以通过阅读:《unix网络编程》第一卷第14章。




在TCP套接字中,超时时间通常用于控制连接过程中的等待时间,以防长时间无响应导致资源浪费。有两种主要的超时设置:发送超时(SendTimeout)和接收超时(ReceiveTimeout)。 1. 发送超时(SendTimeout):这个超时发生在当你试图通过套接字发送数据,但连接尚未建立或者连接已断开的情况下。如果你设置了发送超时,那么`send()`或类似操作会在指定时间内没有收到确认消息时停止并返回错误。 2. 接收超时(ReceiveTimeout):当从远程主机接收数据时,如果没有新的数据到达,就会触发接收超时。这可以防止无限期阻塞在`recv()`调用上。例如,在`recvfrom()`或`poll()`等函数中设置接收缓冲区空闲的时间段。 在C/C++中,通常通过修改Socket选项来设置超时,例如在Linux中可以使用`setsockopt()`函数来设置`SO_SNDTIMEO`(发送超时)和`SO_RCVTIMEO`(接收超时)标志。对于特定的系统库(如Boost.Asio),也有专门的超时管理功能。 下面是一个简单的示例,展示了如何在连接过程中设置超时: ```cpp #include <boost/asio.hpp> // ... auto resolver = boost::asio::ip::resolve<boost::asio::ip::tcp>(host, port); boost::asio::deadline_socket socket(io_service); boost::asio::connect(socket, resolver, deadline); // 设置发送和接收超时 const auto deadline_time = std::chrono::seconds(5); // 5秒超时 socket.set_option(boost::asio::socket_base::send_timeout(deadline_time)); socket.set_option(boost::asio::socket_base::receive_timeout(deadline_time)); // 然后进行数据传输... ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值