基于select模型的udp客户端实现超时机制
来源:互联网 发布:数据库优化方案 编辑:程序博客网 时间:2024/05/16 08:58
多路选择I/O — select模型
其思想在于使用一个集合,该集合中包含需要进行读写的fd,通过轮询这个集合,直到有一个fd可读写,才返回。与阻塞I/O不同的是,阻塞I/O仅使用了一次系统调用,就是对fd的读写,如果没有fd处于就绪状态,则进程一直阻塞,而多路选择I/O使用了两次系统调用,第一次是轮询并返回可读写fd数,第二次是对fd进行读写,阻塞只发生在轮询fd的过程。
select函数的原型(sys/select.h)
1 int select (int __nfds, fd_set *__restrict __readfds,2 fd_set *__restrict __writefds,3 fd_set *__restrict __exceptfds,4 struct timeval *__restrict __timeout);
(1)__nfds
需轮询的最大文件描述符数。如__nfds = 10,则轮询值为0~9的fd,单个进程中,最多可打开1024个fd,该值在sys/select.h中的FD_SETSIZE定义。用户可通过“ulimit -n”查看该值,通过打印/proc/sys/fs/file-max中的值查看系统可打开的最大fd数。
(2)__readfds,__writefds,__exceptfds
分别代表用户关心的可读、可写、异常的fd,这三个参数的数据类型是fd_set *,这是一组文件描述符的集合,使用一个位来代表一个fd。
fd_set位向量操作函数包括
1 #define FD_SET(fd, fdsetp) __FD_SET (fd, fdsetp) //将指定的fd置12 #define FD_CLR(fd, fdsetp) __FD_CLR (fd, fdsetp) //将指定的fd清03 #define FD_ISSET(fd, fdsetp) __FD_ISSET (fd, fdsetp) //测试fd状态,如被置1,返回非0,否则返回04 #define FD_ZERO(fdsetp) __FD_ZERO (fdsetp) //将所有的fd清0
(3)__timeout
timeout的数据类型是timeval结构体。通过填充该结构体,设置超时时间,精确到微妙级,如果该参数设置为NULL,则一直等待,直到有fd可读写。如果tv_sec和tv_usec都设置为0,则轮询完指定fd后,立即返回。
1 struct timeval2 {3 __time_t tv_sec; /* Seconds. */4 __suseconds_t tv_usec; /* Microseconds. */5 };
(4)select有三种返回值
-1 :出错
0 :如果设置了超时,在指定时间内没有fd可读写,则返回0,可在此指定相应的超时处理操作。
>0 :返回可读写的fd数
可屏蔽信号的select — pselect
从原型上看,pselect函数与select函数的区别在于设置超时的结构体不同,以及多了个用于屏蔽信号的参数。如果__sigmask设置为NULL,则与select一样。
1 int pselect (int __nfds, fd_set *__restrict __readfds,2 fd_set *__restrict __writefds,3 fd_set *__restrict __exceptfds,4 const struct timespec *__restrict __timeout,5 const __sigset_t *__restrict __sigmask);
(1)timespec结构体的定义如下,它精确到纳秒级。
1 struct timespec2 {3 __time_t tv_sec; /* Seconds. */4 long int tv_nsec; /* Nanoseconds. */5 };
(2)__sigmask实际上是信号的位向量。数据类型是sigset_t,定义如下
1 /* A `sigset_t' has a bit for each signal. */2 3 # define _SIGSET_NWORDS (1024 / (8 * sizeof (unsigned long int)))4 typedef struct5 {6 unsigned long int __val[_SIGSET_NWORDS];7 } __sigset_t;
测试代码:
//client#include <Winsock2.h>#include <stdio.h>#pragma comment (lib,"Ws2_32.lib")#define MAX_LINE 80#define PORT 8000typedef int socklen_t;int main(int argc, char *argv[]){ struct sockaddr_in sin, cin; socklen_t addr_len; int sockfd, maxfdp; char *msg = "client"; char buf[MAX_LINE]; fd_set fds; struct timeval timeout; int interval = 3; memset(&sin, 0,sizeof(sin)); sin.sin_family = AF_INET; //inet_pton(AF_INET, "127.0.0.1", &sin.sin_addr); sin.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); sin.sin_port = htons(PORT); if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { perror("fail to create socket.\n"); exit(1); } addr_len = sizeof(cin); while (1) { timeout.tv_usec = 0; timeout.tv_sec = interval; FD_ZERO(&fds); FD_SET(sockfd, &fds); maxfdp = sockfd + 1; sendto(sockfd, msg, strlen(msg) + 1, 0, (struct sockaddr*)&sin, sizeof(sin)); switch (select(maxfdp, &fds, NULL, NULL, &timeout)) { case -1: perror("error"); exit(-1); break; case 0: printf("timeout.\n"); break; default: if (FD_ISSET(sockfd, &fds)) { if (recvfrom(sockfd, buf, MAX_LINE, 0, (struct sockaddr *)&cin, &addr_len) < 0) { perror("fail to receive.\n"); exit(1); } else { printf("receive from server: %s.\n", buf); if (closesocket(sockfd) < 0) { perror("fail to close.\n"); exit(1); } return 0; } } break; } } return 0;}
//Server
#pragma comment (lib,"ws2_32.lib")#include <Winsock2.h>#include <stdio.h>#define MAX_LINE 80#define PORT 8000int main(int argc, char *argv[]){ struct sockaddr_in sin, cin; int addr_len; int sockfd, n; char *msg = "server"; char buf[MAX_LINE]; memset(&sin,0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_addr.s_addr = htons(INADDR_ANY); sin.sin_port = htons(PORT); if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { perror("fail to create socket.\n"); exit(1); } n = bind(sockfd, (struct sockaddr*)&sin, sizeof(sin)); if (n < 0) { perror("fail to bind.\n"); exit(1); } while (1) { addr_len = sizeof(cin); recvfrom(sockfd, buf, MAX_LINE, 0, (struct sockaddr*)&cin, &addr_len); sendto(sockfd, msg, strlen(msg) + 1, 0, (struct sockaddr*)&cin, addr_len); }}
测试:链接失败。。。
- 基于select模型的udp客户端实现超时机制
- udp利用select实现超时重传
- udp利用select实现超时重传
- 通过select模型实现具有超时设定的connect
- linux环境下基于UDP的 客户端服务器模型
- UDP并发服务器模型 二:select机制
- 基于UDP实现简单的客户端服务端的消息传递
- 编程实现基于UDP的多线程多客户端socket应用
- 基于UDP的服务器端/客户端
- 实现简单UDP服务器客户端模型
- VC下基于消息机制的UDP连接实现
- TCP UDP select超时总结
- TCP/UDP select超时处理
- 使用socket实现基于select模型的网络聊天室
- 转udp 超时设置(select函数的一种用法)
- select模型的实现
- UDP实现简单的超时重传
- 基于UDP的select函数用法
- 配置tomcat以运行PHP项目
- udp通信C++实现的细节
- Select模型及tcp select模型
- 数据存储
- Winsock IO模型之select模型
- 基于select模型的udp客户端实现超时机制
- Hiernate操作与缓存
- Wireshark基本介绍及应用tcp
- 矩阵的操作
- android-自定义View解决wrap_content无效的问题
- 回文链表
- 总结--20160705
- 对android中ActionBar中setDisplayHomeAsUpEnabled和setHomeButtonEnabled和setDisplayShowHomeEnabled方法的理解
- 满二叉树的最近公共祖先