前言
本章节是用基本的Linux基本函数加上epoll调用编写一个完整的服务器和客户端例子,可在Linux上运行,客户端和服务端的功能如下:
- 客户端从标准输入读入一行,发送到服务端
- 服务端从网络读取一行,然后输出到客户端
- 客户端收到服务端的响应,输出这一行到标准输出
服务端
代码如下:
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
|
#include <unistd.h> #include <sys/types.h> /* basic system data types */ #include <sys/socket.h> /* basic socket definitions */ #include <netinet/in.h> /* sockaddr_in{} and other Internet defns */ #include <arpa/inet.h> /* inet(3) functions */ #include <sys/epoll.h> /* epoll function */ #include <fcntl.h> /* nonblocking */ #include <sys/resource.h> /*setrlimit */ #include <stdlib.h> #include <errno.h> #include <stdio.h> #include <string.h> #define MAXEPOLLSIZE 10000 #define MAXLINE 10240 int handle( int connfd); int setnonblocking( int sockfd) { if (fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFD, 0)|O_NONBLOCK) == -1) { return -1; } return 0; } int main( int argc, char **argv) { int servPort = 6888; int listenq = 1024; int listenfd, connfd, kdpfd, nfds, n, nread, curfds,acceptCount = 0; struct sockaddr_in servaddr, cliaddr; socklen_t socklen = sizeof ( struct sockaddr_in); struct epoll_event ev; struct epoll_event events[MAXEPOLLSIZE]; struct rlimit rt; char buf[MAXLINE]; /* 设置每个进程允许打开的最大文件数 */ rt.rlim_max = rt.rlim_cur = MAXEPOLLSIZE; if (setrlimit(RLIMIT_NOFILE, &rt) == -1) { perror ( "setrlimit error" ); return -1; } bzero(&servaddr, sizeof (servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl (INADDR_ANY); servaddr.sin_port = htons (servPort); listenfd = socket(AF_INET, SOCK_STREAM, 0); if (listenfd == -1) { perror ( "can't create socket file" ); return -1; } int opt = 1; setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt)); if (setnonblocking(listenfd) < 0) { perror ( "setnonblock error" ); } if (bind(listenfd, ( struct sockaddr *) &servaddr, sizeof ( struct sockaddr)) == -1) { perror ( "bind error" ); return -1; } if (listen(listenfd, listenq) == -1) { perror ( "listen error" ); return -1; } /* 创建 epoll 句柄,把监听 socket 加入到 epoll 集合里 */ kdpfd = epoll_create(MAXEPOLLSIZE); ev.events = EPOLLIN | EPOLLET; ev.data.fd = listenfd; if (epoll_ctl(kdpfd, EPOLL_CTL_ADD, listenfd, &ev) < 0) { fprintf (stderr, "epoll set insertion error: fd=%d\n" , listenfd); return -1; } curfds = 1; printf ( "epollserver startup,port %d, max connection is %d, backlog is %d\n" , servPort, MAXEPOLLSIZE, listenq); for (;;) { /* 等待有事件发生 */ nfds = epoll_wait(kdpfd, events, curfds, -1); if (nfds == -1) { perror ( "epoll_wait" ); continue ; } /* 处理所有事件 */ for (n = 0; n < nfds; ++n) { if (events[n].data.fd == listenfd) { connfd = accept(listenfd, ( struct sockaddr *)&cliaddr,&socklen); if (connfd < 0) { perror ( "accept error" ); continue ; } sprintf (buf, "accept form %s:%d\n" , inet_ntoa(cliaddr.sin_addr), cliaddr.sin_port); printf ( "%d:%s" , ++acceptCount, buf); if (curfds >= MAXEPOLLSIZE) { fprintf (stderr, "too many connection, more than %d\n" , MAXEPOLLSIZE); close(connfd); continue ; } if (setnonblocking(connfd) < 0) { perror ( "setnonblocking error" ); } ev.events = EPOLLIN | EPOLLET; ev.data.fd = connfd; if (epoll_ctl(kdpfd, EPOLL_CTL_ADD, connfd, &ev) < 0) { fprintf (stderr, "add socket '%d' to epoll failed: %s\n" , connfd, strerror ( errno )); return -1; } curfds++; continue ; } // 处理客户端请求 if (handle(events[n].data.fd) < 0) { epoll_ctl(kdpfd, EPOLL_CTL_DEL, events[n].data.fd,&ev); curfds--; } } } close(listenfd); return 0; } int handle( int connfd) { int nread; char buf[MAXLINE]; nread = read(connfd, buf, MAXLINE); //读取客户端socket流 if (nread == 0) { printf ( "client close the connection\n" ); close(connfd); return -1; } if (nread < 0) { perror ( "read error" ); close(connfd); return -1; } write(connfd, buf, nread); //响应客户端 return 0; } |
编译
编译和启动服务端
1
2
|
gcc epollserver.c -o epollserver ./epollserver |
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对服务器之家的支持。如果你想了解更多相关内容请查看下面相关链接
原文链接:https://blog.csdn.net/woniu211111/article/details/47318843