0. Chunyang quotations, code nesting more than three layers is a piece of rubbish. So good programming style starts with encapsulation.
1. Encapsulating the Select server model
1.1 How to package? The data structures that are required for select are encapsulated into structs, passed between functions by parameters, and the fixed operations are encapsulated into corresponding functions.
1.2 Post-packaged program:
1.2.1 encapsulated header file select_t.h
#ifndef __select_t_h__#define __select_t_h__#include <sys/select.h> #include <sys/types.h> #include < sys/socket.h> #include <errno.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> #define ERR_EXIT (m) do { perror (m); Exit (exit_failure); } while (0) typedef struct{ fd_set allset_; Fd_set rset_; int clients_[fd_setsize]; int maxi_; int maxfd_; int nready_; int listenfd_; void (*handle_callback_) (int, char *buf); There are user-supplied callback functions}select_t;void select_init (select_t *sel, int listenfd); void Select_set_callback (select_t *sel, void (* handler) (int, char *buf)), void select_do_wait (select_t *sel), void Select_handle_accept (select_t *sel); void select_ Handle_data (select_t *sel); #endif
1.2.2 Encapsulated Select class function select_t.c
#include "select_t.h" #include "network.h" #include <assert.h>//only for internal calls to void Select_add_fd (select_t *sel, int fd ); Joins the newly connected FD into the Listener collection and the Clients array void select_del_fd (select_t *sel, int i); The FD closes the base from the listener collection and clients array, and closes the connection void Select_init (select_t *sel, int listenfd) {sel->listenfd_ = LISTENFD; Fd_zero (&sel->allset_); Fd_zero (&sel->rset_); Fd_set (LISTENFD, &sel->allset_); int i; for (i = 0; i < fd_setsize; i++) {Sel->clients_[i] =-1; } sel->maxi_ =-1; Sel->maxfd_ = LISTENFD;} void Select_set_callback (select_t *sel, Void (*handler) (int, char*)) {sel->handle_callback_ = handler;} void Select_do_wait (select_t *sel) {sel->rset_ = sel->allset_; do{sel->nready_ = Select (Sel->maxfd_ + 1, &sel->rset_, NULL, NULL, NULL); }while (Sel->nready_ = =-1 && errno = = eintr);} void Select_handle_accept (select_t *sel) {if (Fd_isset (Sel->listenfd_, &sel->rset_)) {int PEERFD = Accept (sel->listenfd_, NULL, NULL); if (PEERFD = =-1) err_exit ("accept"); SELECT_ADD_FD (SEL, PEERFD); } sel->nready_--;} void Select_handle_data (select_t *sel) {if (Sel->nready_ = = 0) return; int i; Char recvbuf[1024] = {0}; for (i = 0; i < fd_setsize; i++) {if (sel->clients_[i] = = 1) continue; int FD = sel->clients_[i]; if (Fd_isset (Sel->clients_[i], &sel->rset_)) {//? Here with FD the error int ret = ReadLine (FD, RECVBUF, 1024); if (ret = =-1) err_exit ("ReadLine"); else if (ret = = 0) {printf ("Client closed\n"); SELECT_DEL_FD (sel, i); Continue } sel->handle_callback_ (FD, RECVBUF); }}}void select_add_fd (select_t *sel, int fd) {int i; for (i = 0; i < fd_setsize; i++) {if (sel->clients_[i] = = 1) {Sel->clients_[i] = FD; if (i > sel->maxi_) sel->maxi_ = i; Break }} if (i = = fd_setsize) {fprintf (stderr, "too many clients\n"); Close (FD); Exit (exit_failure);//! } fd_set (FD, &sel->allset_); if (fd > Sel->maxfd_) sel->maxfd_ = FD;} void Select_del_fd (select_t *sel, int i) {assert (i >= 0 && i < fd_setsize);//! int FD = sel->clients_[i]; Sel->clients_[i] =-1; FD_CLR (FD, &sel->allset_); Close (FD);}
1.2.3 Mian function after encapsulation server.c
#include "network.h" #include "select_t.h"/* * Server-side Use SELECT Model * * This provides a way for the server to process client requests * Server callback this function */void handler (int fd, CHA R *buf) { printf ("Recv data:%s", buf); Writen (FD, buf, strlen (BUF));} int main (int argc, const char *argv[]) { if (signal (sigpipe, sig_ign) = = Sig_err) err_exit ("signal"); int listenfd = Listenfd_init (); select_t sel; Select_init (&sel, LISTENFD); Select_set_callback (&sel, handler); while (1) { select_do_wait (&sel); Select_handle_accept (&sel); Select_handle_data (&sel); } Close (LISTENFD); return 0;}
2. Encapsulating the poll server model
2.1 Package header File Poll_t.h
#ifndef __poll_t_h__#define __poll_t_h__#include <poll.h> #include <assert.h> #define ERR_EXIT (m) do { perror (m); Exit (exit_failure); } while (0) typedef struct{ struct POLLFD clients_[2048]; int maxi_; int nready_; int listenfd_; void (*handle_callback_) (int, char*);} Poll_t;void Poll_init (poll_t *pol, int listenfd, void (*handler) (int, char*)), void poll_do_wait (poll_t *pol); void Poll_ Handle_accept (poll_t *pol); void Poll_handle_data (poll_t *pol); #endif
2.2 Encapsulated function poll_t.c
#include "poll_t.h" #include "network.h" void poll_add_fd (poll_t *pol, int fd); void Poll_del_fd (poll_t *pol, int i); void PO LL_init (poll_t *pol, int listenfd, void (*handler) (int, char*)) {pol->listenfd_ = LISTENFD; int i; for (i = 0; i < 2048; i++) {pol->clients_[i].fd =-1; } POL->CLIENTS_[0].FD = LISTENFD; Pol->clients_[0].events = Pollin; Pol->maxi_ = 0; Pol->nready_ = 0; Pol->handle_callback_ = handler;} void Poll_do_wait (poll_t *pol) {int nready; do{Nready = Poll (pol->clients_, Pol->maxi_ + 1,-1); }while (Nready = =-1 && errno = = eintr); if (Nready = =-1) err_exit ("poll"); Pol->nready_ = Nready;} void Poll_handle_accept (poll_t *pol) {if (Pol->clients_[0].revents & pollin) {int peerfd = accept (pol-> Listenfd_, NULL, NULL); if (PEERFD = =-1) err_exit ("accept"); POLL_ADD_FD (Pol, PEERFD); --pol->nready_; }}void Poll_handle_data (poll_t*pol) {if (Pol->nready_ = = 0) return; int i; Char recvbuf[1024] = {0}; for (i = 1; I <= pol->maxi_; i++) {int PEERFD = pol->clients_[i].fd; if (PEERFD = =-1) continue; if (Pol->clients_[i].revents & pollin) {int ret = ReadLine (PEERFD, RECVBUF, 1024); if (ret = =-1) err_exit ("ReadLine"); else if (ret = = 0) {printf ("Client closed\n"); POLL_DEL_FD (Pol, i); Continue } pol->handle_callback_ (PEERFD, recvbuf); }}}void poll_add_fd (poll_t *pol, int fd) {int i; for (i = 0; i < 2048; i++) {if (POL->CLIENTS_[I].FD = =-1) {pol->clients_[i].fd = FD; Pol->clients_[i].events= Pollin; if (i > pol->maxi_) pol->maxi_ = i; Break }} if (i = = 2048) {fprintf (stderr, "too many clients\n"); Close (FD); Exit (Exit_failure); }}void poll_del_fd (poll_t *pol, int i) {assert (I >= 1 && i < 2048);//close (POL->CLIENTS_[I].FD); POL->CLIENTS_[I].FD =-1;}
The main function server.c after 2.3 encapsulation
#include "network.h" #include "poll_t.h" void handler (int fd, char *buf) { printf ("Recv data:%s", buf); Writen (FD, buf, strlen (BUF));} int main (int argc, const char *argv[]) { if (signal (sigpipe, sig_ign) = = Sig_err) err_exit ("signal"); int listenfd = Listenfd_init (); poll_t Pol; Poll_init (&pol, LISTENFD, handler); while (1) { poll_do_wait (&pol); Poll_handle_accept (&pol); Poll_handle_data (&pol); } Close (LISTENFD); return 0;}
3. Encapsulating the Epoll server model
3.1 Package header File epoll_t.c
#ifndef __epoll_t_h__#define __epoll_t_h__#include <sys/epoll.h> #define ERR_EXIT (m) do { perror (m); Exit (exit_failure); } while (0) typedef struct{ int epollfd_; struct epoll_event events_[2048]; int listenfd_; int nready_; void (*handle_callback_) (int, char*);} Epoll_t;void Epoll_init (epoll_t *epo, int listenfd, void (*handler) (int, char*)), void epoll_do_wait (epoll_t *epo); void Epoll_handle (epoll_t *epo); void Epoll_close (epoll_t *epo); #endif
The Epoll class function after 3.2 encapsulation epoll_t.c
#include "epoll_t.h" #include "network.h" void Epoll_handle_accept (epoll_t *epo), void Epoll_handle_data (epoll_t *epo, int peerfd), void epoll_add_fd (epoll_t *epo, int fd), void epoll_del_fd (epoll_t *epo, int fd), void Epoll_init (epoll_t *epo, int listenfd, void (*handler) (int, char*)) {if (Epo->epollfd_ = Epoll_create (2048)) = =-1) err_exit ("EPOLL_CR Eate "); Epo->listenfd_ = LISTENFD; EPOLL_ADD_FD (EPO, LISTENFD); Epo->nready_ = 0; Epo->handle_callback_ = handler;} void Epoll_do_wait (epoll_t *epo) {int nready; do{Nready = epoll_wait (Epo->epollfd_, Epo->events_, 2048,-1); }while (Nready = =-1 && errno = = eintr); if (Nready = =-1) err_exit ("epoll_wait"); Epo->nready_ = Nready;} void Epoll_handle (epoll_t *epo) {int i; for (i = 0; i < epo->nready_; i++) {int FD = epo->events_[i].data.fd; if (fd = = epo->listenfd_) {epoll_handle_accept (EPO); } else Epoll_hAndle_data (EPO, FD); }}void epoll_handle_accept (epoll_t *epo) {int peerfd = accept (epo->listenfd_, NULL, NULL); if (PEERFD = =-1) err_exit ("accept"); EPOLL_ADD_FD (EPO, PEERFD);} void Epoll_handle_data (epoll_t *epo, int peerfd) {char recvbuf[1024] = {0}; int ret = ReadLine (PEERFD, RECVBUF, 1024); if (ret = =-1) err_exit ("ReadLine"); else if (ret = = 0) {printf ("Client closed\n"); EPOLL_DEL_FD (EPO, PEERFD); Return } epo->handle_callback_ (PEERFD, recvbuf);} void Epoll_close (epoll_t *epo) {close (epo->epollfd_); Close (epo->listenfd_);} void Epoll_add_fd (epoll_t *epo, int fd) {struct epoll_event ev; EV.DATA.FD = FD; Ev.events = Epollin; if (Epoll_ctl (Epo->epollfd_, Epoll_ctl_add, FD, &ev) = =-1) err_exit ("Epoll_ctl");} void Epoll_del_fd (epoll_t *epo, int fd) {struct epoll_event ev; EV.DATA.FD = FD; if (Epoll_ctl (Epo->epollfd_, Epoll_ctl_del, FD, &ev) = =-1) err_exit ("EPOLl_ctl ");}
The main function server.c after 3.3 encapsulation
#include "network.h" #include "epoll_t.h" void handler (int fd, char *buf) { printf ("Recv data:%s", buf); Writen (FD, buf, strlen (BUF));} int main (int argc, const char *argv[]) { if (signal (sigpipe, sig_ign) = = Sig_err) err_exit ("signal"); int listenfd = Listenfd_init (); epoll_t EPO; Epoll_init (&epo, LISTENFD, handler); while (1) { epoll_do_wait (&epo); Epoll_handle (&epo); } Epoll_close (&epo); return 0;}
4. Summary
Encapsulation of a program to write, debugging is very important, the code after the package readability significantly improved, so in the future when writing programs, pay attention to this point. In addition, from the encapsulation of these three models, Epoll is obviously more simple and convenient, therefore, in the future when the server to write a select to Epoll.