poll实现IO多路转接服务器

基于该视频完成

04-poll函数实现服务器_哔哩哔哩_bilibili

通过响应式–多路IO转接实现

要求:能看懂看,看不懂也没啥大事,现在基本都用epoll代替了

大家看视频思路吧,代码就是从讲义里面copy了一份,因为不是很重要的东西

思路

image-20241212223412473

代码实现

warp.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#ifndef __WRAP_H_
#define __WRAP_H_
#include<sys/epoll.h>
//#include<event2/event.h>
#include<sys/select.h>
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<errno.h>
#include<string.h>
#include<dirent.h>
#include<sys/stat.h>
#include<wait.h>
#include<sys/mman.h>
#include<signal.h>
#include<pthread.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<ctype.h>
#include<strings.h>
#include<netinet/ip.h>
#define SRV_PORT 1234


void perr_exit(const char *s);
int Accept(int fd,struct sockaddr *sa,socklen_t * salenptr);
int Bind(int fd, const struct sockaddr *sa, socklen_t salen);
int Connect(int fd, const struct sockaddr *sa, socklen_t addrlen);
int Listen(int fd, int backlog);
int Socket(int family, int type, int protocol);
size_t Read(int fd, void *ptr, size_t nbytes);
ssize_t Write(int fd,const void *ptr,size_t nbytes);
int Close(int fd);
ssize_t Readn(int fd, void *vptr, size_t n);
ssize_t Writen(int fd, const void *vptr, size_t n);
ssize_t my_read(int fd, char *ptr);
ssize_t Readline(int fd, void *vptr, size_t maxlen);



#endif

warp.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
#include"warp.h"


void perr_exit(const char *s)
{
perror(s);
exit(1);
}

int Accept(int fd,struct sockaddr *sa,socklen_t * salenptr)
{
int n;
again:
if((n=accept(fd,sa,salenptr))<0)
{
if((errno==ECONNABORTED)||(errno==EINTR))
goto again;
else
perr_exit("accept error");
}
return n;
}

int Bind(int fd, const struct sockaddr *sa, socklen_t salen)
{
int n;
if((n=bind(fd,sa,salen))<0)
perr_exit("bind error");

return n;
}

int Connect(int fd, const struct sockaddr *sa, socklen_t addrlen)
{
int n;
n=connect(fd,sa,addrlen);
if(n<0)
{
perr_exit("connect error");
}
return n;
}

int Listen(int fd, int backlog)
{
int n;
if((n=listen(fd,backlog))<0)
perr_exit("listen error");
return n;
}

int Socket(int family, int type, int protocol)
{
int n;
if((n=socket(family,type,protocol))<0)
perr_exit("socket error");
return n;
}

size_t Read(int fd, void *ptr, size_t nbytes)
{
ssize_t n;
again:
if((n=read(fd,ptr,nbytes))==-1)
{
if(errno==EINTR)
goto again;
else
return -1;
}
return n;
}

ssize_t Write(int fd,const void *ptr,size_t nbytes)
{
ssize_t n;
again:
if((n=write(fd,ptr,nbytes))==-1)
{
if(errno==EINTR)
goto again;
else
return -1;
}

return 0;
}

int Close(int fd)
{
int n;
if((n=close(fd))==-1)
perr_exit("close error");

return n;
}

ssize_t Readn(int fd, void *vptr, size_t n)
{
size_t nleft;
ssize_t nread;
char *ptr;

ptr=vptr;
nleft=n;

while(nleft>0)
{
if((nread=read(fd,ptr,nleft))<0)
{
if(errno==EINTR)
nread=0;
else
return -1;
}
else if(nread==0)
break;

}
}
ssize_t Writen(int fd, const void *vptr, size_t n)
{
size_t nleft;
ssize_t nwritten;
char *ptr;

ptr=(char *)vptr;
nleft=n;

while(nleft>0)
{
if((nwritten=write(fd,ptr,nleft))<=0)
{
if(nwritten<0&&errno==EINTR)
nwritten=0;
else
return -1;
}
nleft-=nwritten;
ptr+=nwritten;
}
return n;
}

ssize_t my_read(int fd, char *ptr)
{
static int read_cnt;
static char *read_ptr;
static char read_buf[100];

if(read_cnt<=0)
{
again:
if((read_cnt=read(fd,read_buf,sizeof(read_buf)))<0)
{
if(errno==EINTR)
goto again;
return -1;
}else if(read_cnt==0)
return 0;
read_ptr=read_buf;
}
read_cnt--;
*ptr=*read_ptr++;
return 1;
}

ssize_t Readline(int fd, void *vptr, size_t maxlen)
{
ssize_t n,rc;
char c,*ptr;
ptr=vptr;

for(n=1;n<maxlen;n++)
{
if((rc=my_read(fd,&c))==1)
{
*ptr++=c;
if(c=='\n')
break;
}else if(rc==0)
{
*ptr=0;
return n-1;
}
else
return -1;
}
*ptr=0;
return n;
}

multi_poll_sever.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
1./* server.c */  
2.#include <stdio.h>
3.#include <stdlib.h>
4.#include <string.h>
5.#include <netinet/in.h>
6.#include <arpa/inet.h>
7.#include <poll.h>
8.#include <errno.h>
9.#include "wrap.h"
10.
11.#define MAXLINE 80
12.#define SERV_PORT 6666
13.#define OPEN_MAX 1024
14.
15.int main(int argc, char *argv[])
16.{
17. int i, j, maxi, listenfd, connfd, sockfd;
18. int nready;
19. ssize_t n;
20. char buf[MAXLINE], str[INET_ADDRSTRLEN];
21. socklen_t clilen;
22. struct pollfd client[OPEN_MAX];
23. struct sockaddr_in cliaddr, servaddr;
24.
25. listenfd = Socket(AF_INET, SOCK_STREAM, 0);
26.
27. bzero(&servaddr, sizeof(servaddr));
28. servaddr.sin_family = AF_INET;
29. servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
30. servaddr.sin_port = htons(SERV_PORT);
31.
32. Bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
33.
34. Listen(listenfd, 20);
35.
36. client[0].fd = listenfd;
37. client[0].events = POLLRDNORM; /* listenfd监听普通读事件 */
38.
39. for (i = 1; i < OPEN_MAX; i++)
40. client[i].fd = -1; /* 用-1初始化client[]里剩下元素 */
41. maxi = 0; /* client[]数组有效元素中最大元素下标 */
42.
43. for ( ; ; ) {
44. nready = poll(client, maxi+1, -1); /* 阻塞 */
45. if (client[0].revents & POLLRDNORM) { /* 有客户端链接请求 */
46. clilen = sizeof(cliaddr);
47. connfd = Accept(listenfd, (struct sockaddr *)&cliaddr, &clilen);
48. printf("received from %s at PORT %d\n",
49. inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),
50. ntohs(cliaddr.sin_port));
51. for (i = 1; i < OPEN_MAX; i++) {
52. if (client[i].fd < 0) {
53. client[i].fd = connfd; /* 找到client[]中空闲的位置,存放accept返回的connfd */
54. break;
55. }
56. }
57.
58. if (i == OPEN_MAX)
59. perr_exit("too many clients");
60.
61. client[i].events = POLLRDNORM; /* 设置刚刚返回的connfd,监控读事件 */
62. if (i > maxi)
63. maxi = i; /* 更新client[]中最大元素下标 */
64. if (--nready <= 0)
65. continue; /* 没有更多就绪事件时,继续回到poll阻塞 */
66. }
67. for (i = 1; i <= maxi; i++) { /* 检测client[] */
68. if ((sockfd = client[i].fd) < 0)
69. continue;
70. if (client[i].revents & (POLLRDNORM | POLLERR)) {
71. if ((n = Read(sockfd, buf, MAXLINE)) < 0) {
72. if (errno == ECONNRESET) { /* 当收到 RST标志时 */
73. /* connection reset by client */
74. printf("client[%d] aborted connection\n", i);
75. Close(sockfd);
76. client[i].fd = -1;
77. } else {
78. perr_exit("read error");
79. }
80. } else if (n == 0) {
81. /* connection closed by client */
82. printf("client[%d] closed connection\n", i);
83. Close(sockfd);
84. client[i].fd = -1;
85. } else {
86. for (j = 0; j < n; j++)
87. buf[j] = toupper(buf[j]);
88. Writen(sockfd, buf, n);
89. }
90. if (--nready <= 0)
91. break; /* no more readable descriptors */
92. }
93. }
94. }
95. return 0;
96.}