poll
poll 系统调用和 select 类似,也是在指定时间内轮询一定数量的文件描述符,以测试其中是否有就绪者。
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
select 和 poll 的区别:
- 在内核实现上,两者都采用轮询方式;时间复杂度:O(n)。
- select 传的是一个集合,上限1024;
poll 支持更多的描述符;因为它传的是一个数组可以动态开辟。 - select 支持三种事件类型,读、写、异常;
poll支持更多的事件类型。
poll服务器代码:
1 #define _GNU_SOURCE
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <unistd.h>
5 #include <string.h>
6 #include <assert.h>
7 #include <sys/socket.h>
8 #include <netinet/in.h>
9 #include <arpa/inet.h>
10 #include <poll.h>
11
12 #define MAX 10
13 void fds_init(struct pollfd fds[])//初始化 清空数组
14 {
15 for( int i = 0; i < MAX; i++ )
16 {
17 fds[i].fd = -1;//文件描述符
18 fds[i].events = 0;//注册的事件
19 fds[i].revents = 0;//实际发生的事件
20 }
21 }
22
23 void fds_add(struct pollfd fds[], int fd)//添加描述符
24 {
25 for( int i = 0; i< MAX; i++ )
26 {
27 if ( fds[i].fd == -1 )
28 {
29 fds[i].fd = fd;
30 fds[i].events = POLLIN | POLLRDHUP;
31 fds[i].revents = 0;
32 break;
33 }
34 }
35 }
36 void fds_del(struct pollfd fds[], int fd )
37 {
38 for( int i = 0; i < MAX; i++ )
39 {
40 if ( fds[i].fd == fd )
41 {
42 fds[i].fd = -1;
43 fds[i].events = 0;
44 fds[i].revents = 0;
45 break;
46 }
47 }
48 }
49 int socket_init();
50 int main()
51 {
52 int sockfd = socket_init();
53 assert( sockfd != -1 );
54
55 struct pollfd fds[MAX];//描述符数组
56 fds_init(fds);
57
58 fds_add(fds,sockfd);//将sockfd添加到fds数组中
59
60 while( 1 )
61 {
62 int n = poll(fds,MAX,5000);//
63 if ( n == -1 )
64 {
65 continue;
66 }
67 else if ( n == 0 )
68 {
69 printf("time out\n");
70 continue;
71 }
72 else
73 {
74 for( int i = 0; i < MAX; i++ )
75 {
76 if ( fds[i].fd == -1 )
77 {
78 continue;
79 }
80
81 if ( fds[i].revents & POLLRDHUP )
82 {
83 close(fds[i].fd);
84 fds_del(fds,fds[i].fd);
85 printf("client hup close\n");
86 continue;
87
88 }
89 if ( fds[i].revents & POLLIN )
90 {
91 if ( fds[i].fd == sockfd )//accept
92 {
93 struct sockaddr_in caddr;
94 int len = sizeof(caddr);
95 int c = accept(sockfd,(struct sockaddr*)&caddr,&len);
96 if ( c < 0 )
97 {
98 continue;
99 }
100 printf("accept c=%d\n",c);
101 fds_add(fds,c);
102 }
103 else//recv
104 {
105 char buff[128] = {0};
106 int num = recv(fds[i].fd,buff,127,0);
107 if ( num <= 0 )
108 {
109 close(fds[i].fd);
110 fds_del(fds,fds[i].fd);
111 printf("client close\n");
112 }
113 else
114 {
115 printf("read(%d)=%s\n",fds[i].fd,buff);
116 send(fds[i].fd,"ok",2,0);
117 }
118 }
119 }
120 }
121 }
122 }
123
124
125 }
126 int socket_init()
127 {
128 int sockfd = socket(AF_INET,SOCK_STREAM,0);//创建套接字
129 if ( sockfd == -1 )
130 {
131 return -1;
132 }
133
134 struct sockaddr_in saddr;
135 memset(&saddr,0,sizeof(saddr));
136 saddr.sin_family = AF_INET;
137 saddr.sin_port = htons(6000);
138 saddr.sin_addr.s_addr = inet_addr("127.0.0.1");
139
140 int res = bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));//绑定
141 if ( res == -1 )
142 {
143 return -1;
144 }
145
146 if ( listen(sockfd,5) == -1 )//创建监听队列
147 {
148 return -1;
149 }
150
151 return sockfd;
152 }
cli 客户端代码
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<unistd.h>
4 #include<string.h>
5 #include<assert.h>
6 #include<sys/socket.h>
7 #include<netinet/in.h>
8 #include<arpa/inet.h>
9
10 int main()
11 {
12 int sockfd=socket(AF_INET,SOCK_STREAM,0);//创建套接字
13 assert(sockfd!=-1);
14
15 //bind()//可以绑定,但是一般不绑定
16
17 struct sockaddr_in saddr;
18 memset(&saddr,0,sizeof(saddr));
19 saddr.sin_family=AF_INET;
20 saddr.sin_port=htons(6000);
21 saddr.sin_addr.s_addr=inet_addr("127.0.0.1");
22
23 int res=connect(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));//三次握手
24 assert(res!=-1);
25 while(1)
26 {
27 char buff[128]={0};
28 printf("input:\n");
29 fgets(buff,128,stdin);
30
31 if(strncmp(buff,"end",3)==0)
32 {
33 break;
34 }
35 send(sockfd,buff,strlen(buff),0);
36
37 memset(buff,0,128);
38 recv(sockfd,buff,127,0);
39 printf("buff=%s\n",buff);
40 }
41 close(sockfd);
42 }