This article does not have much content, mainly is several previously mentioned note points:
One is that Epoll's FD needs reloading. We keep the tcp_connection_t pointer in the array, so we reload the FD listener event based on this array.
//Reload the epoll of FD in the monitor event inti; for(i =0; i < events_size; ++i) {if(Connsets[i]! =NULL) { intFD = i;//FDtcp_connection_t *pt = connsets[i];//TCP Connuint32_tEvent=0; if(Buffer_is_readable (&pt->buffer_)) Event|=kwriteevent; if(Buffer_is_writeable (&pt->buffer_)) Event|=kreadevent; //Reset Listener EventsEPOLL_MOD_FD (EPOLLFD, FD,Event); } }
Second, when establishing a connection, the work to be done is:
1. Create a new tcp_connection_t structure, initialize
2. Add FD to Epoll, do not listen for any events
3. Add the tcp_connection_t pointer to the array.
The code is as follows:
//Establish a connectionintPEERFD = ACCEPT4 (LISTENFD, NULL, NULL, Sock_nonblock |sock_cloexec);if(PEERFD = =-1) Err_exit ("Accept4");//New TCP connectiontcp_connection_t *pt = (tcp_connection_t*) malloc (sizeof(tcp_connection_t)); Buffer_init (&pt->buffer_);//Place the TCP connection into the ConnsetsCONNSETS[PEERFD] =pt;epoll_add_fd (EPOLLFD, PEERFD,0);
When the connection is closed, you need:
// Close = NULL;
Another point: We recorded the relationship between FD and Connsets, using the array subscript, in fact, we can also put the pointer in the Epoll data, which:
typedef Union EPOLL_DATA { void *ptr; int FD; uint32_t u32; uint64_t U64;} epoll_data_t; struct epoll_event { uint32_t events; /* */ epoll_data_t data ; /* */};
For the data consortium, we no longer use FD, but we use PTR, which points to a tcp_connection_t pointer. However, we need to store FD in the tcp_connection_t data structure.
For the sake of brevity, the previous method is still used, and the reader can try it out on its own.
The complete code is as follows:
#define_gnu_source/* See Feature_test_macros (7) */#include<sys/socket.h>#include"sysutil.h"#include"Buffer.h"#include<assert.h>#include<sys/epoll.h>#defineEvents_size 1024typedefstruct{buffer_t buffer_;} tcp_connection_t;//represents a TCP connectiontcp_connection_t*connsets[events_size];//provides mappings from FD to TCP connectionsintMainintargcChar Const*argv[]) { //Get listener FD intLISTENFD = Tcp_server ("localhost",9981); //set the Listen FD to non-blockingActivate_nonblock (LISTENFD); //Initialize Connsets intIX; for(ix =0; IX < Events_size; ++ix) {Connsets[ix]=NULL; } //Initialize Epoll intEPOLLFD = Epoll_create1 (0); EPOLL_ADD_FD (EPOLLFD, LISTENFD, kreadevent); structEpoll_event events[1024x768]; while(1) { //Reload the epoll of FD in the monitor event inti; for(i =0; i < events_size; ++i) {if(Connsets[i]! =NULL) { intFD = i;//FDtcp_connection_t *pt = connsets[i];//TCP Connuint32_tEvent=0; if(Buffer_is_readable (&pt->buffer_)) Event|=kwriteevent; if(Buffer_is_writeable (&pt->buffer_)) Event|=kreadevent; //Reset Listener EventsEPOLL_MOD_FD (EPOLLFD, FD,Event); } } //epoll Monitoring FD intNready = epoll_wait (EPOLLFD, events,1024x768, the); if(Nready = =-1) Err_exit ("epoll Wait"); Else if(Nready = =0) {printf ("Epoll timeout.\n"); Continue; } //processing FD for(i =0; i < Nready; ++i) {intFD =EVENTS[I].DATA.FD; uint32_t revents=events[i].events; if(FD = = LISTENFD)//Processing Listen FD { if(Revents &kreadrevent) { //Establish a connection intPEERFD = ACCEPT4 (LISTENFD, NULL, NULL, Sock_nonblock |sock_cloexec); if(PEERFD = =-1) Err_exit ("Accept4"); //New TCP connectiontcp_connection_t *pt = (tcp_connection_t*) malloc (sizeof(tcp_connection_t)); Buffer_init (&pt->buffer_); //Place the TCP connection into the ConnsetsCONNSETS[PEERFD] =pt; EPOLL_ADD_FD (EPOLLFD, PEERFD,0); } } Else //processing of FD for ordinary customers { //Remove the pointertcp_connection_t *pt =CONNSETS[FD]; Assert (PT!=NULL); if(Revents &kreadrevent) { if(Buffer_read (&pt->buffer_, fd) = =0) { //Closeepoll_del_fd (EPOLLFD, FD); Close (FD); Free (PT); CONNSETS[FD]=NULL; Continue;//continue the next cycle } } if(Revents &kwriterevent) {Buffer_write (&pt->Buffer_, FD); }}}} close (LISTENFD); return 0;}
The following uses the Epoll et pattern.
Linux non-blocking IO (eight) uses Epoll to re-implement non-blocking back-firing servers