php socket read超时,[转]socket超时设置详解(connect/read/write)

本文详细介绍了如何在PHP的Socket编程中设置超时,包括connect、read、write操作的超时处理。介绍了三种设置超时的方法,并强调了阻塞和非阻塞模式下connect的超时问题,以及如何使用setsockopt设置SO_RECVTIMEO和SO_SNDTIMEO套接字选项。提供了一段测试代码,展示了如何在阻塞和非阻塞模式下实现带超时的connect。

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

https://blog.youkuaiyun.com/gettogetto/article/details/77105005

一.基本概念(摘自:《unix网络编程》卷1 14.2 套接字超时)

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

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

(2)在select中阻塞等待I/O(select有内置的时间限制),以此替代直接阻塞在read或write调用上。

(3)使用SO_RECVTIMEO和SO_SNDTIMEO套接字选项

上述三个技术都适用于输入输出操作(例如read、write及其诸如recvfrom、sendto之类的变体),不过我们依然期待可用于connect的技术,因为TCP内置的connect超时相当长(典型值为75秒钟)。select可用来在connect上设置超时的先决条件是相应的套接字是处于非阻塞模式,而那两个套接字选项对connect并不适用。我们还指出,前两个技术适用于任何描述符,而第三个技术仅仅适用于套接字描述符。

注:阻塞模式下,当服务器连接不上时,通过命令 “netstat -tlnap|grep SENT" 可以看到客户端会处于SYN_SENT状态,直到connect超时

二.非阻塞模式socket

1.connect不需要考虑超时问题,立即返回一个错误EINPROGRESS,可通过检测fd是否可用判断连接是否建立完成

2.read不需要考虑超时问题,立即返回

3.write不需要考虑超时问题,立即返回

三.阻塞模式socket

1.connect需要考虑超时问题,否则当连接IP不可达的情况下,需要等待很长一段时间(默认时长)

2.read需要考虑超时问题,可通过setsockopt设置SO_RECVTIMEO选项

3.write需要考虑超时问题,可通过setsockopt设置SO_SNDTIMEO选项

四.带超时的connect,适用于阻塞模式与非阻塞模式socket(本质上是非阻塞connect)

附上测试代码,可通过更改main中的IP和端口进行测试,读懂这段代码需要了解select与getsockopt函数

-----  g++ connect_nonb.cpp -----

1 #include

2 #include

3 #include

4 #include

5 #include

6 #include

7 #include

8 #include

9 #include

10 #include

11 #include

12

13 int connect_nonb(int sockfd, const struct sockaddr *addr, socklen_t addrlen, intnsec)14 {15 intflags, n, error;16 socklen_t len;17 fd_set rset, wset;18 structtimeval tval;19

20 /*调用fcntl把套接字设置为非阻塞*/

21 flags = fcntl(sockfd, F_GETFL, 0);22 fcntl(sockfd, F_SETFL, flags |O_NONBLOCK);23

24 /*发起非阻塞connect。期望的错误是EINPROGRESS,表示连接建立已经启动但是尚未完成*/

25 error = 0;26 if ( (n = connect(sockfd, addr, addrlen)) < 0)27 if (errno !=EINPROGRESS)28 return(-1);29

30 /*如果非阻塞connect返回0,那么连接已经建立。当服务器处于客户端所在主机时这种情况可能发生*/

31 if (n == 0)32 goto done; /*connect completed immediately*/

33

34 /*调用select等待套接字变为可读或可写,如果select返回0,那么表示超时*/

35 FD_ZERO(&rset);36 FD_SET(sockfd, &rset);37 wset =rset;38 tval.tv_sec =nsec;39 tval.tv_usec = 0;40

41 if ( (n = select(sockfd+1, &rset, &wset, NULL, nsec ? &tval : NULL)) == 0) {42 close(sockfd); /*timeout*/

43 errno =ETIMEDOUT;44 return(-1);45 }46

47 /*检查可读或可写条件,调用getsockopt取得套接字的待处理错误,如果建立成功,该值将为0*/

48 if (FD_ISSET(sockfd, &rset) || FD_ISSET(sockfd, &wset)) {49 len = sizeof(error);50 if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len) < 0)51 return(-1); /*Solaris pending error*/

52 } else{53 perror("select error: sockfd not set");54 exit(1);55 }56

57 /*恢复套接字的文件状态标志并返回*/

58 done:59 fcntl(sockfd, F_SETFL, flags); /*restore file status flags*/

60 if(error) {61 close(sockfd); /*just in case*/

62 errno =error;63 return(-1);64 }65 return(0);66 }67

68 intmain()69 {70 //socket

71 structsockaddr_in servaddr;72 short port = 9999;73 int sockfd = socket(AF_INET, SOCK_STREAM, 0);74 servaddr.sin_family =AF_INET;75 servaddr.sin_addr.s_addr = inet_addr("113.107.231.211");76 servaddr.sin_port =htons(port);77 int timeout = 3;78

79 if (connect_nonb(sockfd, (sockaddr *) &servaddr, sizeof(sockaddr_in), 2) < 0) {80 perror("connect fail:");81 return(-1);82 }83 printf("connect success!\n");84

85 return 0;86 }

在Linux下需要注意的是时间的控制结构是struct timeval而并不是某一整型数,须如下定义:

struct timeval timeout = {3,0};

struct timeval {

time_t tv_sec; // seconds

long tv_usec; // microseconds

};

struct timeval有两个成员,一个是秒,一个是微秒, 所以最高精确度是微秒。

//设置发送超时

setsockopt(socket,SOL_SOCKET,SO_SNDTIMEO,(char *)&timeout,sizeof(struct timeval));

//设置接收超时

setsockopt(socket,SOL_SOCKET,SO_RCVTIMEO,(char *)&timeout,sizeof(struct timeval));

有两点注意就是:

1)recv ()的第四个参数需为MSG_WAITALL,在阻塞模式下不等到指定数目的数据不会返回,除非超时时间到。还要注意的是只要设置了接收超时,在没有 MSG_WAITALL时也是有效的。说到底超时就是不让你的程序老在那儿等,到一定时间进行一次返回而已。

2)即使等待超时时间值未到,但对方已经关闭了socket, 则此时recv()会立即返回,并收到多少数据返回多少数据。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值