-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathserver.cpp
176 lines (161 loc) · 4.71 KB
/
server.cpp
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
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/epoll.h>
#include <unistd.h>
#include <sys/types.h>
#define IPADDRESS "127.0.0.1"
#define PORT 6666
#define MAXSIZE 1024
#define LISTENQ 5
#define FDSIZE 1000
#define EPOLLEVENTS 100
/*函数声明*/
/*创建套接字并进行绑定*/
int socket_bind(const char* ip,int port);
/*IO多路复用epoll*/
void do_epoll(int listenfd);
/*事件处理函数*/
void handle_events(int epollfd,struct epoll_event *events,int num,int listenfd,char *buf);
/*处理接收到的连接*/
void handle_accpet(int epollfd,int listenfd);
/*读处理*/
void do_read(int epollfd,int fd,char *buf);
/*写处理*/
void do_write(int epollfd,int fd,char *buf);
/*添加事件*/
void add_event(int epollfd,int fd,int state);
/*修改事件*/
void modify_event(int epollfd,int fd,int state);
/*删除事件*/
void delete_event(int epollfd,int fd,int state);
int main(int argc,char *argv[]){
int listenfd;
listenfd = socket_bind(IPADDRESS,PORT);
listen(listenfd,LISTENQ);
do_epoll(listenfd);
return 0;
}
int socket_bind(const char* ip,int port){
int listenfd;
struct sockaddr_in servaddr;
listenfd = socket(AF_INET,SOCK_STREAM,0);
if (listenfd == -1){
perror("socket error:");
exit(1);
}
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family = AF_INET;
inet_pton(AF_INET,ip,&servaddr.sin_addr);
servaddr.sin_port = htons(port);
if (bind(listenfd,(struct sockaddr*)&servaddr,sizeof(servaddr)) == -1){
perror("bind error: ");
exit(1);
}
return listenfd;
}
void do_epoll(int listenfd){
int epollfd;
struct epoll_event events[EPOLLEVENTS];
int ret;
char buf[MAXSIZE];
memset(buf,0,MAXSIZE);
/*创建一个描述符*/
epollfd = epoll_create(FDSIZE);
/*添加监听描述符事件*/
add_event(epollfd,listenfd,EPOLLIN);
static int counter = 0;
while(1){
/*获取已经准备好的描述符事件*/
ret = epoll_wait(epollfd,events,EPOLLEVENTS,-1);
printf("epoll_wait ret:%d, counter:%d\n", ret, counter++); // add by gaojie, 可以展示有几次触发,如果是水平触发,则会打印很多次,如果是边缘触发,则只会打印一次。
handle_events(epollfd,events,ret,listenfd,buf);
}
close(epollfd);
}
void handle_events(int epollfd,struct epoll_event *events,int num,int listenfd,char *buf){
int i;
int fd;
/*进行选好遍历*/
for (i = 0;i < num;i++){
fd = events[i].data.fd;
/*根据描述符的类型和事件类型进行处理*/
if ((fd == listenfd) &&(events[i].events & EPOLLIN))
handle_accpet(epollfd,listenfd);
else if (events[i].events & EPOLLIN)
do_read(epollfd,fd,buf);
else if (events[i].events & EPOLLOUT)
do_write(epollfd,fd,buf);
}
}
void handle_accpet(int epollfd,int listenfd){
int clifd;
struct sockaddr_in cliaddr;
socklen_t cliaddrlen;
clifd = accept(listenfd,(struct sockaddr*)&cliaddr,&cliaddrlen);
if (clifd == -1)
perror("accpet error:");
else{
printf("accept a new client: %s:%d\n",inet_ntoa(cliaddr.sin_addr),cliaddr.sin_port);
/*添加一个客户描述符和事件*/
add_event(epollfd,clifd,EPOLLIN);
}
}
void do_read(int epollfd,int fd,char *buf){
int nread;
// nread = read(fd,buf,MAXSIZE);
// gaojie:修改MAXSIZE为1便于演示,因为这样一次就读一个字符,只要client端有多个输入就可以演示出效果
nread = read(fd,buf,1);
if (nread == -1){
perror("read error:");
close(fd);
delete_event(epollfd,fd,EPOLLIN);
}
else if (nread == 0){
fprintf(stderr,"client close.\n");
close(fd);
delete_event(epollfd,fd,EPOLLIN);
}
else {
buf[nread] = 0; // add by gaojie, 不会在屏幕上显示特殊符号
// printf("read message is : %s",buf);
printf("read message is : %s\n",buf); // modify by gaojie, 添加了换行符
/*修改描述符对应的事件,由读改为写*/
// modify_event(epollfd,fd,EPOLLOUT); // comment by gaojie, 不产生干扰
}
}
void do_write(int epollfd,int fd,char *buf){
int nwrite;
nwrite = write(fd,buf,strlen(buf));
if (nwrite == -1){
perror("write error:");
close(fd);
delete_event(epollfd,fd,EPOLLOUT);
}
else
modify_event(epollfd,fd,EPOLLIN);
memset(buf,0,MAXSIZE);
}
void add_event(int epollfd,int fd,int state){
struct epoll_event ev;
// ev.events = state|EPOLLET; // gaojie: 边缘触发
ev.events = state; // gaojie: 水平触发
ev.data.fd = fd;
epoll_ctl(epollfd,EPOLL_CTL_ADD,fd,&ev);
}
void delete_event(int epollfd,int fd,int state){
struct epoll_event ev;
ev.events = state;
ev.data.fd = fd;
epoll_ctl(epollfd,EPOLL_CTL_DEL,fd,&ev);
}
void modify_event(int epollfd,int fd,int state){
struct epoll_event ev;
ev.events = state;
ev.data.fd = fd;
epoll_ctl(epollfd,EPOLL_CTL_MOD,fd,&ev);
}