AI智能
改变未来

(TCP IP网络编程)实验六 epoll模型编程


一.实验目的

(1) 在理解I/O复用模型速度慢的主要原因的基础上,理解和掌握Linux下对I/O复用模型的改进和扩展——epoll模型的工作原理;
(2) 理解和掌握epoll模型中条件触发和边缘触发两者在运作机制上的区别;
(3) 分别使用epoll模型的条件触发和边缘触发实现服务器编程。

二.实验内容

(1) 使用条件触发方式实现回声服务器端(及客户端);
(2) 使用边缘触发方式实现回声服务器端(及客户端);
(3) 实现聊天服务器端,使其可以在连接到服务器端的所有客户端之间交换消息。按照条件触发方式和边缘触发方式分别实现epoll服务器端(及客户端)。

三.实验过程

(1)条件触发:

echo_EPLTserv.c:#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <fcntl.h>#include <arpa/inet.h>#include <sys/socket.h>#include <sys/epoll.h>#define BUF_SIZE 4#define EPOLL_SIZE 50void error_handling(char *buf);int main(int argc, char *argv[]){int serv_sock, clnt_sock;struct sockaddr_in serv_adr, clnt_adr;socklen_t adr_sz;int str_len, i;char buf[BUF_SIZE];struct epoll_event *ep_events;struct epoll_event event;int epfd, event_cnt;if(argc!=2) {printf(\"Usage : %s <port>\\n\", argv[0]);exit(1);}serv_sock=socket(PF_INET, SOCK_STREAM, 0);memset(&serv_adr, 0, sizeof(serv_adr));serv_adr.sin_family=AF_INET;serv_adr.sin_addr.s_addr=htonl(INADDR_ANY);serv_adr.sin_port=htons(atoi(argv[1]));if(bind(serv_sock, (struct sockaddr*) &serv_adr, sizeof(serv_adr))==-1)error_handling(\"bind() error\");if(listen(serv_sock, 5)==-1)error_handling(\"listen() error\");epfd=epoll_create(EPOLL_SIZE);ep_events=malloc(sizeof(struct epoll_event)*EPOLL_SIZE);event.events=EPOLLIN;event.data.fd=serv_sock;epoll_ctl(epfd, EPOLL_CTL_ADD, serv_sock, &event);while(1){event_cnt=epoll_wait(epfd, ep_events, EPOLL_SIZE, -1);if(event_cnt==-1){puts(\"epoll_wait() error\");break;}puts(\"return epoll_wait\");for(i=0; i<event_cnt; i++){if(ep_events[i].data.fd==serv_sock){adr_sz=sizeof(clnt_adr);clnt_sock=accept(serv_sock, (struct sockaddr*)&clnt_adr, &adr_sz);event.events=EPOLLIN;event.data.fd=clnt_sock;epoll_ctl(epfd, EPOLL_CTL_ADD, clnt_sock, &event);printf(\"connected client: %d \\n\", clnt_sock);}else{str_len=read(ep_events[i].data.fd, buf, BUF_SIZE);if(str_len==0)    // close request!{epoll_ctl(epfd, EPOLL_CTL_DEL, ep_events[i].data.fd, NULL);close(ep_events[i].data.fd);printf(\"closed client: %d \\n\", ep_events[i].data.fd);}else{write(ep_events[i].data.fd, buf, str_len);    // echo!}}}}close(serv_sock);close(epfd);return 0;}void error_handling(char *buf){fputs(buf, stderr);fputc(\'\\n\', stderr);exit(1);}echo_client.c:#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <arpa/inet.h>#include <sys/socket.h>#define BUF_SIZE 1024void error_handling(char *message);int main(int argc, char *argv[]){int sock;char message[BUF_SIZE];int str_len;struct sockaddr_in serv_adr;if(argc!=3) {printf(\"Usage : %s <IP> <port>\\n\", argv[0]);exit(1);}sock=socket(PF_INET, SOCK_STREAM, 0);if(sock==-1)error_handling(\"socket() error\");memset(&serv_adr, 0, sizeof(serv_adr));serv_adr.sin_family=AF_INET;serv_adr.sin_addr.s_addr=inet_addr(argv[1]);serv_adr.sin_port=htons(atoi(argv[2]));if(connect(sock, (struct sockaddr*)&serv_adr, sizeof(serv_adr))==-1)error_handling(\"connect() error!\");elseputs(\"Connected...........\");while(1){fputs(\"Input message(Q to quit): \", stdout);fgets(message, BUF_SIZE, stdin);if(!strcmp(message,\"q\\n\") || !strcmp(message,\"Q\\n\"))break;write(sock, message, strlen(message));str_len=read(sock, message, BUF_SIZE-1);message[str_len]=0;printf(\"Message from server: %s\", message);}close(sock);return 0;}void error_handling(char *message){fputs(message, stderr);fputc(\'\\n\', stderr);exit(1);}

结果:

(2)边缘触发:

echo_EPETserv.c:#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <fcntl.h>#include <errno.h>#include <arpa/inet.h>#include <sys/socket.h>#include <sys/epoll.h>#define BUF_SIZE 4#define EPOLL_SIZE 50void setnonblockingmode(int fd);void error_handling(char *buf);int main(int argc, char *argv[]){int serv_sock, clnt_sock;struct sockaddr_in serv_adr, clnt_adr;socklen_t adr_sz;int str_len, i;char buf[BUF_SIZE];struct epoll_event *ep_events;struct epoll_event event;int epfd, event_cnt;if(argc!=2) {printf(\"Usage : %s <port>\\n\", argv[0]);exit(1);}serv_sock=socket(PF_INET, SOCK_STREAM, 0);memset(&serv_adr, 0, sizeof(serv_adr));serv_adr.sin_family=AF_INET;serv_adr.sin_addr.s_addr=htonl(INADDR_ANY);serv_adr.sin_port=htons(atoi(argv[1]));if(bind(serv_sock, (struct sockaddr*) &serv_adr, sizeof(serv_adr))==-1)error_handling(\"bind() error\");if(listen(serv_sock, 5)==-1)error_handling(\"listen() error\");epfd=epoll_create(EPOLL_SIZE);ep_events=malloc(sizeof(struct epoll_event)*EPOLL_SIZE);setnonblockingmode(serv_sock);event.events=EPOLLIN;event.data.fd=serv_sock;epoll_ctl(epfd, EPOLL_CTL_ADD, serv_sock, &event);while(1){event_cnt=epoll_wait(epfd, ep_events, EPOLL_SIZE, -1);if(event_cnt==-1){puts(\"epoll_wait() error\");break;}puts(\"return epoll_wait\");for(i=0; i<event_cnt; i++){if(ep_events[i].data.fd==serv_sock){adr_sz=sizeof(clnt_adr);clnt_sock=accept(serv_sock, (struct sockaddr*)&clnt_adr, &adr_sz);setnonblockingmode(clnt_sock);event.events=EPOLLIN|EPOLLET;event.data.fd=clnt_sock;epoll_ctl(epfd, EPOLL_CTL_ADD, clnt_sock, &event);printf(\"connected client: %d \\n\", clnt_sock);}else{while(1){str_len=read(ep_events[i].data.fd, buf, BUF_SIZE);if(str_len==0)    // close request!{epoll_ctl(epfd, EPOLL_CTL_DEL, ep_events[i].data.fd, NULL);close(ep_events[i].data.fd);printf(\"closed client: %d \\n\", ep_events[i].data.fd);break;}else if(str_len<0){if(errno==EAGAIN)break;}else{write(ep_events[i].data.fd, buf, str_len);    // echo!}}}}}close(serv_sock);close(epfd);return 0;}void setnonblockingmode(int fd){int flag=fcntl(fd, F_GETFL, 0);fcntl(fd, F_SETFL, flag|O_NONBLOCK);}void error_handling(char *buf){fputs(buf, stderr);fputc(\'\\n\', stderr);exit(1);}echo_client.c:#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <arpa/inet.h>#include <sys/socket.h>#define BUF_SIZE 1024void error_handling(char *message);int main(int argc, char *argv[]){int sock;char message[BUF_SIZE];int str_len;struct sockaddr_in serv_adr;if(argc!=3) {printf(\"Usage : %s <IP> <port>\\n\", argv[0]);exit(1);}sock=socket(PF_INET, SOCK_STREAM, 0);if(sock==-1)error_handling(\"socket() error\");memset(&serv_adr, 0, sizeof(serv_adr));serv_adr.sin_family=AF_INET;serv_adr.sin_addr.s_addr=inet_addr(argv[1]);serv_adr.sin_port=htons(atoi(argv[2]));if(connect(sock, (struct sockaddr*)&serv_adr, sizeof(serv_adr))==-1)error_handling(\"connect() error!\");elseputs(\"Connected...........\");while(1){fputs(\"Input message(Q to quit): \", stdout);fgets(message, BUF_SIZE, stdin);if(!strcmp(message,\"q\\n\") || !strcmp(message,\"Q\\n\"))break;write(sock, message, strlen(message));str_len=read(sock, message, BUF_SIZE-1);message[str_len]=0;printf(\"Message from server: %s\", message);}close(sock);return 0;}void error_handling(char *message){fputs(message, stderr);fputc(\'\\n\', stderr);exit(1);}

结果:

(3)实验代码:

chat_EPLTserv.c:#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <fcntl.h>#include <arpa/inet.h>#include <sys/socket.h>#include <sys/epoll.h>#define BUF_SIZE 100#define MAX_CLNT 256#define EPOLL_SIZE 50void error_handling(char *buf);void send_msg(char * msg, int len);int clnt_cnt=0;int clnt_socks[MAX_CLNT];int main(int argc, char *argv[]){int serv_sock, clnt_sock;struct sockaddr_in serv_adr, clnt_adr;socklen_t adr_sz;int str_len, i;char buf[BUF_SIZE];struct epoll_event *ep_events;struct epoll_event event;int epfd, event_cnt;if(argc!=2) {printf(\"Usage : %s <port>\\n\", argv[0]);exit(1);}serv_sock=socket(PF_INET, SOCK_STREAM, 0);memset(&serv_adr, 0, sizeof(serv_adr));serv_adr.sin_family=AF_INET;serv_adr.sin_addr.s_addr=htonl(INADDR_ANY);serv_adr.sin_port=htons(atoi(argv[1]));if(bind(serv_sock, (struct sockaddr*) &serv_adr, sizeof(serv_adr))==-1)error_handling(\"bind() error\");if(listen(serv_sock, 5)==-1)error_handling(\"listen() error\");epfd=epoll_create(EPOLL_SIZE);ep_events=malloc(sizeof(struct epoll_event)*EPOLL_SIZE);event.events=EPOLLIN;event.data.fd=serv_sock;epoll_ctl(epfd, EPOLL_CTL_ADD, serv_sock, &event);while(1){event_cnt=epoll_wait(epfd, ep_events, EPOLL_SIZE, -1);if(event_cnt==-1){break;}for(i=0; i<event_cnt; i++){if(ep_events[i].data.fd==serv_sock){adr_sz=sizeof(clnt_adr);clnt_sock=accept(serv_sock, (struct sockaddr*)&clnt_adr, &adr_sz);event.events=EPOLLIN;event.data.fd=clnt_sock;epoll_ctl(epfd, EPOLL_CTL_ADD, clnt_sock, &event);clnt_socks[clnt_cnt++]=clnt_sock;printf(\"connected client: %d \\n\", clnt_sock);}else{str_len=read(ep_events[i].data.fd, buf, BUF_SIZE);if(str_len==0){epoll_ctl(epfd, EPOLL_CTL_DEL, ep_events[i].data.fd, NULL);close(ep_events[i].data.fd);printf(\"closed client: %d \\n\", ep_events[i].data.fd);for(i=0; i<clnt_cnt; i++){if(clnt_sock==clnt_socks[i]){while(i++<clnt_cnt-1)clnt_socks[i]=clnt_socks[i+1];break;}}clnt_cnt--;}else{send_msg(buf, str_len);}}}}close(serv_sock);close(epfd);return 0;}void send_msg(char * msg, int len)   // send to all{int i;for(i=0; i<clnt_cnt; i++)write(clnt_socks[i], msg, len);}void error_handling(char *buf){fputs(buf, stderr);fputc(\'\\n\', stderr);exit(1);}chat_client.c:#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <arpa/inet.h>#include <sys/socket.h>#include <pthread.h>#define BUF_SIZE 100#define NAME_SIZE 20void * send_msg(void * arg);void * recv_msg(void * arg);void error_handling(char * msg);char name[NAME_SIZE]=\"[DEFAULT]\";char msg[BUF_SIZE];int main(int argc, char *argv[]){int sock;struct sockaddr_in serv_addr;pthread_t snd_thread, rcv_thread;void * thread_return;if(argc!=4) {printf(\"Usage : %s <IP> <port> <name>\\n\", argv[0]);exit(1);}sprintf(name, \"[%s]\", argv[3]);sock=socket(PF_INET, SOCK_STREAM, 0);memset(&serv_addr, 0, sizeof(serv_addr));serv_addr.sin_family=AF_INET;serv_addr.sin_addr.s_addr=inet_addr(argv[1]);serv_addr.sin_port=htons(atoi(argv[2]));if(connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr))==-1)error_handling(\"connect() error\");pthread_create(&snd_thread, NULL, send_msg, (void*)&sock);pthread_create(&rcv_thread, NULL, recv_msg, (void*)&sock);pthread_join(snd_thread, &thread_return);pthread_join(rcv_thread, &thread_return);close(sock);return 0;}void * send_msg(void * arg)   // send thread main{int sock=*((int*)arg);char name_msg[NAME_SIZE+BUF_SIZE];while(1){fgets(msg, BUF_SIZE, stdin);if(!strcmp(msg,\"q\\n\")||!strcmp(msg,\"Q\\n\")){close(sock);exit(0);}sprintf(name_msg,\"%s %s\", name, msg);write(sock, name_msg, strlen(name_msg));}return NULL;}void * recv_msg(void * arg)   // read thread main{int sock=*((int*)arg);char name_msg[NAME_SIZE+BUF_SIZE];int str_len;while(1){str_len=read(sock, name_msg, NAME_SIZE+BUF_SIZE-1);if(str_len==-1)return (void*)-1;name_msg[str_len]=0;fputs(name_msg, stdout);}return NULL;}void error_handling(char *msg){fputs(msg, stderr);fputc(\'\\n\', stderr);exit(1);}

结果:

chat_EPETserv.c:#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <fcntl.h>#include <errno.h>#include <arpa/inet.h>#include <sys/socket.h>#include <sys/epoll.h>#define BUF_SIZE 100#define MAX_CLNT 256#define EPOLL_SIZE 50void setnonblockingmode(int fd);void error_handling(char *buf);void send_msg(char * msg, int len);int clnt_cnt=0;int clnt_socks[MAX_CLNT];int main(int argc, char *argv[]){int serv_sock, clnt_sock;struct sockaddr_in serv_adr, clnt_adr;socklen_t adr_sz;int str_len, i;char buf[BUF_SIZE];struct epoll_event *ep_events;struct epoll_event event;int epfd, event_cnt;if(argc!=2) {printf(\"Usage : %s <port>\\n\", argv[0]);exit(1);}serv_sock=socket(PF_INET, SOCK_STREAM, 0);memset(&serv_adr, 0, sizeof(serv_adr));serv_adr.sin_family=AF_INET;serv_adr.sin_addr.s_addr=htonl(INADDR_ANY);serv_adr.sin_port=htons(atoi(argv[1]));if(bind(serv_sock, (struct sockaddr*) &serv_adr, sizeof(serv_adr))==-1)error_handling(\"bind() error\");if(listen(serv_sock, 5)==-1)error_handling(\"listen() error\");epfd=epoll_create(EPOLL_SIZE);ep_events=malloc(sizeof(struct epoll_event)*EPOLL_SIZE);setnonblockingmode(serv_sock);event.events=EPOLLIN;event.data.fd=serv_sock;epoll_ctl(epfd, EPOLL_CTL_ADD, serv_sock, &event);while(1){event_cnt=epoll_wait(epfd, ep_events, EPOLL_SIZE, -1);if(event_cnt==-1){puts(\"epoll_wait() error\");break;}puts(\"return epoll_wait\");for(i=0; i<event_cnt; i++){if(ep_events[i].data.fd==serv_sock){adr_sz=sizeof(clnt_adr);clnt_sock=accept(serv_sock, (struct sockaddr*)&clnt_adr, &adr_sz);setnonblockingmode(clnt_sock);event.events=EPOLLIN|EPOLLET;event.data.fd=clnt_sock;epoll_ctl(epfd, EPOLL_CTL_ADD, clnt_sock, &event);clnt_socks[clnt_cnt++]=clnt_sock;printf(\"connected client: %d \\n\", clnt_sock);}else{while(1){str_len=read(ep_events[i].data.fd, buf, BUF_SIZE);if(str_len==0)    // close request!{epoll_ctl(epfd, EPOLL_CTL_DEL, ep_events[i].data.fd, NULL);close(ep_events[i].data.fd);for(i=0; i<clnt_cnt; i++){if(ep_events[i].data.fd==clnt_socks[i]){while(i++<clnt_cnt-1)clnt_socks[i]=clnt_socks[i+1];break;}}clnt_cnt--;printf(\"closed client: %d \\n\", ep_events[i].data.fd);break;}else if(str_len<0){if(errno==EAGAIN)break;}else{send_msg(buf, str_len);}}}}}close(serv_sock);close(epfd);return 0;}void send_msg(char * msg, int len)   // send to all{int i;for(i=0; i<clnt_cnt; i++)write(clnt_socks[i], msg, len);}void setnonblockingmode(int fd){int flag=fcntl(fd, F_GETFL, 0);fcntl(fd, F_SETFL, flag|O_NONBLOCK);}void error_handling(char *buf){fputs(buf, stderr);fputc(\'\\n\', stderr);exit(1);}

结果:

赞(0) 打赏
未经允许不得转载:爱站程序员基地 » (TCP IP网络编程)实验六 epoll模型编程