I used epoll to write a simple HTTP server that can be correctly processed when the client sends data for the first time. However, when the client does not close the server, the server cannot read the data, please help me to see what's wrong. Thank you.
</PRE> </P> <p> server. h </P> <p> <PRE name = "code" class = "CPP">/** server. h ** created on: Jun 23,201 4 * Author: fangjian */# include <netinet/in. h> # ifndef server_h _ # define query_init_len 10 # define remain_buffer 5/* The following is the state of the processing machine */# define accept 1 # define read 2 # define query_line 4 # define query_head 8 # define query_body 16 # define send_data 32 struct connection {int FD; struct sockaddr_in client_address; int state; // the stage of the current processing char * querybuf; int query_start_index; // The current int query_end_index of the request data; // The next position of the request data: int query_remain_len; // available space char method [8]; char URI [128]; char version [16]; char host [128]; char accept [128]; char conn [20] ;}; struct server {int epollfd ;}; void web_epoll_ctl (INT epollfd, int CTL, int FD, int flag ); int setnonblocking (int fd); struct connection * initconnection (int fd); void state_machine (struct connection & conn); void web_accept (struct connection & conn ); void read_request (struct connection & conn); void process_request_line (struct connection & conn); void process_head (struct connection & conn); void process_body (struct connection & conn ); void send_response (struct connection & conn); void try_to_enlarge_buffer (struct connection & conn); void close_connection (int fd); # endif/* server_h _*/
Server. cpp:
/** Server. CPP ** created on: Jun 23,201 4 * Author: fangjian */# include "server. H "# include <stdio. h> # include <netinet/in. h> # include <ARPA/inet. h> # include <string. h> # include <stdlib. h> # include <fcntl. h> # include <signal. h> # include <sys/socket. h> # include <sys/epoll. h> # include <sys/STAT. h> # include <sys/sendfile. h> # include <iostream> # include <map> using namespace STD; # define max_event_number 10000map <I NT, connection> map_conn; struct server; int main (INT argc, char * argv []) {const char * IP = "172.16.55.67"; int Port = 8083; signal (sigpipe, sig_ign); int listenfd = socket (af_inet, sock_stream, 0); struct sockaddr_in address; bzero (& Address, sizeof (Address); Address. sin_family = af_inet; inet_ton (af_inet, IP, & address. sin_addr); Address. sin_port = htons (port); BIND (listenfd, (struct sockaddr *) & Address, sizeof (Address); Listen (listenfd, 50); epoll_event events [max_event_number]; server. epollfd = epoll_create (1024); web_epoll_ctl (server. epollfd, epoll_ctl_add, listenfd, epollin); // Add the read connection event setnonblocking (listenfd); // fork (); While (true) {int number = epoll_wait (server. epollfd, events, max_event_number,-1); printf ("number = % d \ n", number); printf ("current process ID: % d \ n ", getpid (); int I; for (I = 0; I <number; I ++) {int socket = event S [I]. data. FD; // currently triggered FD // a new connection arrives at if (socket = listenfd) {printf ("New Connection arrives at \ n "); // create a connection structure struct connection * conn = initconnection (socket); // enter the state machine Processing request state_machine (* conn );} // read the event to else if (events [I]. events & epollin) {printf ("-------- start processing request line ------------ \ n"); state_machine (map_conn [socket]); printf ("-------- Processing request row ends -------------- \ n"); // sleep (2); web_epoll_ctl (server. epollfd, epoll_ctl_mod, socket, epollin);} // write event Up to else if (events [I]. events & epollout) {printf ("-------- start sending data -------------- \ n"); state_machine (map_conn [socket]); printf ("--------- end of sending data -------------- \ n ");} // exception else {}}} void state_machine (struct connection & conn) {Switch (Conn. state) {case accept: {web_accept (conn); break;} case read: {read_request (conn); break;} case query_line: {process_request_line (conn); break ;} case send_data: {send_response (conn); break ;}} }/* Call epoll_ctl to process */void web_epoll_ctl (INT epollfd, int CTL, int FD, int flag) {epoll_event event; event. data. FD = FD; event. events = flag; epoll_ctl (epollfd, CTL, FD, & event);} int setnonblocking (int fd) {int old_option = fcntl (FD, f_getfl ); int new_option = old_option | o_nonblock; fcntl (FD, f_setfl, new_option); Return old_option;} struct connection * initconnection (int fd) {struct connection * conn = (struct connect Ion *) malloc (sizeof (struct connection); Conn-> FD = FD; Conn-> state = accept; Conn-> querybuf = (char *) malloc (query_init_len ); if (! Conn-> querybuf) {printf ("malloc error \ n"); return NULL;} Conn-> query_start_index = 0; Conn-> query_end_index = 0; conn-> query_remain_len = query_init_len; return conn;} void web_accept (struct connection & conn) {socklen_t client_addrlength = sizeof (Conn. client_address); int connfd = accept (Conn. FD, (struct sockaddr *) & (Conn. client_address), & client_addrlength); If (connfd =-1) {printf ("Accept error \ n"); return;} W Eb_epoll_ctl (server. epollfd, epoll_ctl_del, Conn. FD, epollin); // Delete the listener event close (Conn. FD); // disable the listener descriptor because keep_alive is used to keep the connection descriptor from disabling Conn. FD = connfd; Conn. state = read; map_conn [connfd] = conn; web_epoll_ctl (server. epollfd, epoll_ctl_add, connfd, epollin); setnonblocking (connfd);} void read_request (struct connection & conn) {int Len, FD = Conn. FD; while (true) {/* try to increase the buffer space */try_to_enlarge_buffer (conn); Len = read (FD, Conn. queryb UF + Conn. query_end_index, Conn. query_remain_len); If (LEN =-1) {printf ("---- Data Reading ----- \ n"); Conn. state = query_line; // enter the parsing stage web_epoll_ctl (server. epollfd, epoll_ctl_del, Conn. FD, epollin); // Delete the read event break on the connection;} else if (LEN = 0) {printf ("---- the client closes the connection ------ \ n "); conn. state = query_line; // enter the parsing stage web_epoll_ctl (server. epollfd, epoll_ctl_del, Conn. FD, epollin); // Delete the read event break on the connection;} else if (LEN> 0) {Conn. query_end_index + = Le N; Conn. query_remain_len-= Len ;}} cout <"----- the client content is" <Endl; cout <Conn. querybuf <Endl; process_request_line (conn);} void process_request_line (struct connection & conn) {int Len; char * PTR = strpbrk (Conn. querybuf + Conn. query_start_index, "\ t"); If (! PTR) {printf ("failed to parse the request line \ n"); return;} Len = PTR-Conn. querybuf-Conn. query_start_index; strncpy (Conn. method, Conn. querybuf + Conn. query_start_index, Len); cout <"metnod =" <Conn. method <Endl; Conn. query_start_index + = (LEN + 1); PTR = strpbrk (Conn. querybuf + Conn. query_start_index, "\ t"); If (! PTR) {printf ("failed to parse the request line \ n"); return;} Len = PTR-Conn. querybuf-Conn. query_start_index; strncpy (Conn. uri, Conn. querybuf + Conn. query_start_index, Len); cout <"uri =" <Conn. uri <Endl; Conn. query_start_index + = (LEN + 1); PTR = strpbrk (Conn. querybuf, "\ n"); // first press enter \ r, then line feed \ NIF (! PTR) {printf ("failed to parse the request line \ n"); return;} Len = PTR-Conn. querybuf-Conn. query_start_index; strncpy (Conn. version, Conn. querybuf + Conn. query_start_index, Len); cout <"version =" <Conn. version <Endl; Conn. query_start_index + = (LEN + 1); cout <"----- request line parsed ----------" <Endl; process_head (conn);} void process_head (struct connection & conn) {cout <"------- start parsing header ------" <Endl; char * end_line; int Len; while (true) {end_l INE = strpbrk (Conn. querybuf + Conn. query_start_index, "\ n"); Len = end_line-Conn. querybuf-Conn. query_start_index; If (LEN = 1) {printf ("parsed \ n"); Conn. query_start_index + = (LEN + 1); cout <Conn. querybuf + Conn. query_start_index <Endl; break;} else {If (strncasecmp (Conn. querybuf + Conn. query_start_index, "Host:", 5) = 0) {strncpy (Conn. host, Conn. querybuf + Conn. query_start_index + 6, len-6); cout <"host =" <c ONN. host <Endl;} else if (strncasecmp (Conn. querybuf + Conn. query_start_index, "accept:", 7) = 0) {strncpy (Conn. accept, Conn. querybuf + Conn. query_start_index + 8, len-8); cout <"Accept =" <Conn. accept <Endl;} else if (strncasecmp (Conn. querybuf + Conn. query_start_index, "connection:", 11) = 0) {strncpy (Conn. conn, Conn. querybuf + Conn. query_start_index + 12, len-12); cout <"connection =" <Conn. conn <Endl;} else {} Conn. qu Ery_start_index + = (LEN + 1) ;}} process_body (conn); printf ("---- the first part has been parsed ---------- \ n");} void process_body (struct connection & conn) {If (Conn. query_start_index = Conn. query_end_index) {printf ("--- the package body is empty ---- \ n");} else {printf ("--- ----- \ n");} Conn. query_start_index = Conn. query_end_index = 0; send_response (conn);} void send_response (struct connection & conn) {char path [128] = "HTTP "; // The folder int Len = strlen (C ONN. uri); memcpy (path + 4, Conn. uri, Len); Len + = 4; path [Len] = '\ 0'; // very important int filefd = open (path, o_rdonly); If (filefd <0) {cout <"this file cannot be opened" <Endl; return;} struct stat stat_buf; fstat (filefd, & stat_buf); sendfile (Conn. FD, filefd, null, stat_buf.st_size); close (filefd); // close (Conn. FD); // If the socket connection is not closed, the browser is always loading. How can we solve this problem and keep-alive? // Web_epoll_ctl (server. epollfd, epoll_ctl_mod, Conn. FD, epollin); Conn. state = read;} void close_connection (int fd) {map_conn.erase (FD); close (FD);} void try_to_enlarge_buffer (struct connection & conn) {If (Conn. query_remain_len <remain_buffer) {int new_size = strlen (Conn. querybuf) + query_init_len; Conn. querybuf = (char *) realloc (Conn. querybuf, new_size); Conn. query_remain_len = new_size-Conn. query_end_index ;}}
Client code:
# Include <stdlib. h> # include <stdio. h> # include <assert. h> # include <unistd. h> # include <sys/types. h> # include <sys/epoll. h> # include <fcntl. h> # include <sys/socket. h> # include <netinet/in. h> # include <ARPA/inet. h> # include <string. h> static const char * request = "Get/index.html HTTP/1.1 \ r \ nconnection: keep-alive \ r \ n \ r \ nxxxxxxxxxx"; int setnonblocking (int fd) {int old_option = fcntl (FD, f_getfl); int ne W_option = old_option | o_nonblock; fcntl (FD, f_setfl, new_option); Return old_option;} void addfd (INT epoll_fd, int FD) {epoll_event event; event. data. FD = FD; event. events = epollout | epollet | epollerr; epoll_ctl (epoll_fd, epoll_ctl_add, FD, & event); setnonblocking (FD);} bool write_nbytes (INT sockfd, const char * buffer, int Len) {int bytes_write = 0; printf ("write out % d bytes to sock Et % d \ n ", Len, sockfd); While (1) {bytes_write = Send (sockfd, buffer, Len, 0); If (bytes_write =-1) {return false;} else if (bytes_write = 0) {return false;} len-= bytes_write; buffer = buffer + bytes_write; If (LEN <= 0) {return true ;}} bool read_once (INT sockfd, char * buffer, int Len) {int bytes_read = 0; memset (buffer, '\ 0', Len ); bytes_read = Recv (sockfd, buffer, le N, 0); If (bytes_read =-1) {return false;} else if (bytes_read = 0) {return false ;} printf ("read in % d bytes from socket % d with content: % s \ n", bytes_read, sockfd, buffer); Return true;} void start_conn (INT epoll_fd, int num, const char * IP, int port) {int ret = 0; struct sockaddr_in address; bzero (& Address, sizeof (Address); Address. sin_family = af_inet; inet_ton (af_inet, IP, & Address. sin_addr); Address. sin_port = htons (port); For (INT I = 0; I <num; ++ I) {sleep (1); int sockfd = socket (pf_inet, sock_stream, 0 ); printf ("create 1 sock \ n"); If (sockfd <0) {continue;} If (connect (sockfd, (struct sockaddr *) & Address, sizeof (Address )) = 0) {printf ("build connection % d \ n", I); addfd (epoll_fd, sockfd) ;}} void close_conn (INT epoll_fd, int sockf D) {epoll_ctl (epoll_fd, epoll_ctl_del, sockfd, 0); close (sockfd);} int main (INT argc, char * argv []) {assert (argc = 4); int epoll_fd = epoll_create (100); start_conn (epoll_fd, atoi (argv [3]), argv [1], atoi (argv [2]); epoll_event events [10000]; char buffer [2048]; while (1) {int FDS = epoll_wait (epoll_fd, events, 10000,200 0 ); for (INT I = 0; I <FDS; I ++) {int sockfd = E Vents [I]. Data. FD; If (events [I]. Events & epollin) {printf ("---- server sends data ----- \ n"); If (! Read_once (sockfd, buffer, 2048) {close_conn (epoll_fd, sockfd);} struct epoll_event event; event. events = epollout | epollet | epollerr; event. data. FD = sockfd; epoll_ctl (epoll_fd, epoll_ctl_mod, sockfd, & event);} else if (events [I]. events & epollout) {printf ("--------- send data to the server --------- \ n"); If (! Write_nbytes (sockfd, request, strlen (request) {close_conn (epoll_fd, sockfd);} printf ("-------- Data Transmission completed ------------- \ n"); struct epoll_event; event. events = epollin | epollet | epollerr; event. data. FD = sockfd; epoll_ctl (epoll_fd, epoll_ctl_mod, sockfd, & event);} else if (events [I]. events & epollerr) {close_conn (epoll_fd, sockfd );}}}}
Test method: create a file named "HTTP" in the server project and put an index.html static file in it, for example:
<!DOCTYPE html>Then, change the Server IP address to your own IP address to run the server. The client can directly run./main IP 8083 1. Thank you for your help.