├── 5 ├── 5-10set_send_buffer.cpp ├── 5-11set_recv_buffer.cpp ├── 5-12access_daytime.cpp ├── 5-1byteorder.cpp ├── 5-3testlisten.cpp ├── 5-5testaccept.cpp ├── 5-6oobsend.cpp ├── 5-7oobrecv.cpp └── 5-9reuse_address.cpp ├── 6 ├── 6-1testdup.cpp ├── 6-2testwritev.cpp ├── 6-3testsendfile.cpp ├── 6-4testsplice.cpp └── 6-5testtee.cpp ├── 7 ├── 7-1testeuid.cpp ├── 7-2switchuser.cpp └── 7-3daemonize.cpp ├── 8 └── 8-3httpparser.cpp ├── 9 ├── 9-1use_select.cpp ├── 9-3mtlt.cpp ├── 9-4oneshot.cpp ├── 9-5unblockconnect.cpp ├── 9-6mytalk_client.cpp ├── 9-7mytalk_server.cpp ├── 9-8multi_port.cpp └── 9-8multi_port.cpp.bak ├── 10 ├── 10-1unievent.cpp └── 10-3sigurg.cpp ├── 11 ├── 11-1connect_timeout.cpp ├── 11-2lst_timer.h ├── 11-3nonactive_conn.cpp ├── 11-4io_timer.cpp ├── 11-5tw_timer.h └── 11-6time_heap.h ├── 12 └── 12-1libevent_test.c ├── 13 ├── 13-3sem.cpp ├── 13-4shm_talk_server.cpp └── 13-5passfd.cpp ├── 14 ├── 14-1mutual_lock.c ├── 14-2locker.h ├── 14-3thread_atfork.c └── 14-5sigmask.c ├── 15 ├── 15-1processpool.h ├── 15-2pool_cgi.cpp ├── 15-3threadpool.h ├── 15-4http_conn.h ├── 15-5http_conn.cpp └── 15-6main.cpp ├── 16 └── 16-4stress_client.cpp ├── README.md └── springsnail ├── Makefile ├── config.xml ├── conn.cpp ├── conn.h ├── fdwrapper.cpp ├── fdwrapper.h ├── log.cpp ├── log.h ├── main.cpp ├── mgr.cpp ├── mgr.h └── processpool.h /10/10-1unievent.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #define MAX_EVENT_NUMBER 1024 17 | static int pipefd[2]; 18 | 19 | int setnonblocking( int fd ) 20 | { 21 | int old_option = fcntl( fd, F_GETFL ); 22 | int new_option = old_option | O_NONBLOCK; 23 | fcntl( fd, F_SETFL, new_option ); 24 | return old_option; 25 | } 26 | 27 | void addfd( int epollfd, int fd ) 28 | { 29 | epoll_event event; 30 | event.data.fd = fd; 31 | event.events = EPOLLIN | EPOLLET; 32 | epoll_ctl( epollfd, EPOLL_CTL_ADD, fd, &event ); 33 | setnonblocking( fd ); 34 | } 35 | 36 | void sig_handler( int sig ) 37 | { 38 | int save_errno = errno; 39 | int msg = sig; 40 | send( pipefd[1], ( char* )&msg, 1, 0 ); 41 | errno = save_errno; 42 | } 43 | 44 | void addsig( int sig ) 45 | { 46 | struct sigaction sa; 47 | memset( &sa, '\0', sizeof( sa ) ); 48 | sa.sa_handler = sig_handler; 49 | sa.sa_flags |= SA_RESTART; 50 | sigfillset( &sa.sa_mask ); 51 | assert( sigaction( sig, &sa, NULL ) != -1 ); 52 | } 53 | 54 | int main( int argc, char* argv[] ) 55 | { 56 | if( argc <= 2 ) 57 | { 58 | printf( "usage: %s ip_address port_number\n", basename( argv[0] ) ); 59 | return 1; 60 | } 61 | const char* ip = argv[1]; 62 | int port = atoi( argv[2] ); 63 | 64 | int ret = 0; 65 | struct sockaddr_in address; 66 | bzero( &address, sizeof( address ) ); 67 | address.sin_family = AF_INET; 68 | inet_pton( AF_INET, ip, &address.sin_addr ); 69 | address.sin_port = htons( port ); 70 | 71 | int listenfd = socket( PF_INET, SOCK_STREAM, 0 ); 72 | assert( listenfd >= 0 ); 73 | 74 | //int nReuseAddr = 1; 75 | //setsockopt( listenfd, SOL_SOCKET, SO_REUSEADDR, &nReuseAddr, sizeof( nReuseAddr ) ); 76 | ret = bind( listenfd, ( struct sockaddr* )&address, sizeof( address ) ); 77 | if( ret == -1 ) 78 | { 79 | printf( "errno is %d\n", errno ); 80 | return 1; 81 | } 82 | //assert( ret != -1 ); 83 | 84 | ret = listen( listenfd, 5 ); 85 | assert( ret != -1 ); 86 | 87 | epoll_event events[ MAX_EVENT_NUMBER ]; 88 | int epollfd = epoll_create( 5 ); 89 | assert( epollfd != -1 ); 90 | addfd( epollfd, listenfd ); 91 | 92 | ret = socketpair( PF_UNIX, SOCK_STREAM, 0, pipefd ); 93 | assert( ret != -1 ); 94 | setnonblocking( pipefd[1] ); 95 | addfd( epollfd, pipefd[0] ); 96 | 97 | // add all the interesting signals here 98 | addsig( SIGHUP ); 99 | addsig( SIGCHLD ); 100 | addsig( SIGTERM ); 101 | addsig( SIGINT ); 102 | bool stop_server = false; 103 | 104 | while( !stop_server ) 105 | { 106 | int number = epoll_wait( epollfd, events, MAX_EVENT_NUMBER, -1 ); 107 | if ( ( number < 0 ) && ( errno != EINTR ) ) 108 | { 109 | printf( "epoll failure\n" ); 110 | break; 111 | } 112 | 113 | for ( int i = 0; i < number; i++ ) 114 | { 115 | int sockfd = events[i].data.fd; 116 | if( sockfd == listenfd ) 117 | { 118 | struct sockaddr_in client_address; 119 | socklen_t client_addrlength = sizeof( client_address ); 120 | int connfd = accept( listenfd, ( struct sockaddr* )&client_address, &client_addrlength ); 121 | addfd( epollfd, connfd ); 122 | } 123 | else if( ( sockfd == pipefd[0] ) && ( events[i].events & EPOLLIN ) ) 124 | { 125 | int sig; 126 | char signals[1024]; 127 | ret = recv( pipefd[0], signals, sizeof( signals ), 0 ); 128 | if( ret == -1 ) 129 | { 130 | continue; 131 | } 132 | else if( ret == 0 ) 133 | { 134 | continue; 135 | } 136 | else 137 | { 138 | for( int i = 0; i < ret; ++i ) 139 | { 140 | //printf( "I caugh the signal %d\n", signals[i] ); 141 | switch( signals[i] ) 142 | { 143 | case SIGCHLD: 144 | case SIGHUP: 145 | { 146 | continue; 147 | } 148 | case SIGTERM: 149 | case SIGINT: 150 | { 151 | stop_server = true; 152 | } 153 | } 154 | } 155 | } 156 | } 157 | else 158 | { 159 | } 160 | } 161 | } 162 | 163 | printf( "close fds\n" ); 164 | close( listenfd ); 165 | close( pipefd[1] ); 166 | close( pipefd[0] ); 167 | return 0; 168 | } 169 | -------------------------------------------------------------------------------- /10/10-3sigurg.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #define BUF_SIZE 1024 14 | 15 | static int connfd; 16 | 17 | void sig_urg( int sig ) 18 | { 19 | int save_errno = errno; 20 | 21 | char buffer[ BUF_SIZE ]; 22 | memset( buffer, '\0', BUF_SIZE ); 23 | int ret = recv( connfd, buffer, BUF_SIZE-1, MSG_OOB ); 24 | printf( "got %d bytes of oob data '%s'\n", ret, buffer ); 25 | 26 | errno = save_errno; 27 | } 28 | 29 | void addsig( int sig, void ( *sig_handler )( int ) ) 30 | { 31 | struct sigaction sa; 32 | memset( &sa, '\0', sizeof( sa ) ); 33 | sa.sa_handler = sig_handler; 34 | sa.sa_flags |= SA_RESTART; 35 | sigfillset( &sa.sa_mask ); 36 | assert( sigaction( sig, &sa, NULL ) != -1 ); 37 | } 38 | 39 | int main( int argc, char* argv[] ) 40 | { 41 | if( argc <= 2 ) 42 | { 43 | printf( "usage: %s ip_address port_number\n", basename( argv[0] ) ); 44 | return 1; 45 | } 46 | const char* ip = argv[1]; 47 | int port = atoi( argv[2] ); 48 | 49 | struct sockaddr_in address; 50 | bzero( &address, sizeof( address ) ); 51 | address.sin_family = AF_INET; 52 | inet_pton( AF_INET, ip, &address.sin_addr ); 53 | address.sin_port = htons( port ); 54 | 55 | int sock = socket( PF_INET, SOCK_STREAM, 0 ); 56 | assert( sock >= 0 ); 57 | 58 | int ret = bind( sock, ( struct sockaddr* )&address, sizeof( address ) ); 59 | assert( ret != -1 ); 60 | 61 | ret = listen( sock, 5 ); 62 | assert( ret != -1 ); 63 | 64 | struct sockaddr_in client; 65 | socklen_t client_addrlength = sizeof( client ); 66 | connfd = accept( sock, ( struct sockaddr* )&client, &client_addrlength ); 67 | if ( connfd < 0 ) 68 | { 69 | printf( "errno is: %d\n", errno ); 70 | } 71 | else 72 | { 73 | addsig( SIGURG, sig_urg ); 74 | fcntl( connfd, F_SETOWN, getpid() ); 75 | 76 | char buffer[ BUF_SIZE ]; 77 | while( 1 ) 78 | { 79 | memset( buffer, '\0', BUF_SIZE ); 80 | ret = recv( connfd, buffer, BUF_SIZE-1, 0 ); 81 | if( ret <= 0 ) 82 | { 83 | break; 84 | } 85 | printf( "got %d bytes of normal data '%s'\n", ret, buffer ); 86 | } 87 | 88 | close( connfd ); 89 | } 90 | 91 | close( sock ); 92 | return 0; 93 | } 94 | 95 | -------------------------------------------------------------------------------- /11/11-1connect_timeout.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | int timeout_connect( const char* ip, int port, int time ) 14 | { 15 | int ret = 0; 16 | struct sockaddr_in address; 17 | bzero( &address, sizeof( address ) ); 18 | address.sin_family = AF_INET; 19 | inet_pton( AF_INET, ip, &address.sin_addr ); 20 | address.sin_port = htons( port ); 21 | 22 | int sockfd = socket( PF_INET, SOCK_STREAM, 0 ); 23 | assert( sockfd >= 0 ); 24 | 25 | struct timeval timeout; 26 | timeout.tv_sec = time; 27 | timeout.tv_usec = 0; 28 | socklen_t len = sizeof( timeout ); 29 | ret = setsockopt( sockfd, SOL_SOCKET, SO_SNDTIMEO, &timeout, len ); 30 | assert( ret != -1 ); 31 | 32 | ret = connect( sockfd, ( struct sockaddr* )&address, sizeof( address ) ); 33 | if ( ret == -1 ) 34 | { 35 | if( errno == EINPROGRESS ) 36 | { 37 | printf( "connecting timeout\n" ); 38 | return -1; 39 | } 40 | printf( "error occur when connecting to server\n" ); 41 | return -1; 42 | } 43 | 44 | return sockfd; 45 | } 46 | 47 | int main( int argc, char* argv[] ) 48 | { 49 | if( argc <= 2 ) 50 | { 51 | printf( "usage: %s ip_address port_number\n", basename( argv[0] ) ); 52 | return 1; 53 | } 54 | const char* ip = argv[1]; 55 | int port = atoi( argv[2] ); 56 | 57 | int sockfd = timeout_connect( ip, port, 10 ); 58 | if ( sockfd < 0 ) 59 | { 60 | return 1; 61 | } 62 | return 0; 63 | } 64 | -------------------------------------------------------------------------------- /11/11-2lst_timer.h: -------------------------------------------------------------------------------- 1 | #ifndef LST_TIMER 2 | #define LST_TIMER 3 | 4 | #include 5 | 6 | #define BUFFER_SIZE 64 7 | class util_timer; 8 | struct client_data 9 | { 10 | sockaddr_in address; 11 | int sockfd; 12 | char buf[ BUFFER_SIZE ]; 13 | util_timer* timer; 14 | }; 15 | 16 | class util_timer 17 | { 18 | public: 19 | util_timer() : prev( NULL ), next( NULL ){} 20 | 21 | public: 22 | time_t expire; 23 | void (*cb_func)( client_data* ); 24 | client_data* user_data; 25 | util_timer* prev; 26 | util_timer* next; 27 | }; 28 | 29 | class sort_timer_lst 30 | { 31 | public: 32 | sort_timer_lst() : head( NULL ), tail( NULL ) {} 33 | ~sort_timer_lst() 34 | { 35 | util_timer* tmp = head; 36 | while( tmp ) 37 | { 38 | head = tmp->next; 39 | delete tmp; 40 | tmp = head; 41 | } 42 | } 43 | void add_timer( util_timer* timer ) 44 | { 45 | if( !timer ) 46 | { 47 | return; 48 | } 49 | if( !head ) 50 | { 51 | head = tail = timer; 52 | return; 53 | } 54 | if( timer->expire < head->expire ) 55 | { 56 | timer->next = head; 57 | head->prev = timer; 58 | head = timer; 59 | return; 60 | } 61 | add_timer( timer, head ); 62 | } 63 | void adjust_timer( util_timer* timer ) 64 | { 65 | if( !timer ) 66 | { 67 | return; 68 | } 69 | util_timer* tmp = timer->next; 70 | if( !tmp || ( timer->expire < tmp->expire ) ) 71 | { 72 | return; 73 | } 74 | if( timer == head ) 75 | { 76 | head = head->next; 77 | head->prev = NULL; 78 | timer->next = NULL; 79 | add_timer( timer, head ); 80 | } 81 | else 82 | { 83 | timer->prev->next = timer->next; 84 | timer->next->prev = timer->prev; 85 | add_timer( timer, timer->next ); 86 | } 87 | } 88 | void del_timer( util_timer* timer ) 89 | { 90 | if( !timer ) 91 | { 92 | return; 93 | } 94 | if( ( timer == head ) && ( timer == tail ) ) 95 | { 96 | delete timer; 97 | head = NULL; 98 | tail = NULL; 99 | return; 100 | } 101 | if( timer == head ) 102 | { 103 | head = head->next; 104 | head->prev = NULL; 105 | delete timer; 106 | return; 107 | } 108 | if( timer == tail ) 109 | { 110 | tail = tail->prev; 111 | tail->next = NULL; 112 | delete timer; 113 | return; 114 | } 115 | timer->prev->next = timer->next; 116 | timer->next->prev = timer->prev; 117 | delete timer; 118 | } 119 | void tick() 120 | { 121 | if( !head ) 122 | { 123 | return; 124 | } 125 | printf( "timer tick\n" ); 126 | time_t cur = time( NULL ); 127 | util_timer* tmp = head; 128 | while( tmp ) 129 | { 130 | if( cur < tmp->expire ) 131 | { 132 | break; 133 | } 134 | tmp->cb_func( tmp->user_data ); 135 | head = tmp->next; 136 | if( head ) 137 | { 138 | head->prev = NULL; 139 | } 140 | delete tmp; 141 | tmp = head; 142 | } 143 | } 144 | 145 | private: 146 | void add_timer( util_timer* timer, util_timer* lst_head ) 147 | { 148 | util_timer* prev = lst_head; 149 | util_timer* tmp = prev->next; 150 | while( tmp ) 151 | { 152 | if( timer->expire < tmp->expire ) 153 | { 154 | prev->next = timer; 155 | timer->next = tmp; 156 | tmp->prev = timer; 157 | timer->prev = prev; 158 | break; 159 | } 160 | prev = tmp; 161 | tmp = tmp->next; 162 | } 163 | if( !tmp ) 164 | { 165 | prev->next = timer; 166 | timer->prev = prev; 167 | timer->next = NULL; 168 | tail = timer; 169 | } 170 | 171 | } 172 | 173 | private: 174 | util_timer* head; 175 | util_timer* tail; 176 | }; 177 | 178 | #endif 179 | -------------------------------------------------------------------------------- /11/11-3nonactive_conn.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include "lst_timer.h" 16 | 17 | #define FD_LIMIT 65535 18 | #define MAX_EVENT_NUMBER 1024 19 | #define TIMESLOT 5 20 | 21 | static int pipefd[2]; 22 | static sort_timer_lst timer_lst; 23 | static int epollfd = 0; 24 | 25 | int setnonblocking( int fd ) 26 | { 27 | int old_option = fcntl( fd, F_GETFL ); 28 | int new_option = old_option | O_NONBLOCK; 29 | fcntl( fd, F_SETFL, new_option ); 30 | return old_option; 31 | } 32 | 33 | void addfd( int epollfd, int fd ) 34 | { 35 | epoll_event event; 36 | event.data.fd = fd; 37 | event.events = EPOLLIN | EPOLLET; 38 | epoll_ctl( epollfd, EPOLL_CTL_ADD, fd, &event ); 39 | setnonblocking( fd ); 40 | } 41 | 42 | void sig_handler( int sig ) 43 | { 44 | int save_errno = errno; 45 | int msg = sig; 46 | send( pipefd[1], ( char* )&msg, 1, 0 ); 47 | errno = save_errno; 48 | } 49 | 50 | void addsig( int sig ) 51 | { 52 | struct sigaction sa; 53 | memset( &sa, '\0', sizeof( sa ) ); 54 | sa.sa_handler = sig_handler; 55 | sa.sa_flags |= SA_RESTART; 56 | sigfillset( &sa.sa_mask ); 57 | assert( sigaction( sig, &sa, NULL ) != -1 ); 58 | } 59 | 60 | void timer_handler() 61 | { 62 | timer_lst.tick(); 63 | alarm( TIMESLOT ); 64 | } 65 | 66 | void cb_func( client_data* user_data ) 67 | { 68 | epoll_ctl( epollfd, EPOLL_CTL_DEL, user_data->sockfd, 0 ); 69 | assert( user_data ); 70 | close( user_data->sockfd ); 71 | printf( "close fd %d\n", user_data->sockfd ); 72 | } 73 | 74 | int main( int argc, char* argv[] ) 75 | { 76 | if( argc <= 2 ) 77 | { 78 | printf( "usage: %s ip_address port_number\n", basename( argv[0] ) ); 79 | return 1; 80 | } 81 | const char* ip = argv[1]; 82 | int port = atoi( argv[2] ); 83 | 84 | int ret = 0; 85 | struct sockaddr_in address; 86 | bzero( &address, sizeof( address ) ); 87 | address.sin_family = AF_INET; 88 | inet_pton( AF_INET, ip, &address.sin_addr ); 89 | address.sin_port = htons( port ); 90 | 91 | int listenfd = socket( PF_INET, SOCK_STREAM, 0 ); 92 | assert( listenfd >= 0 ); 93 | 94 | ret = bind( listenfd, ( struct sockaddr* )&address, sizeof( address ) ); 95 | assert( ret != -1 ); 96 | 97 | ret = listen( listenfd, 5 ); 98 | assert( ret != -1 ); 99 | 100 | epoll_event events[ MAX_EVENT_NUMBER ]; 101 | int epollfd = epoll_create( 5 ); 102 | assert( epollfd != -1 ); 103 | addfd( epollfd, listenfd ); 104 | 105 | ret = socketpair( PF_UNIX, SOCK_STREAM, 0, pipefd ); 106 | assert( ret != -1 ); 107 | setnonblocking( pipefd[1] ); 108 | addfd( epollfd, pipefd[0] ); 109 | 110 | // add all the interesting signals here 111 | addsig( SIGALRM ); 112 | addsig( SIGTERM ); 113 | bool stop_server = false; 114 | 115 | client_data* users = new client_data[FD_LIMIT]; 116 | bool timeout = false; 117 | alarm( TIMESLOT ); 118 | 119 | while( !stop_server ) 120 | { 121 | int number = epoll_wait( epollfd, events, MAX_EVENT_NUMBER, -1 ); 122 | if ( ( number < 0 ) && ( errno != EINTR ) ) 123 | { 124 | printf( "epoll failure\n" ); 125 | break; 126 | } 127 | 128 | for ( int i = 0; i < number; i++ ) 129 | { 130 | int sockfd = events[i].data.fd; 131 | if( sockfd == listenfd ) 132 | { 133 | struct sockaddr_in client_address; 134 | socklen_t client_addrlength = sizeof( client_address ); 135 | int connfd = accept( listenfd, ( struct sockaddr* )&client_address, &client_addrlength ); 136 | addfd( epollfd, connfd ); 137 | users[connfd].address = client_address; 138 | users[connfd].sockfd = connfd; 139 | util_timer* timer = new util_timer; 140 | timer->user_data = &users[connfd]; 141 | timer->cb_func = cb_func; 142 | time_t cur = time( NULL ); 143 | timer->expire = cur + 3 * TIMESLOT; 144 | users[connfd].timer = timer; 145 | timer_lst.add_timer( timer ); 146 | } 147 | else if( ( sockfd == pipefd[0] ) && ( events[i].events & EPOLLIN ) ) 148 | { 149 | int sig; 150 | char signals[1024]; 151 | ret = recv( pipefd[0], signals, sizeof( signals ), 0 ); 152 | if( ret == -1 ) 153 | { 154 | // handle the error 155 | continue; 156 | } 157 | else if( ret == 0 ) 158 | { 159 | continue; 160 | } 161 | else 162 | { 163 | for( int i = 0; i < ret; ++i ) 164 | { 165 | switch( signals[i] ) 166 | { 167 | case SIGALRM: 168 | { 169 | timeout = true; 170 | break; 171 | } 172 | case SIGTERM: 173 | { 174 | stop_server = true; 175 | } 176 | } 177 | } 178 | } 179 | } 180 | else if( events[i].events & EPOLLIN ) 181 | { 182 | memset( users[sockfd].buf, '\0', BUFFER_SIZE ); 183 | ret = recv( sockfd, users[sockfd].buf, BUFFER_SIZE-1, 0 ); 184 | printf( "get %d bytes of client data %s from %d\n", ret, users[sockfd].buf, sockfd ); 185 | util_timer* timer = users[sockfd].timer; 186 | if( ret < 0 ) 187 | { 188 | if( errno != EAGAIN ) 189 | { 190 | cb_func( &users[sockfd] ); 191 | if( timer ) 192 | { 193 | timer_lst.del_timer( timer ); 194 | } 195 | } 196 | } 197 | else if( ret == 0 ) 198 | { 199 | cb_func( &users[sockfd] ); 200 | if( timer ) 201 | { 202 | timer_lst.del_timer( timer ); 203 | } 204 | } 205 | else 206 | { 207 | //send( sockfd, users[sockfd].buf, BUFFER_SIZE-1, 0 ); 208 | if( timer ) 209 | { 210 | time_t cur = time( NULL ); 211 | timer->expire = cur + 3 * TIMESLOT; 212 | printf( "adjust timer once\n" ); 213 | timer_lst.adjust_timer( timer ); 214 | } 215 | } 216 | } 217 | else 218 | { 219 | // others 220 | } 221 | } 222 | 223 | if( timeout ) 224 | { 225 | timer_handler(); 226 | timeout = false; 227 | } 228 | } 229 | 230 | close( listenfd ); 231 | close( pipefd[1] ); 232 | close( pipefd[0] ); 233 | delete [] users; 234 | return 0; 235 | } 236 | -------------------------------------------------------------------------------- /11/11-4io_timer.cpp: -------------------------------------------------------------------------------- 1 | #define TIMEOUT 5000 2 | 3 | int timeout = TIMEOUT; 4 | time_t start = time( NULL ); 5 | time_t end = time( NULL ); 6 | while( 1 ) 7 | { 8 | printf( "the timeout is now %d mill-seconds\n", timeout ); 9 | start = time( NULL ); 10 | int number = epoll_wait( epollfd, events, MAX_EVENT_NUMBER, timeout ); 11 | if( ( number < 0 ) && ( errno != EINTR ) ) 12 | { 13 | printf( "epoll failure\n" ); 14 | break; 15 | } 16 | if( number == 0 ) 17 | { 18 | // timeout 19 | timeout = TIMEOUT; 20 | continue; 21 | } 22 | 23 | end = time( NULL ); 24 | timeout -= ( end - start ) * 1000; 25 | if( timeout <= 0 ) 26 | { 27 | // timeout 28 | timeout = TIMEOUT; 29 | } 30 | 31 | // handle connections 32 | } 33 | -------------------------------------------------------------------------------- /11/11-5tw_timer.h: -------------------------------------------------------------------------------- 1 | #ifndef TIME_WHEEL_TIMER 2 | #define TIME_WHEEL_TIMER 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #define BUFFER_SIZE 64 9 | class tw_timer; 10 | struct client_data 11 | { 12 | sockaddr_in address; 13 | int sockfd; 14 | char buf[ BUFFER_SIZE ]; 15 | tw_timer* timer; 16 | }; 17 | 18 | class tw_timer 19 | { 20 | public: 21 | tw_timer( int rot, int ts ) 22 | : next( NULL ), prev( NULL ), rotation( rot ), time_slot( ts ){} 23 | 24 | public: 25 | int rotation; 26 | int time_slot; 27 | void (*cb_func)( client_data* ); 28 | client_data* user_data; 29 | tw_timer* next; 30 | tw_timer* prev; 31 | }; 32 | 33 | class time_wheel 34 | { 35 | public: 36 | time_wheel() : cur_slot( 0 ) 37 | { 38 | for( int i = 0; i < N; ++i ) 39 | { 40 | slots[i] = NULL; 41 | } 42 | } 43 | ~time_wheel() 44 | { 45 | for( int i = 0; i < N; ++i ) 46 | { 47 | tw_timer* tmp = slots[i]; 48 | while( tmp ) 49 | { 50 | slots[i] = tmp->next; 51 | delete tmp; 52 | tmp = slots[i]; 53 | } 54 | } 55 | } 56 | tw_timer* add_timer( int timeout ) 57 | { 58 | if( timeout < 0 ) 59 | { 60 | return NULL; 61 | } 62 | int ticks = 0; 63 | if( timeout < TI ) 64 | { 65 | ticks = 1; 66 | } 67 | else 68 | { 69 | ticks = timeout / TI; 70 | } 71 | int rotation = ticks / N; 72 | int ts = ( cur_slot + ( ticks % N ) ) % N; 73 | tw_timer* timer = new tw_timer( rotation, ts ); 74 | if( !slots[ts] ) 75 | { 76 | printf( "add timer, rotation is %d, ts is %d, cur_slot is %d\n", rotation, ts, cur_slot ); 77 | slots[ts] = timer; 78 | } 79 | else 80 | { 81 | timer->next = slots[ts]; 82 | slots[ts]->prev = timer; 83 | slots[ts] = timer; 84 | } 85 | return timer; 86 | } 87 | void del_timer( tw_timer* timer ) 88 | { 89 | if( !timer ) 90 | { 91 | return; 92 | } 93 | int ts = timer->time_slot; 94 | if( timer == slots[ts] ) 95 | { 96 | slots[ts] = slots[ts]->next; 97 | if( slots[ts] ) 98 | { 99 | slots[ts]->prev = NULL; 100 | } 101 | delete timer; 102 | } 103 | else 104 | { 105 | timer->prev->next = timer->next; 106 | if( timer->next ) 107 | { 108 | timer->next->prev = timer->prev; 109 | } 110 | delete timer; 111 | } 112 | } 113 | void tick() 114 | { 115 | tw_timer* tmp = slots[cur_slot]; 116 | printf( "current slot is %d\n", cur_slot ); 117 | while( tmp ) 118 | { 119 | printf( "tick the timer once\n" ); 120 | if( tmp->rotation > 0 ) 121 | { 122 | tmp->rotation--; 123 | tmp = tmp->next; 124 | } 125 | else 126 | { 127 | tmp->cb_func( tmp->user_data ); 128 | if( tmp == slots[cur_slot] ) 129 | { 130 | printf( "delete header in cur_slot\n" ); 131 | slots[cur_slot] = tmp->next; 132 | delete tmp; 133 | if( slots[cur_slot] ) 134 | { 135 | slots[cur_slot]->prev = NULL; 136 | } 137 | tmp = slots[cur_slot]; 138 | } 139 | else 140 | { 141 | tmp->prev->next = tmp->next; 142 | if( tmp->next ) 143 | { 144 | tmp->next->prev = tmp->prev; 145 | } 146 | tw_timer* tmp2 = tmp->next; 147 | delete tmp; 148 | tmp = tmp2; 149 | } 150 | } 151 | } 152 | cur_slot = ++cur_slot % N; 153 | } 154 | 155 | private: 156 | static const int N = 60; 157 | static const int TI = 1; 158 | tw_timer* slots[N]; 159 | int cur_slot; 160 | }; 161 | 162 | #endif 163 | -------------------------------------------------------------------------------- /11/11-6time_heap.h: -------------------------------------------------------------------------------- 1 | #ifndef intIME_HEAP 2 | #define intIME_HEAP 3 | 4 | #include 5 | #include 6 | #include 7 | using std::exception; 8 | 9 | #define BUFFER_SIZE 64 10 | 11 | class heap_timer; 12 | struct client_data 13 | { 14 | sockaddr_in address; 15 | int sockfd; 16 | char buf[ BUFFER_SIZE ]; 17 | heap_timer* timer; 18 | }; 19 | 20 | class heap_timer 21 | { 22 | public: 23 | heap_timer( int delay ) 24 | { 25 | expire = time( NULL ) + delay; 26 | } 27 | 28 | public: 29 | time_t expire; 30 | void (*cb_func)( client_data* ); 31 | client_data* user_data; 32 | }; 33 | 34 | class time_heap 35 | { 36 | public: 37 | time_heap( int cap ) throw ( std::exception ) 38 | : capacity( cap ), cur_size( 0 ) 39 | { 40 | array = new heap_timer* [capacity]; 41 | if ( ! array ) 42 | { 43 | throw std::exception(); 44 | } 45 | for( int i = 0; i < capacity; ++i ) 46 | { 47 | array[i] = NULL; 48 | } 49 | } 50 | time_heap( heap_timer** init_array, int size, int capacity ) throw ( std::exception ) 51 | : cur_size( size ), capacity( capacity ) 52 | { 53 | if ( capacity < size ) 54 | { 55 | throw std::exception(); 56 | } 57 | array = new heap_timer* [capacity]; 58 | if ( ! array ) 59 | { 60 | throw std::exception(); 61 | } 62 | for( int i = 0; i < capacity; ++i ) 63 | { 64 | array[i] = NULL; 65 | } 66 | if ( size != 0 ) 67 | { 68 | for ( int i = 0; i < size; ++i ) 69 | { 70 | array[ i ] = init_array[ i ]; 71 | } 72 | for ( int i = (cur_size-1)/2; i >=0; --i ) 73 | { 74 | percolate_down( i ); 75 | } 76 | } 77 | } 78 | ~time_heap() 79 | { 80 | for ( int i = 0; i < cur_size; ++i ) 81 | { 82 | delete array[i]; 83 | } 84 | delete [] array; 85 | } 86 | 87 | public: 88 | void add_timer( heap_timer* timer ) throw ( std::exception ) 89 | { 90 | if( !timer ) 91 | { 92 | return; 93 | } 94 | if( cur_size >= capacity ) 95 | { 96 | resize(); 97 | } 98 | int hole = cur_size++; 99 | int parent = 0; 100 | for( ; hole > 0; hole=parent ) 101 | { 102 | parent = (hole-1)/2; 103 | if ( array[parent]->expire <= timer->expire ) 104 | { 105 | break; 106 | } 107 | array[hole] = array[parent]; 108 | } 109 | array[hole] = timer; 110 | } 111 | void del_timer( heap_timer* timer ) 112 | { 113 | if( !timer ) 114 | { 115 | return; 116 | } 117 | // lazy delelte 118 | timer->cb_func = NULL; 119 | } 120 | heap_timer* top() const 121 | { 122 | if ( empty() ) 123 | { 124 | return NULL; 125 | } 126 | return array[0]; 127 | } 128 | void pop_timer() 129 | { 130 | if( empty() ) 131 | { 132 | return; 133 | } 134 | if( array[0] ) 135 | { 136 | delete array[0]; 137 | array[0] = array[--cur_size]; 138 | percolate_down( 0 ); 139 | } 140 | } 141 | void tick() 142 | { 143 | heap_timer* tmp = array[0]; 144 | time_t cur = time( NULL ); 145 | while( !empty() ) 146 | { 147 | if( !tmp ) 148 | { 149 | break; 150 | } 151 | if( tmp->expire > cur ) 152 | { 153 | break; 154 | } 155 | if( array[0]->cb_func ) 156 | { 157 | array[0]->cb_func( array[0]->user_data ); 158 | } 159 | pop_timer(); 160 | tmp = array[0]; 161 | } 162 | } 163 | bool empty() const { return cur_size == 0; } 164 | 165 | private: 166 | void percolate_down( int hole ) 167 | { 168 | heap_timer* temp = array[hole]; 169 | int child = 0; 170 | for ( ; ((hole*2+1) <= (cur_size-1)); hole=child ) 171 | { 172 | child = hole*2+1; 173 | if ( (child < (cur_size-1)) && (array[child+1]->expire < array[child]->expire ) ) 174 | { 175 | ++child; 176 | } 177 | if ( array[child]->expire < temp->expire ) 178 | { 179 | array[hole] = array[child]; 180 | } 181 | else 182 | { 183 | break; 184 | } 185 | } 186 | array[hole] = temp; 187 | } 188 | void resize() throw ( std::exception ) 189 | { 190 | heap_timer** temp = new heap_timer* [2*capacity]; 191 | for( int i = 0; i < 2*capacity; ++i ) 192 | { 193 | temp[i] = NULL; 194 | } 195 | if ( ! temp ) 196 | { 197 | throw std::exception(); 198 | } 199 | capacity = 2*capacity; 200 | for ( int i = 0; i < cur_size; ++i ) 201 | { 202 | temp[i] = array[i]; 203 | } 204 | delete [] array; 205 | array = temp; 206 | } 207 | 208 | private: 209 | heap_timer** array; 210 | int capacity; 211 | int cur_size; 212 | }; 213 | 214 | #endif 215 | -------------------------------------------------------------------------------- /12/12-1libevent_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void signal_cb( int fd, short event, void* argc ) 5 | { 6 | struct event_base* base = ( event_base* )argc; 7 | struct timeval delay = { 2, 0 }; 8 | printf( "Caught an interrupt signal; exiting cleanly in two seconds...\n" ); 9 | event_base_loopexit( base, &delay ); 10 | } 11 | 12 | void timeout_cb( int fd, short event, void* argc ) 13 | { 14 | printf( "timeout\n" ); 15 | } 16 | 17 | int main() 18 | { 19 | struct event_base* base = event_init(); 20 | 21 | struct event* signal_event = evsignal_new( base, SIGINT, signal_cb, base ); 22 | event_add( signal_event, NULL ); 23 | 24 | timeval tv = { 1, 0 }; 25 | struct event* timeout_event = evtimer_new( base, timeout_cb, NULL ); 26 | event_add( timeout_event, &tv ); 27 | 28 | event_base_dispatch( base ); 29 | 30 | event_free( timeout_event ); 31 | event_free( signal_event ); 32 | event_base_free( base ); 33 | } 34 | -------------------------------------------------------------------------------- /13/13-3sem.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | union semun 8 | { 9 | int val; 10 | struct semid_ds* buf; 11 | unsigned short int* array; 12 | struct seminfo* __buf; 13 | }; 14 | 15 | void pv( int sem_id, int op ) 16 | { 17 | struct sembuf sem_b; 18 | sem_b.sem_num = 0; 19 | sem_b.sem_op = op; 20 | sem_b.sem_flg = SEM_UNDO; 21 | semop( sem_id, &sem_b, 1 ); 22 | } 23 | 24 | int main( int argc, char* argv[] ) 25 | { 26 | int sem_id = semget( IPC_PRIVATE, 1, 0666 ); 27 | 28 | union semun sem_un; 29 | sem_un.val = 1; 30 | semctl( sem_id, 0, SETVAL, sem_un ); 31 | 32 | pid_t id = fork(); 33 | if( id < 0 ) 34 | { 35 | return 1; 36 | } 37 | else if( id == 0 ) 38 | { 39 | printf( "child try to get binary sem\n" ); 40 | pv( sem_id, -1 ); 41 | printf( "child get the sem and would release it after 5 seconds\n" ); 42 | sleep( 5 ); 43 | pv( sem_id, 1 ); 44 | exit( 0 ); 45 | } 46 | else 47 | { 48 | printf( "parent try to get binary sem\n" ); 49 | pv( sem_id, -1 ); 50 | printf( "parent get the sem and would release it after 5 seconds\n" ); 51 | sleep( 5 ); 52 | pv( sem_id, 1 ); 53 | } 54 | 55 | waitpid( id, NULL, 0 ); 56 | semctl( sem_id, 0, IPC_RMID, sem_un ); 57 | return 0; 58 | } 59 | -------------------------------------------------------------------------------- /13/13-4shm_talk_server.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #define USER_LIMIT 5 19 | #define BUFFER_SIZE 1024 20 | #define FD_LIMIT 65535 21 | #define MAX_EVENT_NUMBER 1024 22 | #define PROCESS_LIMIT 65536 23 | 24 | struct client_data 25 | { 26 | sockaddr_in address; 27 | int connfd; 28 | pid_t pid; 29 | int pipefd[2]; 30 | }; 31 | 32 | static const char* shm_name = "/my_shm"; 33 | int sig_pipefd[2]; 34 | int epollfd; 35 | int listenfd; 36 | int shmfd; 37 | char* share_mem = 0; 38 | client_data* users = 0; 39 | int* sub_process = 0; 40 | int user_count = 0; 41 | bool stop_child = false; 42 | 43 | int setnonblocking( int fd ) 44 | { 45 | int old_option = fcntl( fd, F_GETFL ); 46 | int new_option = old_option | O_NONBLOCK; 47 | fcntl( fd, F_SETFL, new_option ); 48 | return old_option; 49 | } 50 | 51 | void addfd( int epollfd, int fd ) 52 | { 53 | epoll_event event; 54 | event.data.fd = fd; 55 | event.events = EPOLLIN | EPOLLET; 56 | epoll_ctl( epollfd, EPOLL_CTL_ADD, fd, &event ); 57 | setnonblocking( fd ); 58 | } 59 | 60 | void sig_handler( int sig ) 61 | { 62 | int save_errno = errno; 63 | int msg = sig; 64 | send( sig_pipefd[1], ( char* )&msg, 1, 0 ); 65 | errno = save_errno; 66 | } 67 | 68 | void addsig( int sig, void(*handler)(int), bool restart = true ) 69 | { 70 | struct sigaction sa; 71 | memset( &sa, '\0', sizeof( sa ) ); 72 | sa.sa_handler = handler; 73 | if( restart ) 74 | { 75 | sa.sa_flags |= SA_RESTART; 76 | } 77 | sigfillset( &sa.sa_mask ); 78 | assert( sigaction( sig, &sa, NULL ) != -1 ); 79 | } 80 | 81 | void del_resource() 82 | { 83 | close( sig_pipefd[0] ); 84 | close( sig_pipefd[1] ); 85 | close( listenfd ); 86 | close( epollfd ); 87 | shm_unlink( shm_name ); 88 | delete [] users; 89 | delete [] sub_process; 90 | } 91 | 92 | void child_term_handler( int sig ) 93 | { 94 | stop_child = true; 95 | } 96 | 97 | int run_child( int idx, client_data* users, char* share_mem ) 98 | { 99 | epoll_event events[ MAX_EVENT_NUMBER ]; 100 | int child_epollfd = epoll_create( 5 ); 101 | assert( child_epollfd != -1 ); 102 | int connfd = users[idx].connfd; 103 | addfd( child_epollfd, connfd ); 104 | int pipefd = users[idx].pipefd[1]; 105 | addfd( child_epollfd, pipefd ); 106 | int ret; 107 | addsig( SIGTERM, child_term_handler, false ); 108 | 109 | while( !stop_child ) 110 | { 111 | int number = epoll_wait( child_epollfd, events, MAX_EVENT_NUMBER, -1 ); 112 | if ( ( number < 0 ) && ( errno != EINTR ) ) 113 | { 114 | printf( "epoll failure\n" ); 115 | break; 116 | } 117 | 118 | for ( int i = 0; i < number; i++ ) 119 | { 120 | int sockfd = events[i].data.fd; 121 | if( ( sockfd == connfd ) && ( events[i].events & EPOLLIN ) ) 122 | { 123 | memset( share_mem + idx*BUFFER_SIZE, '\0', BUFFER_SIZE ); 124 | ret = recv( connfd, share_mem + idx*BUFFER_SIZE, BUFFER_SIZE-1, 0 ); 125 | if( ret < 0 ) 126 | { 127 | if( errno != EAGAIN ) 128 | { 129 | stop_child = true; 130 | } 131 | } 132 | else if( ret == 0 ) 133 | { 134 | stop_child = true; 135 | } 136 | else 137 | { 138 | send( pipefd, ( char* )&idx, sizeof( idx ), 0 ); 139 | } 140 | } 141 | else if( ( sockfd == pipefd ) && ( events[i].events & EPOLLIN ) ) 142 | { 143 | int client = 0; 144 | ret = recv( sockfd, ( char* )&client, sizeof( client ), 0 ); 145 | if( ret < 0 ) 146 | { 147 | if( errno != EAGAIN ) 148 | { 149 | stop_child = true; 150 | } 151 | } 152 | else if( ret == 0 ) 153 | { 154 | stop_child = true; 155 | } 156 | else 157 | { 158 | send( connfd, share_mem + client * BUFFER_SIZE, BUFFER_SIZE, 0 ); 159 | } 160 | } 161 | else 162 | { 163 | continue; 164 | } 165 | } 166 | } 167 | 168 | close( connfd ); 169 | close( pipefd ); 170 | close( child_epollfd ); 171 | return 0; 172 | } 173 | 174 | int main( int argc, char* argv[] ) 175 | { 176 | if( argc <= 2 ) 177 | { 178 | printf( "usage: %s ip_address port_number\n", basename( argv[0] ) ); 179 | return 1; 180 | } 181 | const char* ip = argv[1]; 182 | int port = atoi( argv[2] ); 183 | 184 | int ret = 0; 185 | struct sockaddr_in address; 186 | bzero( &address, sizeof( address ) ); 187 | address.sin_family = AF_INET; 188 | inet_pton( AF_INET, ip, &address.sin_addr ); 189 | address.sin_port = htons( port ); 190 | 191 | listenfd = socket( PF_INET, SOCK_STREAM, 0 ); 192 | assert( listenfd >= 0 ); 193 | 194 | ret = bind( listenfd, ( struct sockaddr* )&address, sizeof( address ) ); 195 | assert( ret != -1 ); 196 | 197 | ret = listen( listenfd, 5 ); 198 | assert( ret != -1 ); 199 | 200 | user_count = 0; 201 | users = new client_data [ USER_LIMIT+1 ]; 202 | sub_process = new int [ PROCESS_LIMIT ]; 203 | for( int i = 0; i < PROCESS_LIMIT; ++i ) 204 | { 205 | sub_process[i] = -1; 206 | } 207 | 208 | epoll_event events[ MAX_EVENT_NUMBER ]; 209 | epollfd = epoll_create( 5 ); 210 | assert( epollfd != -1 ); 211 | addfd( epollfd, listenfd ); 212 | 213 | ret = socketpair( PF_UNIX, SOCK_STREAM, 0, sig_pipefd ); 214 | assert( ret != -1 ); 215 | setnonblocking( sig_pipefd[1] ); 216 | addfd( epollfd, sig_pipefd[0] ); 217 | 218 | addsig( SIGCHLD, sig_handler ); 219 | addsig( SIGTERM, sig_handler ); 220 | addsig( SIGINT, sig_handler ); 221 | addsig( SIGPIPE, SIG_IGN ); 222 | bool stop_server = false; 223 | bool terminate = false; 224 | 225 | shmfd = shm_open( shm_name, O_CREAT | O_RDWR, 0666 ); 226 | assert( shmfd != -1 ); 227 | ret = ftruncate( shmfd, USER_LIMIT * BUFFER_SIZE ); 228 | assert( ret != -1 ); 229 | 230 | share_mem = (char*)mmap( NULL, USER_LIMIT * BUFFER_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shmfd, 0 ); 231 | assert( share_mem != MAP_FAILED ); 232 | close( shmfd ); 233 | 234 | while( !stop_server ) 235 | { 236 | int number = epoll_wait( epollfd, events, MAX_EVENT_NUMBER, -1 ); 237 | if ( ( number < 0 ) && ( errno != EINTR ) ) 238 | { 239 | printf( "epoll failure\n" ); 240 | break; 241 | } 242 | 243 | for ( int i = 0; i < number; i++ ) 244 | { 245 | int sockfd = events[i].data.fd; 246 | if( sockfd == listenfd ) 247 | { 248 | struct sockaddr_in client_address; 249 | socklen_t client_addrlength = sizeof( client_address ); 250 | int connfd = accept( listenfd, ( struct sockaddr* )&client_address, &client_addrlength ); 251 | if ( connfd < 0 ) 252 | { 253 | printf( "errno is: %d\n", errno ); 254 | continue; 255 | } 256 | if( user_count >= USER_LIMIT ) 257 | { 258 | const char* info = "too many users\n"; 259 | printf( "%s", info ); 260 | send( connfd, info, strlen( info ), 0 ); 261 | close( connfd ); 262 | continue; 263 | } 264 | users[user_count].address = client_address; 265 | users[user_count].connfd = connfd; 266 | ret = socketpair( PF_UNIX, SOCK_STREAM, 0, users[user_count].pipefd ); 267 | assert( ret != -1 ); 268 | pid_t pid = fork(); 269 | if( pid < 0 ) 270 | { 271 | close( connfd ); 272 | continue; 273 | } 274 | else if( pid == 0 ) 275 | { 276 | close( epollfd ); 277 | close( listenfd ); 278 | close( users[user_count].pipefd[0] ); 279 | close( sig_pipefd[0] ); 280 | close( sig_pipefd[1] ); 281 | run_child( user_count, users, share_mem ); 282 | munmap( (void*)share_mem, USER_LIMIT * BUFFER_SIZE ); 283 | exit( 0 ); 284 | } 285 | else 286 | { 287 | close( connfd ); 288 | close( users[user_count].pipefd[1] ); 289 | addfd( epollfd, users[user_count].pipefd[0] ); 290 | users[user_count].pid = pid; 291 | sub_process[pid] = user_count; 292 | user_count++; 293 | } 294 | } 295 | else if( ( sockfd == sig_pipefd[0] ) && ( events[i].events & EPOLLIN ) ) 296 | { 297 | int sig; 298 | char signals[1024]; 299 | ret = recv( sig_pipefd[0], signals, sizeof( signals ), 0 ); 300 | if( ret == -1 ) 301 | { 302 | continue; 303 | } 304 | else if( ret == 0 ) 305 | { 306 | continue; 307 | } 308 | else 309 | { 310 | for( int i = 0; i < ret; ++i ) 311 | { 312 | switch( signals[i] ) 313 | { 314 | case SIGCHLD: 315 | { 316 | pid_t pid; 317 | int stat; 318 | while ( ( pid = waitpid( -1, &stat, WNOHANG ) ) > 0 ) 319 | { 320 | int del_user = sub_process[pid]; 321 | sub_process[pid] = -1; 322 | if( ( del_user < 0 ) || ( del_user > USER_LIMIT ) ) 323 | { 324 | printf( "the deleted user was not change\n" ); 325 | continue; 326 | } 327 | epoll_ctl( epollfd, EPOLL_CTL_DEL, users[del_user].pipefd[0], 0 ); 328 | close( users[del_user].pipefd[0] ); 329 | users[del_user] = users[--user_count]; 330 | sub_process[users[del_user].pid] = del_user; 331 | printf( "child %d exit, now we have %d users\n", del_user, user_count ); 332 | } 333 | if( terminate && user_count == 0 ) 334 | { 335 | stop_server = true; 336 | } 337 | break; 338 | } 339 | case SIGTERM: 340 | case SIGINT: 341 | { 342 | printf( "kill all the clild now\n" ); 343 | //addsig( SIGTERM, SIG_IGN ); 344 | //addsig( SIGINT, SIG_IGN ); 345 | if( user_count == 0 ) 346 | { 347 | stop_server = true; 348 | break; 349 | } 350 | for( int i = 0; i < user_count; ++i ) 351 | { 352 | int pid = users[i].pid; 353 | kill( pid, SIGTERM ); 354 | } 355 | terminate = true; 356 | break; 357 | } 358 | default: 359 | { 360 | break; 361 | } 362 | } 363 | } 364 | } 365 | } 366 | else if( events[i].events & EPOLLIN ) 367 | { 368 | int child = 0; 369 | ret = recv( sockfd, ( char* )&child, sizeof( child ), 0 ); 370 | printf( "read data from child accross pipe\n" ); 371 | if( ret == -1 ) 372 | { 373 | continue; 374 | } 375 | else if( ret == 0 ) 376 | { 377 | continue; 378 | } 379 | else 380 | { 381 | for( int j = 0; j < user_count; ++j ) 382 | { 383 | if( users[j].pipefd[0] != sockfd ) 384 | { 385 | printf( "send data to child accross pipe\n" ); 386 | send( users[j].pipefd[0], ( char* )&child, sizeof( child ), 0 ); 387 | } 388 | } 389 | } 390 | } 391 | } 392 | } 393 | 394 | del_resource(); 395 | return 0; 396 | } 397 | -------------------------------------------------------------------------------- /13/13-5passfd.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | static const int CONTROL_LEN = CMSG_LEN( sizeof(int) ); 10 | 11 | void send_fd( int fd, int fd_to_send ) 12 | { 13 | struct iovec iov[1]; 14 | struct msghdr msg; 15 | char buf[0]; 16 | 17 | iov[0].iov_base = buf; 18 | iov[0].iov_len = 1; 19 | msg.msg_name = NULL; 20 | msg.msg_namelen = 0; 21 | msg.msg_iov = iov; 22 | msg.msg_iovlen = 1; 23 | 24 | cmsghdr cm; 25 | cm.cmsg_len = CONTROL_LEN; 26 | cm.cmsg_level = SOL_SOCKET; 27 | cm.cmsg_type = SCM_RIGHTS; 28 | *(int *)CMSG_DATA( &cm ) = fd_to_send; 29 | msg.msg_control = &cm; 30 | msg.msg_controllen = CONTROL_LEN; 31 | 32 | sendmsg( fd, &msg, 0 ); 33 | } 34 | 35 | int recv_fd( int fd ) 36 | { 37 | struct iovec iov[1]; 38 | struct msghdr msg; 39 | char buf[0]; 40 | 41 | iov[0].iov_base = buf; 42 | iov[0].iov_len = 1; 43 | msg.msg_name = NULL; 44 | msg.msg_namelen = 0; 45 | msg.msg_iov = iov; 46 | msg.msg_iovlen = 1; 47 | 48 | cmsghdr cm; 49 | msg.msg_control = &cm; 50 | msg.msg_controllen = CONTROL_LEN; 51 | 52 | recvmsg( fd, &msg, 0 ); 53 | 54 | int fd_to_read = *(int *)CMSG_DATA( &cm ); 55 | return fd_to_read; 56 | } 57 | 58 | int main() 59 | { 60 | int pipefd[2]; 61 | int fd_to_pass = 0; 62 | 63 | int ret = socketpair( PF_UNIX, SOCK_DGRAM, 0, pipefd ); 64 | assert( ret != -1 ); 65 | 66 | pid_t pid = fork(); 67 | assert( pid >= 0 ); 68 | 69 | if ( pid == 0 ) 70 | { 71 | close( pipefd[0] ); 72 | fd_to_pass = open( "test.txt", O_RDWR, 0666 ); 73 | send_fd( pipefd[1], ( fd_to_pass > 0 ) ? fd_to_pass : 0 ); 74 | close( fd_to_pass ); 75 | exit( 0 ); 76 | } 77 | 78 | close( pipefd[1] ); 79 | fd_to_pass = recv_fd( pipefd[0] ); 80 | char buf[1024]; 81 | memset( buf, '\0', 1024 ); 82 | read( fd_to_pass, buf, 1024 ); 83 | printf( "I got fd %d and data %s\n", fd_to_pass, buf ); 84 | close( fd_to_pass ); 85 | } 86 | -------------------------------------------------------------------------------- /14/14-1mutual_lock.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int a = 0; 6 | int b = 0; 7 | pthread_mutex_t mutex_a; 8 | pthread_mutex_t mutex_b; 9 | 10 | void* another( void* arg ) 11 | { 12 | pthread_mutex_lock( &mutex_b ); 13 | printf( "in child thread, got mutex b, waiting for mutex a\n" ); 14 | sleep( 5 ); 15 | ++b; 16 | pthread_mutex_lock( &mutex_a ); 17 | b += a++; 18 | pthread_mutex_unlock( &mutex_a ); 19 | pthread_mutex_unlock( &mutex_b ); 20 | pthread_exit( NULL ); 21 | } 22 | 23 | int main() 24 | { 25 | pthread_t id; 26 | 27 | pthread_mutex_init( &mutex_a, NULL ); 28 | pthread_mutex_init( &mutex_b, NULL ); 29 | pthread_create( &id, NULL, another, NULL ); 30 | 31 | pthread_mutex_lock( &mutex_a ); 32 | printf( "in parent thread, got mutex a, waiting for mutex b\n" ); 33 | sleep( 5 ); 34 | ++a; 35 | pthread_mutex_lock( &mutex_b ); 36 | a += b++; 37 | pthread_mutex_unlock( &mutex_b ); 38 | pthread_mutex_unlock( &mutex_a ); 39 | 40 | pthread_join( id, NULL ); 41 | pthread_mutex_destroy( &mutex_a ); 42 | pthread_mutex_destroy( &mutex_b ); 43 | return 0; 44 | } 45 | -------------------------------------------------------------------------------- /14/14-2locker.h: -------------------------------------------------------------------------------- 1 | #ifndef LOCKER_H 2 | #define LOCKER_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | class sem 9 | { 10 | public: 11 | sem() 12 | { 13 | if( sem_init( &m_sem, 0, 0 ) != 0 ) 14 | { 15 | throw std::exception(); 16 | } 17 | } 18 | ~sem() 19 | { 20 | sem_destroy( &m_sem ); 21 | } 22 | bool wait() 23 | { 24 | return sem_wait( &m_sem ) == 0; 25 | } 26 | bool post() 27 | { 28 | return sem_post( &m_sem ) == 0; 29 | } 30 | 31 | private: 32 | sem_t m_sem; 33 | }; 34 | 35 | class locker 36 | { 37 | public: 38 | locker() 39 | { 40 | if( pthread_mutex_init( &m_mutex, NULL ) != 0 ) 41 | { 42 | throw std::exception(); 43 | } 44 | } 45 | ~locker() 46 | { 47 | pthread_mutex_destroy( &m_mutex ); 48 | } 49 | bool lock() 50 | { 51 | return pthread_mutex_lock( &m_mutex ) == 0; 52 | } 53 | bool unlock() 54 | { 55 | return pthread_mutex_unlock( &m_mutex ) == 0; 56 | } 57 | 58 | private: 59 | pthread_mutex_t m_mutex; 60 | }; 61 | 62 | class cond 63 | { 64 | public: 65 | cond() 66 | { 67 | if( pthread_mutex_init( &m_mutex, NULL ) != 0 ) 68 | { 69 | throw std::exception(); 70 | } 71 | if ( pthread_cond_init( &m_cond, NULL ) != 0 ) 72 | { 73 | pthread_mutex_destroy( &m_mutex ); 74 | throw std::exception(); 75 | } 76 | } 77 | ~cond() 78 | { 79 | pthread_mutex_destroy( &m_mutex ); 80 | pthread_cond_destroy( &m_cond ); 81 | } 82 | bool wait() 83 | { 84 | int ret = 0; 85 | pthread_mutex_lock( &m_mutex ); 86 | ret = pthread_cond_wait( &m_cond, &m_mutex ); 87 | pthread_mutex_unlock( &m_mutex ); 88 | return ret == 0; 89 | } 90 | bool signal() 91 | { 92 | return pthread_cond_signal( &m_cond ) == 0; 93 | } 94 | 95 | private: 96 | pthread_mutex_t m_mutex; 97 | pthread_cond_t m_cond; 98 | }; 99 | 100 | #endif 101 | -------------------------------------------------------------------------------- /14/14-3thread_atfork.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | pthread_mutex_t mutex; 8 | 9 | void* another( void* arg ) 10 | { 11 | printf( "in child thread, lock the mutex\n" ); 12 | pthread_mutex_lock( &mutex ); 13 | sleep( 5 ); 14 | pthread_mutex_unlock( &mutex ); 15 | } 16 | 17 | void prepare() 18 | { 19 | pthread_mutex_lock( &mutex ); 20 | } 21 | 22 | void infork() 23 | { 24 | pthread_mutex_unlock( &mutex ); 25 | } 26 | 27 | int main() 28 | { 29 | pthread_mutex_init( &mutex, NULL ); 30 | pthread_t id; 31 | pthread_create( &id, NULL, another, NULL ); 32 | //pthread_atfork( prepare, infork, infork ); 33 | sleep( 1 ); 34 | int pid = fork(); 35 | if( pid < 0 ) 36 | { 37 | pthread_join( id, NULL ); 38 | pthread_mutex_destroy( &mutex ); 39 | return 1; 40 | } 41 | else if( pid == 0 ) 42 | { 43 | printf( "I anm in the child, want to get the lock\n" ); 44 | pthread_mutex_lock( &mutex ); 45 | printf( "I can not run to here, oop...\n" ); 46 | pthread_mutex_unlock( &mutex ); 47 | exit( 0 ); 48 | } 49 | else 50 | { 51 | pthread_mutex_unlock( &mutex ); 52 | wait( NULL ); 53 | } 54 | pthread_join( id, NULL ); 55 | pthread_mutex_destroy( &mutex ); 56 | return 0; 57 | } 58 | -------------------------------------------------------------------------------- /14/14-5sigmask.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | /* Simple error handling functions */ 9 | 10 | #define handle_error_en(en, msg) \ 11 | do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0) 12 | 13 | static void * 14 | sig_thread(void *arg) 15 | { 16 | printf( "yyyyy, thread id is: %ld\n", pthread_self() ); 17 | sigset_t aset; 18 | int s, sig; 19 | sigemptyset(&aset); 20 | sigaddset(&aset, SIGQUIT); 21 | sigaddset(&aset, SIGUSR1); 22 | //s = pthread_sigmask(SIG_BLOCK, &aset, NULL); 23 | sigset_t *set = (sigset_t *) arg; 24 | 25 | for (;;) { 26 | s = sigwait(set, &sig); 27 | if (s != 0) 28 | handle_error_en(s, "sigwait"); 29 | printf("Signal handling thread got signal %d\n", sig); 30 | } 31 | } 32 | 33 | static void handler( int arg ) 34 | { 35 | printf( "xxxxx, thread id is: %ld\n", pthread_self() ); 36 | } 37 | 38 | int 39 | main(int argc, char *argv[]) 40 | { 41 | pthread_t thread; 42 | sigset_t set; 43 | int s; 44 | 45 | /* Block SIGINT; other threads created by main() will inherit 46 | * a copy of the signal mask. */ 47 | 48 | signal( SIGQUIT, handler ); 49 | // if (s != 0) 50 | // handle_error_en(s, "pthread_sigmask"); 51 | 52 | s = pthread_create(&thread, NULL, &sig_thread, (void *) &set); 53 | sigemptyset(&set); 54 | sigaddset(&set, SIGQUIT); 55 | sigaddset(&set, SIGUSR1); 56 | //s = pthread_sigmask(SIG_BLOCK, &set, NULL); 57 | if (s != 0) 58 | handle_error_en(s, "pthread_create"); 59 | printf( "sub thread with id: %ld\n", thread ); 60 | /* Main thread carries on to create other threads and/or do 61 | * other work */ 62 | 63 | pause(); /* Dummy pause so we can test program */ 64 | } 65 | 66 | -------------------------------------------------------------------------------- /15/15-1processpool.h: -------------------------------------------------------------------------------- 1 | #ifndef PROCESSPOOL_H 2 | #define PROCESSPOOL_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | class process 21 | { 22 | public: 23 | process() : m_pid( -1 ){} 24 | 25 | public: 26 | pid_t m_pid; 27 | int m_pipefd[2]; 28 | }; 29 | 30 | template< typename T > 31 | class processpool 32 | { 33 | private: 34 | processpool( int listenfd, int process_number = 8 ); 35 | public: 36 | static processpool< T >* create( int listenfd, int process_number = 8 ) 37 | { 38 | if( !m_instance ) 39 | { 40 | m_instance = new processpool< T >( listenfd, process_number ); 41 | } 42 | return m_instance; 43 | } 44 | ~processpool() 45 | { 46 | delete [] m_sub_process; 47 | } 48 | void run(); 49 | 50 | private: 51 | void setup_sig_pipe(); 52 | void run_parent(); 53 | void run_child(); 54 | 55 | private: 56 | static const int MAX_PROCESS_NUMBER = 16; 57 | static const int USER_PER_PROCESS = 65536; 58 | static const int MAX_EVENT_NUMBER = 10000; 59 | int m_process_number; 60 | int m_idx; 61 | int m_epollfd; 62 | int m_listenfd; 63 | int m_stop; 64 | process* m_sub_process; 65 | static processpool< T >* m_instance; 66 | }; 67 | template< typename T > 68 | processpool< T >* processpool< T >::m_instance = NULL; 69 | 70 | static int sig_pipefd[2]; 71 | 72 | static int setnonblocking( int fd ) 73 | { 74 | int old_option = fcntl( fd, F_GETFL ); 75 | int new_option = old_option | O_NONBLOCK; 76 | fcntl( fd, F_SETFL, new_option ); 77 | return old_option; 78 | } 79 | 80 | static void addfd( int epollfd, int fd ) 81 | { 82 | epoll_event event; 83 | event.data.fd = fd; 84 | event.events = EPOLLIN | EPOLLET; 85 | epoll_ctl( epollfd, EPOLL_CTL_ADD, fd, &event ); 86 | setnonblocking( fd ); 87 | } 88 | 89 | static void removefd( int epollfd, int fd ) 90 | { 91 | epoll_ctl( epollfd, EPOLL_CTL_DEL, fd, 0 ); 92 | close( fd ); 93 | } 94 | 95 | static void sig_handler( int sig ) 96 | { 97 | int save_errno = errno; 98 | int msg = sig; 99 | send( sig_pipefd[1], ( char* )&msg, 1, 0 ); 100 | errno = save_errno; 101 | } 102 | 103 | static void addsig( int sig, void( handler )(int), bool restart = true ) 104 | { 105 | struct sigaction sa; 106 | memset( &sa, '\0', sizeof( sa ) ); 107 | sa.sa_handler = handler; 108 | if( restart ) 109 | { 110 | sa.sa_flags |= SA_RESTART; 111 | } 112 | sigfillset( &sa.sa_mask ); 113 | assert( sigaction( sig, &sa, NULL ) != -1 ); 114 | } 115 | 116 | template< typename T > 117 | processpool< T >::processpool( int listenfd, int process_number ) 118 | : m_listenfd( listenfd ), m_process_number( process_number ), m_idx( -1 ), m_stop( false ) 119 | { 120 | assert( ( process_number > 0 ) && ( process_number <= MAX_PROCESS_NUMBER ) ); 121 | 122 | m_sub_process = new process[ process_number ]; 123 | assert( m_sub_process ); 124 | 125 | for( int i = 0; i < process_number; ++i ) 126 | { 127 | int ret = socketpair( PF_UNIX, SOCK_STREAM, 0, m_sub_process[i].m_pipefd ); 128 | assert( ret == 0 ); 129 | 130 | m_sub_process[i].m_pid = fork(); 131 | assert( m_sub_process[i].m_pid >= 0 ); 132 | if( m_sub_process[i].m_pid > 0 ) 133 | { 134 | close( m_sub_process[i].m_pipefd[1] ); 135 | continue; 136 | } 137 | else 138 | { 139 | close( m_sub_process[i].m_pipefd[0] ); 140 | m_idx = i; 141 | break; 142 | } 143 | } 144 | } 145 | 146 | template< typename T > 147 | void processpool< T >::setup_sig_pipe() 148 | { 149 | m_epollfd = epoll_create( 5 ); 150 | assert( m_epollfd != -1 ); 151 | 152 | int ret = socketpair( PF_UNIX, SOCK_STREAM, 0, sig_pipefd ); 153 | assert( ret != -1 ); 154 | 155 | setnonblocking( sig_pipefd[1] ); 156 | addfd( m_epollfd, sig_pipefd[0] ); 157 | 158 | addsig( SIGCHLD, sig_handler ); 159 | addsig( SIGTERM, sig_handler ); 160 | addsig( SIGINT, sig_handler ); 161 | addsig( SIGPIPE, SIG_IGN ); 162 | } 163 | 164 | template< typename T > 165 | void processpool< T >::run() 166 | { 167 | if( m_idx != -1 ) 168 | { 169 | run_child(); 170 | return; 171 | } 172 | run_parent(); 173 | } 174 | 175 | template< typename T > 176 | void processpool< T >::run_child() 177 | { 178 | setup_sig_pipe(); 179 | 180 | int pipefd = m_sub_process[m_idx].m_pipefd[ 1 ]; 181 | addfd( m_epollfd, pipefd ); 182 | 183 | epoll_event events[ MAX_EVENT_NUMBER ]; 184 | T* users = new T [ USER_PER_PROCESS ]; 185 | assert( users ); 186 | int number = 0; 187 | int ret = -1; 188 | 189 | while( ! m_stop ) 190 | { 191 | number = epoll_wait( m_epollfd, events, MAX_EVENT_NUMBER, -1 ); 192 | if ( ( number < 0 ) && ( errno != EINTR ) ) 193 | { 194 | printf( "epoll failure\n" ); 195 | break; 196 | } 197 | 198 | for ( int i = 0; i < number; i++ ) 199 | { 200 | int sockfd = events[i].data.fd; 201 | if( ( sockfd == pipefd ) && ( events[i].events & EPOLLIN ) ) 202 | { 203 | int client = 0; 204 | ret = recv( sockfd, ( char* )&client, sizeof( client ), 0 ); 205 | if( ( ( ret < 0 ) && ( errno != EAGAIN ) ) || ret == 0 ) 206 | { 207 | continue; 208 | } 209 | else 210 | { 211 | struct sockaddr_in client_address; 212 | socklen_t client_addrlength = sizeof( client_address ); 213 | int connfd = accept( m_listenfd, ( struct sockaddr* )&client_address, &client_addrlength ); 214 | if ( connfd < 0 ) 215 | { 216 | printf( "errno is: %d\n", errno ); 217 | continue; 218 | } 219 | addfd( m_epollfd, connfd ); 220 | users[connfd].init( m_epollfd, connfd, client_address ); 221 | } 222 | } 223 | else if( ( sockfd == sig_pipefd[0] ) && ( events[i].events & EPOLLIN ) ) 224 | { 225 | int sig; 226 | char signals[1024]; 227 | ret = recv( sig_pipefd[0], signals, sizeof( signals ), 0 ); 228 | if( ret <= 0 ) 229 | { 230 | continue; 231 | } 232 | else 233 | { 234 | for( int i = 0; i < ret; ++i ) 235 | { 236 | switch( signals[i] ) 237 | { 238 | case SIGCHLD: 239 | { 240 | pid_t pid; 241 | int stat; 242 | while ( ( pid = waitpid( -1, &stat, WNOHANG ) ) > 0 ) 243 | { 244 | continue; 245 | } 246 | break; 247 | } 248 | case SIGTERM: 249 | case SIGINT: 250 | { 251 | m_stop = true; 252 | break; 253 | } 254 | default: 255 | { 256 | break; 257 | } 258 | } 259 | } 260 | } 261 | } 262 | else if( events[i].events & EPOLLIN ) 263 | { 264 | users[sockfd].process(); 265 | } 266 | else 267 | { 268 | continue; 269 | } 270 | } 271 | } 272 | 273 | delete [] users; 274 | users = NULL; 275 | close( pipefd ); 276 | //close( m_listenfd ); 277 | close( m_epollfd ); 278 | } 279 | 280 | template< typename T > 281 | void processpool< T >::run_parent() 282 | { 283 | setup_sig_pipe(); 284 | 285 | addfd( m_epollfd, m_listenfd ); 286 | 287 | epoll_event events[ MAX_EVENT_NUMBER ]; 288 | int sub_process_counter = 0; 289 | int new_conn = 1; 290 | int number = 0; 291 | int ret = -1; 292 | 293 | while( ! m_stop ) 294 | { 295 | number = epoll_wait( m_epollfd, events, MAX_EVENT_NUMBER, -1 ); 296 | if ( ( number < 0 ) && ( errno != EINTR ) ) 297 | { 298 | printf( "epoll failure\n" ); 299 | break; 300 | } 301 | 302 | for ( int i = 0; i < number; i++ ) 303 | { 304 | int sockfd = events[i].data.fd; 305 | if( sockfd == m_listenfd ) 306 | { 307 | int i = sub_process_counter; 308 | do 309 | { 310 | if( m_sub_process[i].m_pid != -1 ) 311 | { 312 | break; 313 | } 314 | i = (i+1)%m_process_number; 315 | } 316 | while( i != sub_process_counter ); 317 | 318 | if( m_sub_process[i].m_pid == -1 ) 319 | { 320 | m_stop = true; 321 | break; 322 | } 323 | sub_process_counter = (i+1)%m_process_number; 324 | //send( m_sub_process[sub_process_counter++].m_pipefd[0], ( char* )&new_conn, sizeof( new_conn ), 0 ); 325 | send( m_sub_process[i].m_pipefd[0], ( char* )&new_conn, sizeof( new_conn ), 0 ); 326 | printf( "send request to child %d\n", i ); 327 | //sub_process_counter %= m_process_number; 328 | } 329 | else if( ( sockfd == sig_pipefd[0] ) && ( events[i].events & EPOLLIN ) ) 330 | { 331 | int sig; 332 | char signals[1024]; 333 | ret = recv( sig_pipefd[0], signals, sizeof( signals ), 0 ); 334 | if( ret <= 0 ) 335 | { 336 | continue; 337 | } 338 | else 339 | { 340 | for( int i = 0; i < ret; ++i ) 341 | { 342 | switch( signals[i] ) 343 | { 344 | case SIGCHLD: 345 | { 346 | pid_t pid; 347 | int stat; 348 | while ( ( pid = waitpid( -1, &stat, WNOHANG ) ) > 0 ) 349 | { 350 | for( int i = 0; i < m_process_number; ++i ) 351 | { 352 | if( m_sub_process[i].m_pid == pid ) 353 | { 354 | printf( "child %d join\n", i ); 355 | close( m_sub_process[i].m_pipefd[0] ); 356 | m_sub_process[i].m_pid = -1; 357 | } 358 | } 359 | } 360 | m_stop = true; 361 | for( int i = 0; i < m_process_number; ++i ) 362 | { 363 | if( m_sub_process[i].m_pid != -1 ) 364 | { 365 | m_stop = false; 366 | } 367 | } 368 | break; 369 | } 370 | case SIGTERM: 371 | case SIGINT: 372 | { 373 | printf( "kill all the clild now\n" ); 374 | for( int i = 0; i < m_process_number; ++i ) 375 | { 376 | int pid = m_sub_process[i].m_pid; 377 | if( pid != -1 ) 378 | { 379 | kill( pid, SIGTERM ); 380 | } 381 | } 382 | break; 383 | } 384 | default: 385 | { 386 | break; 387 | } 388 | } 389 | } 390 | } 391 | } 392 | else 393 | { 394 | continue; 395 | } 396 | } 397 | } 398 | 399 | //close( m_listenfd ); 400 | close( m_epollfd ); 401 | } 402 | 403 | #endif 404 | -------------------------------------------------------------------------------- /15/15-2pool_cgi.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #define BUFFER_SIZE 1024 20 | #define MAX_EVENT_NUMBER 1024 21 | #define PROCESS_COUNT 5 22 | #define USER_PER_PROCESS 65535 23 | 24 | struct process_in_pool 25 | { 26 | pid_t pid; 27 | int pipefd[2]; 28 | }; 29 | 30 | struct client_data 31 | { 32 | sockaddr_in address; 33 | char buf[ BUFFER_SIZE ]; 34 | int read_idx; 35 | }; 36 | 37 | int sig_pipefd[2]; 38 | int epollfd; 39 | int listenfd; 40 | process_in_pool sub_process[ PROCESS_COUNT ]; 41 | bool stop_child = false; 42 | 43 | int setnonblocking( int fd ) 44 | { 45 | int old_option = fcntl( fd, F_GETFL ); 46 | int new_option = old_option | O_NONBLOCK; 47 | fcntl( fd, F_SETFL, new_option ); 48 | return old_option; 49 | } 50 | 51 | void addfd( int epollfd, int fd ) 52 | { 53 | epoll_event event; 54 | event.data.fd = fd; 55 | event.events = EPOLLIN | EPOLLET; 56 | epoll_ctl( epollfd, EPOLL_CTL_ADD, fd, &event ); 57 | setnonblocking( fd ); 58 | } 59 | 60 | void sig_handler( int sig ) 61 | { 62 | int save_errno = errno; 63 | int msg = sig; 64 | send( sig_pipefd[1], ( char* )&msg, 1, 0 ); 65 | errno = save_errno; 66 | } 67 | 68 | void addsig( int sig, void(*handler)(int), bool restart = true ) 69 | { 70 | struct sigaction sa; 71 | memset( &sa, '\0', sizeof( sa ) ); 72 | sa.sa_handler = handler; 73 | if( restart ) 74 | { 75 | sa.sa_flags |= SA_RESTART; 76 | } 77 | sigfillset( &sa.sa_mask ); 78 | assert( sigaction( sig, &sa, NULL ) != -1 ); 79 | } 80 | 81 | void del_resource() 82 | { 83 | close( sig_pipefd[0] ); 84 | close( sig_pipefd[1] ); 85 | close( listenfd ); 86 | close( epollfd ); 87 | } 88 | 89 | void child_term_handler( int sig ) 90 | { 91 | stop_child = true; 92 | } 93 | 94 | void child_child_handler( int sig ) 95 | { 96 | pid_t pid; 97 | int stat; 98 | while ( ( pid = waitpid( -1, &stat, WNOHANG ) ) > 0 ) 99 | { 100 | continue; 101 | } 102 | } 103 | 104 | int run_child( int idx ) 105 | { 106 | epoll_event events[ MAX_EVENT_NUMBER ]; 107 | int child_epollfd = epoll_create( 5 ); 108 | assert( child_epollfd != -1 ); 109 | int pipefd = sub_process[idx].pipefd[1]; 110 | addfd( child_epollfd, pipefd ); 111 | int ret; 112 | addsig( SIGTERM, child_term_handler, false ); 113 | addsig( SIGCHLD, child_child_handler ); 114 | client_data* users = new client_data[ USER_PER_PROCESS ]; 115 | 116 | while( !stop_child ) 117 | { 118 | int number = epoll_wait( child_epollfd, events, MAX_EVENT_NUMBER, -1 ); 119 | if ( ( number < 0 ) && ( errno != EINTR ) ) 120 | { 121 | printf( "epoll failure\n" ); 122 | break; 123 | } 124 | 125 | for ( int i = 0; i < number; i++ ) 126 | { 127 | int sockfd = events[i].data.fd; 128 | if( ( sockfd == pipefd ) && ( events[i].events & EPOLLIN ) ) 129 | { 130 | int client = 0; 131 | ret = recv( sockfd, ( char* )&client, sizeof( client ), 0 ); 132 | if( ret < 0 ) 133 | { 134 | if( errno != EAGAIN ) 135 | { 136 | stop_child = true; 137 | } 138 | } 139 | else if( ret == 0 ) 140 | { 141 | stop_child = true; 142 | } 143 | else 144 | { 145 | struct sockaddr_in client_address; 146 | socklen_t client_addrlength = sizeof( client_address ); 147 | int connfd = accept( listenfd, ( struct sockaddr* )&client_address, &client_addrlength ); 148 | if ( connfd < 0 ) 149 | { 150 | printf( "errno is: %d\n", errno ); 151 | continue; 152 | } 153 | memset( users[connfd].buf, '\0', BUFFER_SIZE ); 154 | users[connfd].address = client_address; 155 | users[connfd].read_idx = 0; 156 | addfd( child_epollfd, connfd ); 157 | } 158 | } 159 | else if( events[i].events & EPOLLIN ) 160 | { 161 | int idx = 0; 162 | while( true ) 163 | { 164 | idx = users[sockfd].read_idx; 165 | ret = recv( sockfd, users[sockfd].buf + idx, BUFFER_SIZE-1-idx, 0 ); 166 | if( ret < 0 ) 167 | { 168 | if( errno != EAGAIN ) 169 | { 170 | epoll_ctl( child_epollfd, EPOLL_CTL_DEL, sockfd, 0 ); 171 | close( sockfd ); 172 | } 173 | break; 174 | } 175 | else if( ret == 0 ) 176 | { 177 | epoll_ctl( child_epollfd, EPOLL_CTL_DEL, sockfd, 0 ); 178 | close( sockfd ); 179 | break; 180 | } 181 | else 182 | { 183 | users[sockfd].read_idx += ret; 184 | printf( "user content is: %s\n", users[sockfd].buf ); 185 | idx = users[sockfd].read_idx; 186 | if( ( idx < 2 ) || ( users[sockfd].buf[idx-2] != '\r' ) || ( users[sockfd].buf[idx-1] != '\n' ) ) 187 | { 188 | continue; 189 | } 190 | users[sockfd].buf[users[sockfd].read_idx-2] = '\0'; 191 | char* file_name = users[sockfd].buf; 192 | if( access( file_name, F_OK ) == -1 ) 193 | { 194 | epoll_ctl( child_epollfd, EPOLL_CTL_DEL, sockfd, 0 ); 195 | close( sockfd ); 196 | break; 197 | } 198 | ret = fork(); 199 | if( ret == -1 ) 200 | { 201 | epoll_ctl( child_epollfd, EPOLL_CTL_DEL, sockfd, 0 ); 202 | close( sockfd ); 203 | break; 204 | } 205 | else if( ret > 0 ) 206 | { 207 | epoll_ctl( child_epollfd, EPOLL_CTL_DEL, sockfd, 0 ); 208 | close( sockfd ); 209 | break; 210 | } 211 | else 212 | { 213 | close( STDOUT_FILENO ); 214 | dup( sockfd ); 215 | execl( users[sockfd].buf, users[sockfd].buf, 0 ); 216 | exit( 0 ); 217 | } 218 | } 219 | } 220 | } 221 | else 222 | { 223 | continue; 224 | } 225 | } 226 | } 227 | 228 | delete [] users; 229 | close( pipefd ); 230 | close( child_epollfd ); 231 | return 0; 232 | } 233 | 234 | int main( int argc, char* argv[] ) 235 | { 236 | if( argc <= 2 ) 237 | { 238 | printf( "usage: %s ip_address port_number\n", basename( argv[0] ) ); 239 | return 1; 240 | } 241 | const char* ip = argv[1]; 242 | int port = atoi( argv[2] ); 243 | 244 | int ret = 0; 245 | struct sockaddr_in address; 246 | bzero( &address, sizeof( address ) ); 247 | address.sin_family = AF_INET; 248 | inet_pton( AF_INET, ip, &address.sin_addr ); 249 | address.sin_port = htons( port ); 250 | 251 | listenfd = socket( PF_INET, SOCK_STREAM, 0 ); 252 | assert( listenfd >= 0 ); 253 | 254 | ret = bind( listenfd, ( struct sockaddr* )&address, sizeof( address ) ); 255 | assert( ret != -1 ); 256 | 257 | ret = listen( listenfd, 5 ); 258 | assert( ret != -1 ); 259 | 260 | for( int i = 0; i < PROCESS_COUNT; ++i ) 261 | { 262 | ret = socketpair( PF_UNIX, SOCK_STREAM, 0, sub_process[i].pipefd ); 263 | assert( ret != -1 ); 264 | sub_process[i].pid = fork(); 265 | if( sub_process[i].pid < 0 ) 266 | { 267 | continue; 268 | } 269 | else if( sub_process[i].pid > 0 ) 270 | { 271 | close( sub_process[i].pipefd[1] ); 272 | setnonblocking( sub_process[i].pipefd[0] ); 273 | continue; 274 | } 275 | else 276 | { 277 | close( sub_process[i].pipefd[0] ); 278 | setnonblocking( sub_process[i].pipefd[1] ); 279 | run_child( i ); 280 | exit( 0 ); 281 | } 282 | } 283 | 284 | epoll_event events[ MAX_EVENT_NUMBER ]; 285 | epollfd = epoll_create( 5 ); 286 | assert( epollfd != -1 ); 287 | addfd( epollfd, listenfd ); 288 | 289 | ret = socketpair( PF_UNIX, SOCK_STREAM, 0, sig_pipefd ); 290 | assert( ret != -1 ); 291 | setnonblocking( sig_pipefd[1] ); 292 | addfd( epollfd, sig_pipefd[0] ); 293 | 294 | addsig( SIGCHLD, sig_handler ); 295 | addsig( SIGTERM, sig_handler ); 296 | addsig( SIGINT, sig_handler ); 297 | addsig( SIGPIPE, SIG_IGN ); 298 | bool stop_server = false; 299 | int sub_process_counter = 0; 300 | 301 | while( !stop_server ) 302 | { 303 | int number = epoll_wait( epollfd, events, MAX_EVENT_NUMBER, -1 ); 304 | if ( ( number < 0 ) && ( errno != EINTR ) ) 305 | { 306 | printf( "epoll failure\n" ); 307 | break; 308 | } 309 | 310 | for ( int i = 0; i < number; i++ ) 311 | { 312 | int sockfd = events[i].data.fd; 313 | if( sockfd == listenfd ) 314 | { 315 | int new_conn = 1; 316 | send( sub_process[sub_process_counter++].pipefd[0], ( char* )&new_conn, sizeof( new_conn ), 0 ); 317 | printf( "send request to child %d\n", sub_process_counter-1 ); 318 | sub_process_counter %= PROCESS_COUNT; 319 | } 320 | else if( ( sockfd == sig_pipefd[0] ) && ( events[i].events & EPOLLIN ) ) 321 | { 322 | int sig; 323 | char signals[1024]; 324 | ret = recv( sig_pipefd[0], signals, sizeof( signals ), 0 ); 325 | if( ret == -1 ) 326 | { 327 | continue; 328 | } 329 | else if( ret == 0 ) 330 | { 331 | continue; 332 | } 333 | else 334 | { 335 | for( int i = 0; i < ret; ++i ) 336 | { 337 | switch( signals[i] ) 338 | { 339 | case SIGCHLD: 340 | { 341 | pid_t pid; 342 | int stat; 343 | while ( ( pid = waitpid( -1, &stat, WNOHANG ) ) > 0 ) 344 | { 345 | for( int i = 0; i < PROCESS_COUNT; ++i ) 346 | { 347 | if( sub_process[i].pid == pid ) 348 | { 349 | close( sub_process[i].pipefd[0] ); 350 | sub_process[i].pid = -1; 351 | } 352 | } 353 | } 354 | stop_server = true; 355 | for( int i = 0; i < PROCESS_COUNT; ++i ) 356 | { 357 | if( sub_process[i].pid != -1 ) 358 | { 359 | stop_server = false; 360 | } 361 | } 362 | break; 363 | } 364 | case SIGTERM: 365 | case SIGINT: 366 | { 367 | printf( "kill all the clild now\n" ); 368 | for( int i = 0; i < PROCESS_COUNT; ++i ) 369 | { 370 | int pid = sub_process[i].pid; 371 | kill( pid, SIGTERM ); 372 | } 373 | break; 374 | } 375 | default: 376 | { 377 | break; 378 | } 379 | } 380 | } 381 | } 382 | } 383 | else 384 | { 385 | continue; 386 | } 387 | } 388 | } 389 | 390 | del_resource(); 391 | return 0; 392 | } 393 | -------------------------------------------------------------------------------- /15/15-3threadpool.h: -------------------------------------------------------------------------------- 1 | #ifndef THREADPOOL_H 2 | #define THREADPOOL_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "locker.h" 9 | 10 | template< typename T > 11 | class threadpool 12 | { 13 | public: 14 | threadpool( int thread_number = 8, int max_requests = 10000 ); 15 | ~threadpool(); 16 | bool append( T* request ); 17 | 18 | private: 19 | static void* worker( void* arg ); 20 | void run(); 21 | 22 | private: 23 | int m_thread_number; 24 | int m_max_requests; 25 | pthread_t* m_threads; 26 | std::list< T* > m_workqueue; 27 | locker m_queuelocker; 28 | sem m_queuestat; 29 | bool m_stop; 30 | }; 31 | 32 | template< typename T > 33 | threadpool< T >::threadpool( int thread_number, int max_requests ) : 34 | m_thread_number( thread_number ), m_max_requests( max_requests ), m_stop( false ), m_threads( NULL ) 35 | { 36 | if( ( thread_number <= 0 ) || ( max_requests <= 0 ) ) 37 | { 38 | throw std::exception(); 39 | } 40 | 41 | m_threads = new pthread_t[ m_thread_number ]; 42 | if( ! m_threads ) 43 | { 44 | throw std::exception(); 45 | } 46 | 47 | for ( int i = 0; i < thread_number; ++i ) 48 | { 49 | printf( "create the %dth thread\n", i ); 50 | if( pthread_create( m_threads + i, NULL, worker, this ) != 0 ) 51 | { 52 | delete [] m_threads; 53 | throw std::exception(); 54 | } 55 | if( pthread_detach( m_threads[i] ) ) 56 | { 57 | delete [] m_threads; 58 | throw std::exception(); 59 | } 60 | } 61 | } 62 | 63 | template< typename T > 64 | threadpool< T >::~threadpool() 65 | { 66 | delete [] m_threads; 67 | m_stop = true; 68 | } 69 | 70 | template< typename T > 71 | bool threadpool< T >::append( T* request ) 72 | { 73 | m_queuelocker.lock(); 74 | if ( m_workqueue.size() > m_max_requests ) 75 | { 76 | m_queuelocker.unlock(); 77 | return false; 78 | } 79 | m_workqueue.push_back( request ); 80 | m_queuelocker.unlock(); 81 | m_queuestat.post(); 82 | return true; 83 | } 84 | 85 | template< typename T > 86 | void* threadpool< T >::worker( void* arg ) 87 | { 88 | threadpool* pool = ( threadpool* )arg; 89 | pool->run(); 90 | return pool; 91 | } 92 | 93 | template< typename T > 94 | void threadpool< T >::run() 95 | { 96 | while ( ! m_stop ) 97 | { 98 | m_queuestat.wait(); 99 | m_queuelocker.lock(); 100 | if ( m_workqueue.empty() ) 101 | { 102 | m_queuelocker.unlock(); 103 | continue; 104 | } 105 | T* request = m_workqueue.front(); 106 | m_workqueue.pop_front(); 107 | m_queuelocker.unlock(); 108 | if ( ! request ) 109 | { 110 | continue; 111 | } 112 | request->process(); 113 | } 114 | } 115 | 116 | #endif 117 | -------------------------------------------------------------------------------- /15/15-4http_conn.h: -------------------------------------------------------------------------------- 1 | #ifndef HTTPCONNECTION_H 2 | #define HTTPCONNECTION_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include "locker.h" 22 | 23 | class http_conn 24 | { 25 | public: 26 | static const int FILENAME_LEN = 200; 27 | static const int READ_BUFFER_SIZE = 2048; 28 | static const int WRITE_BUFFER_SIZE = 1024; 29 | enum METHOD { GET = 0, POST, HEAD, PUT, DELETE, TRACE, OPTIONS, CONNECT, PATCH }; 30 | enum CHECK_STATE { CHECK_STATE_REQUESTLINE = 0, CHECK_STATE_HEADER, CHECK_STATE_CONTENT }; 31 | enum HTTP_CODE { NO_REQUEST, GET_REQUEST, BAD_REQUEST, NO_RESOURCE, FORBIDDEN_REQUEST, FILE_REQUEST, INTERNAL_ERROR, CLOSED_CONNECTION }; 32 | enum LINE_STATUS { LINE_OK = 0, LINE_BAD, LINE_OPEN }; 33 | 34 | public: 35 | http_conn(){} 36 | ~http_conn(){} 37 | 38 | public: 39 | void init( int sockfd, const sockaddr_in& addr ); 40 | void close_conn( bool real_close = true ); 41 | void process(); 42 | bool read(); 43 | bool write(); 44 | 45 | private: 46 | void init(); 47 | HTTP_CODE process_read(); 48 | bool process_write( HTTP_CODE ret ); 49 | 50 | HTTP_CODE parse_request_line( char* text ); 51 | HTTP_CODE parse_headers( char* text ); 52 | HTTP_CODE parse_content( char* text ); 53 | HTTP_CODE do_request(); 54 | char* get_line() { return m_read_buf + m_start_line; } 55 | LINE_STATUS parse_line(); 56 | 57 | void unmap(); 58 | bool add_response( const char* format, ... ); 59 | bool add_content( const char* content ); 60 | bool add_status_line( int status, const char* title ); 61 | bool add_headers( int content_length ); 62 | bool add_content_length( int content_length ); 63 | bool add_linger(); 64 | bool add_blank_line(); 65 | 66 | public: 67 | static int m_epollfd; 68 | static int m_user_count; 69 | 70 | private: 71 | int m_sockfd; 72 | sockaddr_in m_address; 73 | 74 | char m_read_buf[ READ_BUFFER_SIZE ]; 75 | int m_read_idx; 76 | int m_checked_idx; 77 | int m_start_line; 78 | char m_write_buf[ WRITE_BUFFER_SIZE ]; 79 | int m_write_idx; 80 | 81 | CHECK_STATE m_check_state; 82 | METHOD m_method; 83 | 84 | char m_real_file[ FILENAME_LEN ]; 85 | char* m_url; 86 | char* m_version; 87 | char* m_host; 88 | int m_content_length; 89 | bool m_linger; 90 | 91 | char* m_file_address; 92 | struct stat m_file_stat; 93 | struct iovec m_iv[2]; 94 | int m_iv_count; 95 | }; 96 | 97 | #endif 98 | -------------------------------------------------------------------------------- /15/15-5http_conn.cpp: -------------------------------------------------------------------------------- 1 | #include "http_conn.h" 2 | 3 | const char* ok_200_title = "OK"; 4 | const char* error_400_title = "Bad Request"; 5 | const char* error_400_form = "Your request has bad syntax or is inherently impossible to satisfy.\n"; 6 | const char* error_403_title = "Forbidden"; 7 | const char* error_403_form = "You do not have permission to get file from this server.\n"; 8 | const char* error_404_title = "Not Found"; 9 | const char* error_404_form = "The requested file was not found on this server.\n"; 10 | const char* error_500_title = "Internal Error"; 11 | const char* error_500_form = "There was an unusual problem serving the requested file.\n"; 12 | const char* doc_root = "/var/www/html"; 13 | 14 | int setnonblocking( int fd ) 15 | { 16 | int old_option = fcntl( fd, F_GETFL ); 17 | int new_option = old_option | O_NONBLOCK; 18 | fcntl( fd, F_SETFL, new_option ); 19 | return old_option; 20 | } 21 | 22 | void addfd( int epollfd, int fd, bool one_shot ) 23 | { 24 | epoll_event event; 25 | event.data.fd = fd; 26 | event.events = EPOLLIN | EPOLLET | EPOLLRDHUP; 27 | if( one_shot ) 28 | { 29 | event.events |= EPOLLONESHOT; 30 | } 31 | epoll_ctl( epollfd, EPOLL_CTL_ADD, fd, &event ); 32 | setnonblocking( fd ); 33 | } 34 | 35 | void removefd( int epollfd, int fd ) 36 | { 37 | epoll_ctl( epollfd, EPOLL_CTL_DEL, fd, 0 ); 38 | close( fd ); 39 | } 40 | 41 | void modfd( int epollfd, int fd, int ev ) 42 | { 43 | epoll_event event; 44 | event.data.fd = fd; 45 | event.events = ev | EPOLLET | EPOLLONESHOT | EPOLLRDHUP; 46 | epoll_ctl( epollfd, EPOLL_CTL_MOD, fd, &event ); 47 | } 48 | 49 | int http_conn::m_user_count = 0; 50 | int http_conn::m_epollfd = -1; 51 | 52 | void http_conn::close_conn( bool real_close ) 53 | { 54 | if( real_close && ( m_sockfd != -1 ) ) 55 | { 56 | //modfd( m_epollfd, m_sockfd, EPOLLIN ); 57 | removefd( m_epollfd, m_sockfd ); 58 | m_sockfd = -1; 59 | m_user_count--; 60 | } 61 | } 62 | 63 | void http_conn::init( int sockfd, const sockaddr_in& addr ) 64 | { 65 | m_sockfd = sockfd; 66 | m_address = addr; 67 | int error = 0; 68 | socklen_t len = sizeof( error ); 69 | getsockopt( m_sockfd, SOL_SOCKET, SO_ERROR, &error, &len ); 70 | int reuse = 1; 71 | setsockopt( m_sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof( reuse ) ); 72 | addfd( m_epollfd, sockfd, true ); 73 | m_user_count++; 74 | 75 | init(); 76 | } 77 | 78 | void http_conn::init() 79 | { 80 | m_check_state = CHECK_STATE_REQUESTLINE; 81 | m_linger = false; 82 | 83 | m_method = GET; 84 | m_url = 0; 85 | m_version = 0; 86 | m_content_length = 0; 87 | m_host = 0; 88 | m_start_line = 0; 89 | m_checked_idx = 0; 90 | m_read_idx = 0; 91 | m_write_idx = 0; 92 | memset( m_read_buf, '\0', READ_BUFFER_SIZE ); 93 | memset( m_write_buf, '\0', WRITE_BUFFER_SIZE ); 94 | memset( m_real_file, '\0', FILENAME_LEN ); 95 | } 96 | 97 | http_conn::LINE_STATUS http_conn::parse_line() 98 | { 99 | char temp; 100 | for ( ; m_checked_idx < m_read_idx; ++m_checked_idx ) 101 | { 102 | temp = m_read_buf[ m_checked_idx ]; 103 | if ( temp == '\r' ) 104 | { 105 | if ( ( m_checked_idx + 1 ) == m_read_idx ) 106 | { 107 | return LINE_OPEN; 108 | } 109 | else if ( m_read_buf[ m_checked_idx + 1 ] == '\n' ) 110 | { 111 | m_read_buf[ m_checked_idx++ ] = '\0'; 112 | m_read_buf[ m_checked_idx++ ] = '\0'; 113 | return LINE_OK; 114 | } 115 | 116 | return LINE_BAD; 117 | } 118 | else if( temp == '\n' ) 119 | { 120 | if( ( m_checked_idx > 1 ) && ( m_read_buf[ m_checked_idx - 1 ] == '\r' ) ) 121 | { 122 | m_read_buf[ m_checked_idx-1 ] = '\0'; 123 | m_read_buf[ m_checked_idx++ ] = '\0'; 124 | return LINE_OK; 125 | } 126 | return LINE_BAD; 127 | } 128 | } 129 | 130 | return LINE_OPEN; 131 | } 132 | 133 | bool http_conn::read() 134 | { 135 | if( m_read_idx >= READ_BUFFER_SIZE ) 136 | { 137 | return false; 138 | } 139 | 140 | int bytes_read = 0; 141 | while( true ) 142 | { 143 | bytes_read = recv( m_sockfd, m_read_buf + m_read_idx, READ_BUFFER_SIZE - m_read_idx, 0 ); 144 | if ( bytes_read == -1 ) 145 | { 146 | if( errno == EAGAIN || errno == EWOULDBLOCK ) 147 | { 148 | break; 149 | } 150 | return false; 151 | } 152 | else if ( bytes_read == 0 ) 153 | { 154 | return false; 155 | } 156 | 157 | m_read_idx += bytes_read; 158 | } 159 | return true; 160 | } 161 | 162 | http_conn::HTTP_CODE http_conn::parse_request_line( char* text ) 163 | { 164 | m_url = strpbrk( text, " \t" ); 165 | if ( ! m_url ) 166 | { 167 | return BAD_REQUEST; 168 | } 169 | *m_url++ = '\0'; 170 | 171 | char* method = text; 172 | if ( strcasecmp( method, "GET" ) == 0 ) 173 | { 174 | m_method = GET; 175 | } 176 | else 177 | { 178 | return BAD_REQUEST; 179 | } 180 | 181 | m_url += strspn( m_url, " \t" ); 182 | m_version = strpbrk( m_url, " \t" ); 183 | if ( ! m_version ) 184 | { 185 | return BAD_REQUEST; 186 | } 187 | *m_version++ = '\0'; 188 | m_version += strspn( m_version, " \t" ); 189 | if ( strcasecmp( m_version, "HTTP/1.1" ) != 0 ) 190 | { 191 | return BAD_REQUEST; 192 | } 193 | 194 | if ( strncasecmp( m_url, "http://", 7 ) == 0 ) 195 | { 196 | m_url += 7; 197 | m_url = strchr( m_url, '/' ); 198 | } 199 | 200 | if ( ! m_url || m_url[ 0 ] != '/' ) 201 | { 202 | return BAD_REQUEST; 203 | } 204 | 205 | m_check_state = CHECK_STATE_HEADER; 206 | return NO_REQUEST; 207 | } 208 | 209 | http_conn::HTTP_CODE http_conn::parse_headers( char* text ) 210 | { 211 | if( text[ 0 ] == '\0' ) 212 | { 213 | if ( m_method == HEAD ) 214 | { 215 | return GET_REQUEST; 216 | } 217 | 218 | if ( m_content_length != 0 ) 219 | { 220 | m_check_state = CHECK_STATE_CONTENT; 221 | return NO_REQUEST; 222 | } 223 | 224 | return GET_REQUEST; 225 | } 226 | else if ( strncasecmp( text, "Connection:", 11 ) == 0 ) 227 | { 228 | text += 11; 229 | text += strspn( text, " \t" ); 230 | if ( strcasecmp( text, "keep-alive" ) == 0 ) 231 | { 232 | m_linger = true; 233 | } 234 | } 235 | else if ( strncasecmp( text, "Content-Length:", 15 ) == 0 ) 236 | { 237 | text += 15; 238 | text += strspn( text, " \t" ); 239 | m_content_length = atol( text ); 240 | } 241 | else if ( strncasecmp( text, "Host:", 5 ) == 0 ) 242 | { 243 | text += 5; 244 | text += strspn( text, " \t" ); 245 | m_host = text; 246 | } 247 | else 248 | { 249 | printf( "oop! unknow header %s\n", text ); 250 | } 251 | 252 | return NO_REQUEST; 253 | 254 | } 255 | 256 | http_conn::HTTP_CODE http_conn::parse_content( char* text ) 257 | { 258 | if ( m_read_idx >= ( m_content_length + m_checked_idx ) ) 259 | { 260 | text[ m_content_length ] = '\0'; 261 | return GET_REQUEST; 262 | } 263 | 264 | return NO_REQUEST; 265 | } 266 | 267 | http_conn::HTTP_CODE http_conn::process_read() 268 | { 269 | LINE_STATUS line_status = LINE_OK; 270 | HTTP_CODE ret = NO_REQUEST; 271 | char* text = 0; 272 | 273 | while ( ( ( m_check_state == CHECK_STATE_CONTENT ) && ( line_status == LINE_OK ) ) 274 | || ( ( line_status = parse_line() ) == LINE_OK ) ) 275 | { 276 | text = get_line(); 277 | m_start_line = m_checked_idx; 278 | printf( "got 1 http line: %s\n", text ); 279 | 280 | switch ( m_check_state ) 281 | { 282 | case CHECK_STATE_REQUESTLINE: 283 | { 284 | ret = parse_request_line( text ); 285 | if ( ret == BAD_REQUEST ) 286 | { 287 | return BAD_REQUEST; 288 | } 289 | break; 290 | } 291 | case CHECK_STATE_HEADER: 292 | { 293 | ret = parse_headers( text ); 294 | if ( ret == BAD_REQUEST ) 295 | { 296 | return BAD_REQUEST; 297 | } 298 | else if ( ret == GET_REQUEST ) 299 | { 300 | return do_request(); 301 | } 302 | break; 303 | } 304 | case CHECK_STATE_CONTENT: 305 | { 306 | ret = parse_content( text ); 307 | if ( ret == GET_REQUEST ) 308 | { 309 | return do_request(); 310 | } 311 | line_status = LINE_OPEN; 312 | break; 313 | } 314 | default: 315 | { 316 | return INTERNAL_ERROR; 317 | } 318 | } 319 | } 320 | 321 | return NO_REQUEST; 322 | } 323 | 324 | http_conn::HTTP_CODE http_conn::do_request() 325 | { 326 | strcpy( m_real_file, doc_root ); 327 | int len = strlen( doc_root ); 328 | strncpy( m_real_file + len, m_url, FILENAME_LEN - len - 1 ); 329 | if ( stat( m_real_file, &m_file_stat ) < 0 ) 330 | { 331 | return NO_RESOURCE; 332 | } 333 | 334 | if ( ! ( m_file_stat.st_mode & S_IROTH ) ) 335 | { 336 | return FORBIDDEN_REQUEST; 337 | } 338 | 339 | if ( S_ISDIR( m_file_stat.st_mode ) ) 340 | { 341 | return BAD_REQUEST; 342 | } 343 | 344 | int fd = open( m_real_file, O_RDONLY ); 345 | m_file_address = ( char* )mmap( 0, m_file_stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0 ); 346 | close( fd ); 347 | return FILE_REQUEST; 348 | } 349 | 350 | void http_conn::unmap() 351 | { 352 | if( m_file_address ) 353 | { 354 | munmap( m_file_address, m_file_stat.st_size ); 355 | m_file_address = 0; 356 | } 357 | } 358 | 359 | bool http_conn::write() 360 | { 361 | int temp = 0; 362 | int bytes_have_send = 0; 363 | int bytes_to_send = m_write_idx; 364 | if ( bytes_to_send == 0 ) 365 | { 366 | modfd( m_epollfd, m_sockfd, EPOLLIN ); 367 | init(); 368 | return true; 369 | } 370 | 371 | while( 1 ) 372 | { 373 | temp = writev( m_sockfd, m_iv, m_iv_count ); 374 | if ( temp <= -1 ) 375 | { 376 | if( errno == EAGAIN ) 377 | { 378 | modfd( m_epollfd, m_sockfd, EPOLLOUT ); 379 | return true; 380 | } 381 | unmap(); 382 | return false; 383 | } 384 | 385 | bytes_to_send -= temp; 386 | bytes_have_send += temp; 387 | if ( bytes_to_send <= bytes_have_send ) 388 | { 389 | unmap(); 390 | if( m_linger ) 391 | { 392 | init(); 393 | modfd( m_epollfd, m_sockfd, EPOLLIN ); 394 | return true; 395 | } 396 | else 397 | { 398 | modfd( m_epollfd, m_sockfd, EPOLLIN ); 399 | return false; 400 | } 401 | } 402 | } 403 | } 404 | 405 | bool http_conn::add_response( const char* format, ... ) 406 | { 407 | if( m_write_idx >= WRITE_BUFFER_SIZE ) 408 | { 409 | return false; 410 | } 411 | va_list arg_list; 412 | va_start( arg_list, format ); 413 | int len = vsnprintf( m_write_buf + m_write_idx, WRITE_BUFFER_SIZE - 1 - m_write_idx, format, arg_list ); 414 | if( len >= ( WRITE_BUFFER_SIZE - 1 - m_write_idx ) ) 415 | { 416 | return false; 417 | } 418 | m_write_idx += len; 419 | va_end( arg_list ); 420 | return true; 421 | } 422 | 423 | bool http_conn::add_status_line( int status, const char* title ) 424 | { 425 | return add_response( "%s %d %s\r\n", "HTTP/1.1", status, title ); 426 | } 427 | 428 | bool http_conn::add_headers( int content_len ) 429 | { 430 | add_content_length( content_len ); 431 | add_linger(); 432 | add_blank_line(); 433 | } 434 | 435 | bool http_conn::add_content_length( int content_len ) 436 | { 437 | return add_response( "Content-Length: %d\r\n", content_len ); 438 | } 439 | 440 | bool http_conn::add_linger() 441 | { 442 | return add_response( "Connection: %s\r\n", ( m_linger == true ) ? "keep-alive" : "close" ); 443 | } 444 | 445 | bool http_conn::add_blank_line() 446 | { 447 | return add_response( "%s", "\r\n" ); 448 | } 449 | 450 | bool http_conn::add_content( const char* content ) 451 | { 452 | return add_response( "%s", content ); 453 | } 454 | 455 | bool http_conn::process_write( HTTP_CODE ret ) 456 | { 457 | switch ( ret ) 458 | { 459 | case INTERNAL_ERROR: 460 | { 461 | add_status_line( 500, error_500_title ); 462 | add_headers( strlen( error_500_form ) ); 463 | if ( ! add_content( error_500_form ) ) 464 | { 465 | return false; 466 | } 467 | break; 468 | } 469 | case BAD_REQUEST: 470 | { 471 | add_status_line( 400, error_400_title ); 472 | add_headers( strlen( error_400_form ) ); 473 | if ( ! add_content( error_400_form ) ) 474 | { 475 | return false; 476 | } 477 | break; 478 | } 479 | case NO_RESOURCE: 480 | { 481 | add_status_line( 404, error_404_title ); 482 | add_headers( strlen( error_404_form ) ); 483 | if ( ! add_content( error_404_form ) ) 484 | { 485 | return false; 486 | } 487 | break; 488 | } 489 | case FORBIDDEN_REQUEST: 490 | { 491 | add_status_line( 403, error_403_title ); 492 | add_headers( strlen( error_403_form ) ); 493 | if ( ! add_content( error_403_form ) ) 494 | { 495 | return false; 496 | } 497 | break; 498 | } 499 | case FILE_REQUEST: 500 | { 501 | add_status_line( 200, ok_200_title ); 502 | if ( m_file_stat.st_size != 0 ) 503 | { 504 | add_headers( m_file_stat.st_size ); 505 | m_iv[ 0 ].iov_base = m_write_buf; 506 | m_iv[ 0 ].iov_len = m_write_idx; 507 | m_iv[ 1 ].iov_base = m_file_address; 508 | m_iv[ 1 ].iov_len = m_file_stat.st_size; 509 | m_iv_count = 2; 510 | return true; 511 | } 512 | else 513 | { 514 | const char* ok_string = ""; 515 | add_headers( strlen( ok_string ) ); 516 | if ( ! add_content( ok_string ) ) 517 | { 518 | return false; 519 | } 520 | } 521 | } 522 | default: 523 | { 524 | return false; 525 | } 526 | } 527 | 528 | m_iv[ 0 ].iov_base = m_write_buf; 529 | m_iv[ 0 ].iov_len = m_write_idx; 530 | m_iv_count = 1; 531 | return true; 532 | } 533 | 534 | void http_conn::process() 535 | { 536 | HTTP_CODE read_ret = process_read(); 537 | if ( read_ret == NO_REQUEST ) 538 | { 539 | modfd( m_epollfd, m_sockfd, EPOLLIN ); 540 | return; 541 | } 542 | 543 | bool write_ret = process_write( read_ret ); 544 | if ( ! write_ret ) 545 | { 546 | close_conn(); 547 | } 548 | 549 | modfd( m_epollfd, m_sockfd, EPOLLOUT ); 550 | } 551 | 552 | -------------------------------------------------------------------------------- /15/15-6main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "locker.h" 14 | #include "threadpool.h" 15 | #include "http_conn.h" 16 | 17 | #define MAX_FD 65536 18 | #define MAX_EVENT_NUMBER 10000 19 | 20 | extern int addfd( int epollfd, int fd, bool one_shot ); 21 | extern int removefd( int epollfd, int fd ); 22 | 23 | void addsig( int sig, void( handler )(int), bool restart = true ) 24 | { 25 | struct sigaction sa; 26 | memset( &sa, '\0', sizeof( sa ) ); 27 | sa.sa_handler = handler; 28 | if( restart ) 29 | { 30 | sa.sa_flags |= SA_RESTART; 31 | } 32 | sigfillset( &sa.sa_mask ); 33 | assert( sigaction( sig, &sa, NULL ) != -1 ); 34 | } 35 | 36 | void show_error( int connfd, const char* info ) 37 | { 38 | printf( "%s", info ); 39 | send( connfd, info, strlen( info ), 0 ); 40 | close( connfd ); 41 | } 42 | 43 | 44 | int main( int argc, char* argv[] ) 45 | { 46 | if( argc <= 2 ) 47 | { 48 | printf( "usage: %s ip_address port_number\n", basename( argv[0] ) ); 49 | return 1; 50 | } 51 | const char* ip = argv[1]; 52 | int port = atoi( argv[2] ); 53 | 54 | addsig( SIGPIPE, SIG_IGN ); 55 | 56 | threadpool< http_conn >* pool = NULL; 57 | try 58 | { 59 | pool = new threadpool< http_conn >; 60 | } 61 | catch( ... ) 62 | { 63 | return 1; 64 | } 65 | 66 | http_conn* users = new http_conn[ MAX_FD ]; 67 | assert( users ); 68 | int user_count = 0; 69 | 70 | int listenfd = socket( PF_INET, SOCK_STREAM, 0 ); 71 | assert( listenfd >= 0 ); 72 | struct linger tmp = { 1, 0 }; 73 | setsockopt( listenfd, SOL_SOCKET, SO_LINGER, &tmp, sizeof( tmp ) ); 74 | 75 | int ret = 0; 76 | struct sockaddr_in address; 77 | bzero( &address, sizeof( address ) ); 78 | address.sin_family = AF_INET; 79 | inet_pton( AF_INET, ip, &address.sin_addr ); 80 | address.sin_port = htons( port ); 81 | 82 | ret = bind( listenfd, ( struct sockaddr* )&address, sizeof( address ) ); 83 | assert( ret >= 0 ); 84 | 85 | ret = listen( listenfd, 5 ); 86 | assert( ret >= 0 ); 87 | 88 | epoll_event events[ MAX_EVENT_NUMBER ]; 89 | int epollfd = epoll_create( 5 ); 90 | assert( epollfd != -1 ); 91 | addfd( epollfd, listenfd, false ); 92 | http_conn::m_epollfd = epollfd; 93 | 94 | while( true ) 95 | { 96 | int number = epoll_wait( epollfd, events, MAX_EVENT_NUMBER, -1 ); 97 | if ( ( number < 0 ) && ( errno != EINTR ) ) 98 | { 99 | printf( "epoll failure\n" ); 100 | break; 101 | } 102 | 103 | for ( int i = 0; i < number; i++ ) 104 | { 105 | int sockfd = events[i].data.fd; 106 | if( sockfd == listenfd ) 107 | { 108 | struct sockaddr_in client_address; 109 | socklen_t client_addrlength = sizeof( client_address ); 110 | int connfd = accept( listenfd, ( struct sockaddr* )&client_address, &client_addrlength ); 111 | if ( connfd < 0 ) 112 | { 113 | printf( "errno is: %d\n", errno ); 114 | continue; 115 | } 116 | if( http_conn::m_user_count >= MAX_FD ) 117 | { 118 | show_error( connfd, "Internal server busy" ); 119 | continue; 120 | } 121 | 122 | users[connfd].init( connfd, client_address ); 123 | } 124 | else if( events[i].events & ( EPOLLRDHUP | EPOLLHUP | EPOLLERR ) ) 125 | { 126 | users[sockfd].close_conn(); 127 | } 128 | else if( events[i].events & EPOLLIN ) 129 | { 130 | if( users[sockfd].read() ) 131 | { 132 | pool->append( users + sockfd ); 133 | } 134 | else 135 | { 136 | users[sockfd].close_conn(); 137 | } 138 | } 139 | else if( events[i].events & EPOLLOUT ) 140 | { 141 | if( !users[sockfd].write() ) 142 | { 143 | users[sockfd].close_conn(); 144 | } 145 | } 146 | else 147 | {} 148 | } 149 | } 150 | 151 | close( epollfd ); 152 | close( listenfd ); 153 | delete [] users; 154 | delete pool; 155 | return 0; 156 | } 157 | -------------------------------------------------------------------------------- /16/16-4stress_client.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | static const char* request = "GET http://localhost/index.html HTTP/1.1\r\nConnection: keep-alive\r\n\r\nxxxxxxxxxxxx"; 14 | 15 | int setnonblocking( int fd ) 16 | { 17 | int old_option = fcntl( fd, F_GETFL ); 18 | int new_option = old_option | O_NONBLOCK; 19 | fcntl( fd, F_SETFL, new_option ); 20 | return old_option; 21 | } 22 | 23 | void addfd( int epoll_fd, int fd ) 24 | { 25 | epoll_event event; 26 | event.data.fd = fd; 27 | event.events = EPOLLOUT | EPOLLET | EPOLLERR; 28 | epoll_ctl( epoll_fd, EPOLL_CTL_ADD, fd, &event ); 29 | setnonblocking( fd ); 30 | } 31 | 32 | bool write_nbytes( int sockfd, const char* buffer, int len ) 33 | { 34 | int bytes_write = 0; 35 | printf( "write out %d bytes to socket %d\n", len, sockfd ); 36 | while( 1 ) 37 | { 38 | bytes_write = send( sockfd, buffer, len, 0 ); 39 | if ( bytes_write == -1 ) 40 | { 41 | return false; 42 | } 43 | else if ( bytes_write == 0 ) 44 | { 45 | return false; 46 | } 47 | 48 | len -= bytes_write; 49 | buffer = buffer + bytes_write; 50 | if ( len <= 0 ) 51 | { 52 | return true; 53 | } 54 | } 55 | } 56 | 57 | bool read_once( int sockfd, char* buffer, int len ) 58 | { 59 | int bytes_read = 0; 60 | memset( buffer, '\0', len ); 61 | bytes_read = recv( sockfd, buffer, len, 0 ); 62 | if ( bytes_read == -1 ) 63 | { 64 | return false; 65 | } 66 | else if ( bytes_read == 0 ) 67 | { 68 | return false; 69 | } 70 | printf( "read in %d bytes from socket %d with content: %s\n", bytes_read, sockfd, buffer ); 71 | 72 | return true; 73 | } 74 | 75 | void start_conn( int epoll_fd, int num, const char* ip, int port ) 76 | { 77 | int ret = 0; 78 | struct sockaddr_in address; 79 | bzero( &address, sizeof( address ) ); 80 | address.sin_family = AF_INET; 81 | inet_pton( AF_INET, ip, &address.sin_addr ); 82 | address.sin_port = htons( port ); 83 | 84 | for ( int i = 0; i < num; ++i ) 85 | { 86 | sleep( 1 ); 87 | int sockfd = socket( PF_INET, SOCK_STREAM, 0 ); 88 | printf( "create 1 sock\n" ); 89 | if( sockfd < 0 ) 90 | { 91 | continue; 92 | } 93 | 94 | if ( connect( sockfd, ( struct sockaddr* )&address, sizeof( address ) ) == 0 ) 95 | { 96 | printf( "build connection %d\n", i ); 97 | addfd( epoll_fd, sockfd ); 98 | } 99 | } 100 | } 101 | 102 | void close_conn( int epoll_fd, int sockfd ) 103 | { 104 | epoll_ctl( epoll_fd, EPOLL_CTL_DEL, sockfd, 0 ); 105 | close( sockfd ); 106 | } 107 | 108 | int main( int argc, char* argv[] ) 109 | { 110 | assert( argc == 4 ); 111 | int epoll_fd = epoll_create( 100 ); 112 | start_conn( epoll_fd, atoi( argv[ 3 ] ), argv[1], atoi( argv[2] ) ); 113 | epoll_event events[ 10000 ]; 114 | char buffer[ 2048 ]; 115 | while ( 1 ) 116 | { 117 | int fds = epoll_wait( epoll_fd, events, 10000, 2000 ); 118 | for ( int i = 0; i < fds; i++ ) 119 | { 120 | int sockfd = events[i].data.fd; 121 | if ( events[i].events & EPOLLIN ) 122 | { 123 | if ( ! read_once( sockfd, buffer, 2048 ) ) 124 | { 125 | close_conn( epoll_fd, sockfd ); 126 | } 127 | struct epoll_event event; 128 | event.events = EPOLLOUT | EPOLLET | EPOLLERR; 129 | event.data.fd = sockfd; 130 | epoll_ctl( epoll_fd, EPOLL_CTL_MOD, sockfd, &event ); 131 | } 132 | else if( events[i].events & EPOLLOUT ) 133 | { 134 | if ( ! write_nbytes( sockfd, request, strlen( request ) ) ) 135 | { 136 | close_conn( epoll_fd, sockfd ); 137 | } 138 | struct epoll_event event; 139 | event.events = EPOLLIN | EPOLLET | EPOLLERR; 140 | event.data.fd = sockfd; 141 | epoll_ctl( epoll_fd, EPOLL_CTL_MOD, sockfd, &event ); 142 | } 143 | else if( events[i].events & EPOLLERR ) 144 | { 145 | close_conn( epoll_fd, sockfd ); 146 | } 147 | } 148 | } 149 | } 150 | 151 | -------------------------------------------------------------------------------- /5/5-10set_send_buffer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define BUFFER_SIZE 512 10 | 11 | int main( int argc, char* argv[] ) 12 | { 13 | if( argc <= 3 ) 14 | { 15 | printf( "usage: %s ip_address port_number send_bufer_size\n", basename( argv[0] ) ); 16 | return 1; 17 | } 18 | const char* ip = argv[1]; 19 | int port = atoi( argv[2] ); 20 | 21 | struct sockaddr_in server_address; 22 | bzero( &server_address, sizeof( server_address ) ); 23 | server_address.sin_family = AF_INET; 24 | inet_pton( AF_INET, ip, &server_address.sin_addr ); 25 | server_address.sin_port = htons( port ); 26 | 27 | int sock = socket( PF_INET, SOCK_STREAM, 0 ); 28 | assert( sock >= 0 ); 29 | 30 | int sendbuf = atoi( argv[3] ); 31 | int len = sizeof( sendbuf ); 32 | setsockopt( sock, SOL_SOCKET, SO_SNDBUF, &sendbuf, sizeof( sendbuf ) ); 33 | getsockopt( sock, SOL_SOCKET, SO_SNDBUF, &sendbuf, ( socklen_t* )&len ); 34 | printf( "the tcp send buffer size after setting is %d\n", sendbuf ); 35 | 36 | if ( connect( sock, ( struct sockaddr* )&server_address, sizeof( server_address ) ) != -1 ) 37 | { 38 | char buffer[ BUFFER_SIZE ]; 39 | memset( buffer, 'a', BUFFER_SIZE ); 40 | send( sock, buffer, BUFFER_SIZE, 0 ); 41 | } 42 | 43 | close( sock ); 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /5/5-11set_recv_buffer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define BUFFER_SIZE 1024 12 | 13 | int main( int argc, char* argv[] ) 14 | { 15 | if( argc <= 3 ) 16 | { 17 | printf( "usage: %s ip_address port_number receive_buffer_size\n", basename( argv[0] ) ); 18 | return 1; 19 | } 20 | const char* ip = argv[1]; 21 | int port = atoi( argv[2] ); 22 | 23 | struct sockaddr_in address; 24 | bzero( &address, sizeof( address ) ); 25 | address.sin_family = AF_INET; 26 | inet_pton( AF_INET, ip, &address.sin_addr ); 27 | address.sin_port = htons( port ); 28 | 29 | int sock = socket( PF_INET, SOCK_STREAM, 0 ); 30 | assert( sock >= 0 ); 31 | int recvbuf = atoi( argv[3] ); 32 | int len = sizeof( recvbuf ); 33 | setsockopt( sock, SOL_SOCKET, SO_RCVBUF, &recvbuf, sizeof( recvbuf ) ); 34 | getsockopt( sock, SOL_SOCKET, SO_RCVBUF, &recvbuf, ( socklen_t* )&len ); 35 | printf( "the receive buffer size after settting is %d\n", recvbuf ); 36 | 37 | int ret = bind( sock, ( struct sockaddr* )&address, sizeof( address ) ); 38 | assert( ret != -1 ); 39 | 40 | ret = listen( sock, 5 ); 41 | assert( ret != -1 ); 42 | 43 | struct sockaddr_in client; 44 | socklen_t client_addrlength = sizeof( client ); 45 | int connfd = accept( sock, ( struct sockaddr* )&client, &client_addrlength ); 46 | if ( connfd < 0 ) 47 | { 48 | printf( "errno is: %d\n", errno ); 49 | } 50 | else 51 | { 52 | char buffer[ BUFFER_SIZE ]; 53 | memset( buffer, '\0', BUFFER_SIZE ); 54 | while( recv( connfd, buffer, BUFFER_SIZE-1, 0 ) > 0 ){} 55 | close( connfd ); 56 | } 57 | 58 | close( sock ); 59 | return 0; 60 | } 61 | 62 | -------------------------------------------------------------------------------- /5/5-12access_daytime.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main( int argc, char *argv[] ) 9 | { 10 | assert( argc == 2 ); 11 | char *host = argv[1]; 12 | struct hostent* hostinfo = gethostbyname( host ); 13 | assert( hostinfo ); 14 | struct servent* servinfo = getservbyname( "daytime", "tcp" ); 15 | assert( servinfo ); 16 | printf( "daytime port is %d\n", ntohs( servinfo->s_port ) ); 17 | 18 | struct sockaddr_in address; 19 | address.sin_family = AF_INET; 20 | address.sin_port = servinfo->s_port; 21 | address.sin_addr = *( struct in_addr* )*hostinfo->h_addr_list; 22 | 23 | int sockfd = socket( AF_INET, SOCK_STREAM, 0 ); 24 | int result = connect( sockfd, (struct sockaddr* )&address, sizeof( address ) ); 25 | assert( result != -1 ); 26 | 27 | char buffer[128]; 28 | result = read( sockfd, buffer, sizeof( buffer ) ); 29 | assert( result > 0 ); 30 | buffer[ result ] = '\0'; 31 | printf( "the day tiem is: %s", buffer ); 32 | close( sockfd ); 33 | return 0; 34 | } -------------------------------------------------------------------------------- /5/5-1byteorder.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | void byteorder() 3 | { 4 | union 5 | { 6 | short value; 7 | char union_bytes[ sizeof( short ) ]; 8 | } test; 9 | test.value = 0x0102; 10 | if ( ( test.union_bytes[ 0 ] == 1 ) && ( test.union_bytes[ 1 ] == 2 ) ) 11 | { 12 | printf( "big endian\n" ); 13 | } 14 | else if ( ( test.union_bytes[ 0 ] == 2 ) && ( test.union_bytes[ 1 ] == 1 ) ) 15 | { 16 | printf( "little endian\n" ); 17 | } 18 | else 19 | { 20 | printf( "unknown...\n" ); 21 | } 22 | } -------------------------------------------------------------------------------- /5/5-3testlisten.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | static bool stop = false; 12 | static void handle_term( int sig ) 13 | { 14 | stop = true; 15 | } 16 | 17 | int main( int argc, char* argv[] ) 18 | { 19 | signal( SIGTERM, handle_term ); 20 | 21 | if( argc <= 3 ) 22 | { 23 | printf( "usage: %s ip_address port_number backlog\n", basename( argv[0] ) ); 24 | return 1; 25 | } 26 | const char* ip = argv[1]; 27 | int port = atoi( argv[2] ); 28 | int backlog = atoi( argv[3] ); 29 | 30 | int sock = socket( PF_INET, SOCK_STREAM, 0 ); 31 | assert( sock >= 0 ); 32 | 33 | struct sockaddr_in address; 34 | bzero( &address, sizeof( address ) ); 35 | address.sin_family = AF_INET; 36 | inet_pton( AF_INET, ip, &address.sin_addr ); 37 | address.sin_port = htons( port ); 38 | 39 | int ret = bind( sock, ( struct sockaddr* )&address, sizeof( address ) ); 40 | assert( ret != -1 ); 41 | 42 | ret = listen( sock, backlog ); 43 | assert( ret != -1 ); 44 | 45 | while ( ! stop ) 46 | { 47 | sleep( 1 ); 48 | } 49 | 50 | close( sock ); 51 | return 0; 52 | } 53 | -------------------------------------------------------------------------------- /5/5-5testaccept.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int main( int argc, char* argv[] ) 12 | { 13 | if( argc <= 2 ) 14 | { 15 | printf( "usage: %s ip_address port_number\n", basename( argv[0] ) ); 16 | return 1; 17 | } 18 | const char* ip = argv[1]; 19 | int port = atoi( argv[2] ); 20 | 21 | struct sockaddr_in address; 22 | bzero( &address, sizeof( address ) ); 23 | address.sin_family = AF_INET; 24 | inet_pton( AF_INET, ip, &address.sin_addr ); 25 | address.sin_port = htons( port ); 26 | 27 | int sock = socket( PF_INET, SOCK_STREAM, 0 ); 28 | assert( sock >= 0 ); 29 | 30 | int ret = bind( sock, ( struct sockaddr* )&address, sizeof( address ) ); 31 | assert( ret != -1 ); 32 | 33 | ret = listen( sock, 5 ); 34 | assert( ret != -1 ); 35 | 36 | struct sockaddr_in client; 37 | socklen_t client_addrlength = sizeof( client ); 38 | int connfd = accept( sock, ( struct sockaddr* )&client, &client_addrlength ); 39 | if ( connfd < 0 ) 40 | { 41 | printf( "errno is: %d\n", errno ); 42 | } 43 | else 44 | { 45 | char remote[INET_ADDRSTRLEN ]; 46 | printf( "connected with ip: %s and port: %d\n", 47 | inet_ntop( AF_INET, &client.sin_addr, remote, INET_ADDRSTRLEN ), ntohs( client.sin_port ) ); 48 | close( connfd ); 49 | } 50 | 51 | close( sock ); 52 | return 0; 53 | } 54 | 55 | -------------------------------------------------------------------------------- /5/5-6oobsend.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | int main( int argc, char* argv[] ) 11 | { 12 | if( argc <= 2 ) 13 | { 14 | printf( "usage: %s ip_address port_number\n", basename( argv[0] ) ); 15 | return 1; 16 | } 17 | const char* ip = argv[1]; 18 | int port = atoi( argv[2] ); 19 | 20 | struct sockaddr_in server_address; 21 | bzero( &server_address, sizeof( server_address ) ); 22 | server_address.sin_family = AF_INET; 23 | inet_pton( AF_INET, ip, &server_address.sin_addr ); 24 | server_address.sin_port = htons( port ); 25 | 26 | int sockfd = socket( PF_INET, SOCK_STREAM, 0 ); 27 | assert( sockfd >= 0 ); 28 | if ( connect( sockfd, ( struct sockaddr* )&server_address, sizeof( server_address ) ) < 0 ) 29 | { 30 | printf( "connection failed\n" ); 31 | } 32 | else 33 | { 34 | printf( "send oob data out\n" ); 35 | const char* oob_data = "abc"; 36 | const char* normal_data = "123"; 37 | send( sockfd, normal_data, strlen( normal_data ), 0 ); 38 | send( sockfd, oob_data, strlen( oob_data ), MSG_OOB ); 39 | send( sockfd, normal_data, strlen( normal_data ), 0 ); 40 | } 41 | 42 | close( sockfd ); 43 | return 0; 44 | } 45 | -------------------------------------------------------------------------------- /5/5-7oobrecv.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define BUF_SIZE 1024 12 | 13 | int main( int argc, char* argv[] ) 14 | { 15 | if( argc <= 2 ) 16 | { 17 | printf( "usage: %s ip_address port_number\n", basename( argv[0] ) ); 18 | return 1; 19 | } 20 | const char* ip = argv[1]; 21 | int port = atoi( argv[2] ); 22 | 23 | struct sockaddr_in address; 24 | bzero( &address, sizeof( address ) ); 25 | address.sin_family = AF_INET; 26 | inet_pton( AF_INET, ip, &address.sin_addr ); 27 | address.sin_port = htons( port ); 28 | 29 | int sock = socket( PF_INET, SOCK_STREAM, 0 ); 30 | assert( sock >= 0 ); 31 | 32 | int ret = bind( sock, ( struct sockaddr* )&address, sizeof( address ) ); 33 | assert( ret != -1 ); 34 | 35 | ret = listen( sock, 5 ); 36 | assert( ret != -1 ); 37 | 38 | struct sockaddr_in client; 39 | socklen_t client_addrlength = sizeof( client ); 40 | int connfd = accept( sock, ( struct sockaddr* )&client, &client_addrlength ); 41 | if ( connfd < 0 ) 42 | { 43 | printf( "errno is: %d\n", errno ); 44 | } 45 | else 46 | { 47 | char buffer[ BUF_SIZE ]; 48 | 49 | memset( buffer, '\0', BUF_SIZE ); 50 | ret = recv( connfd, buffer, BUF_SIZE-1, 0 ); 51 | printf( "got %d bytes of normal data '%s'\n", ret, buffer ); 52 | 53 | memset( buffer, '\0', BUF_SIZE ); 54 | ret = recv( connfd, buffer, BUF_SIZE-1, MSG_OOB ); 55 | printf( "got %d bytes of oob data '%s'\n", ret, buffer ); 56 | 57 | memset( buffer, '\0', BUF_SIZE ); 58 | ret = recv( connfd, buffer, BUF_SIZE-1, 0 ); 59 | printf( "got %d bytes of normal data '%s'\n", ret, buffer ); 60 | 61 | close( connfd ); 62 | } 63 | 64 | close( sock ); 65 | return 0; 66 | } 67 | 68 | -------------------------------------------------------------------------------- /5/5-9reuse_address.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int main( int argc, char* argv[] ) 12 | { 13 | if( argc <= 2 ) 14 | { 15 | printf( "usage: %s ip_address port_number\n", basename( argv[0] ) ); 16 | return 1; 17 | } 18 | const char* ip = argv[1]; 19 | int port = atoi( argv[2] ); 20 | 21 | int sock = socket( PF_INET, SOCK_STREAM, 0 ); 22 | assert( sock >= 0 ); 23 | int reuse = 1; 24 | setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof( reuse ) ); 25 | 26 | struct sockaddr_in address; 27 | bzero( &address, sizeof( address ) ); 28 | address.sin_family = AF_INET; 29 | inet_pton( AF_INET, ip, &address.sin_addr ); 30 | address.sin_port = htons( port ); 31 | int ret = bind( sock, ( struct sockaddr* )&address, sizeof( address ) ); 32 | assert( ret != -1 ); 33 | 34 | ret = listen( sock, 5 ); 35 | assert( ret != -1 ); 36 | 37 | struct sockaddr_in client; 38 | socklen_t client_addrlength = sizeof( client ); 39 | int connfd = accept( sock, ( struct sockaddr* )&client, &client_addrlength ); 40 | if ( connfd < 0 ) 41 | { 42 | printf( "errno is: %d\n", errno ); 43 | } 44 | else 45 | { 46 | char remote[INET_ADDRSTRLEN ]; 47 | printf( "connected with ip: %s and port: %d\n", 48 | inet_ntop( AF_INET, &client.sin_addr, remote, INET_ADDRSTRLEN ), ntohs( client.sin_port ) ); 49 | close( connfd ); 50 | } 51 | 52 | close( sock ); 53 | return 0; 54 | } 55 | 56 | -------------------------------------------------------------------------------- /6/6-1testdup.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int main( int argc, char* argv[] ) 12 | { 13 | if( argc <= 2 ) 14 | { 15 | printf( "usage: %s ip_address port_number\n", basename( argv[0] ) ); 16 | return 1; 17 | } 18 | const char* ip = argv[1]; 19 | int port = atoi( argv[2] ); 20 | 21 | struct sockaddr_in address; 22 | bzero( &address, sizeof( address ) ); 23 | address.sin_family = AF_INET; 24 | inet_pton( AF_INET, ip, &address.sin_addr ); 25 | address.sin_port = htons( port ); 26 | 27 | int sock = socket( PF_INET, SOCK_STREAM, 0 ); 28 | assert( sock >= 0 ); 29 | 30 | int ret = bind( sock, ( struct sockaddr* )&address, sizeof( address ) ); 31 | assert( ret != -1 ); 32 | 33 | ret = listen( sock, 5 ); 34 | assert( ret != -1 ); 35 | 36 | struct sockaddr_in client; 37 | socklen_t client_addrlength = sizeof( client ); 38 | int connfd = accept( sock, ( struct sockaddr* )&client, &client_addrlength ); 39 | if ( connfd < 0 ) 40 | { 41 | printf( "errno is: %d\n", errno ); 42 | } 43 | else 44 | { 45 | close( STDOUT_FILENO ); 46 | dup( connfd ); 47 | printf( "abcd\n" ); 48 | close( connfd ); 49 | } 50 | 51 | close( sock ); 52 | return 0; 53 | } 54 | 55 | -------------------------------------------------------------------------------- /6/6-2testwritev.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #define BUFFER_SIZE 1024 15 | static const char* status_line[2] = { "200 OK", "500 Internal server error" }; 16 | 17 | int main( int argc, char* argv[] ) 18 | { 19 | if( argc <= 3 ) 20 | { 21 | printf( "usage: %s ip_address port_number filename\n", basename( argv[0] ) ); 22 | return 1; 23 | } 24 | const char* ip = argv[1]; 25 | int port = atoi( argv[2] ); 26 | const char* file_name = argv[3]; 27 | 28 | struct sockaddr_in address; 29 | bzero( &address, sizeof( address ) ); 30 | address.sin_family = AF_INET; 31 | inet_pton( AF_INET, ip, &address.sin_addr ); 32 | address.sin_port = htons( port ); 33 | 34 | int sock = socket( PF_INET, SOCK_STREAM, 0 ); 35 | assert( sock >= 0 ); 36 | 37 | int ret = bind( sock, ( struct sockaddr* )&address, sizeof( address ) ); 38 | assert( ret != -1 ); 39 | 40 | ret = listen( sock, 5 ); 41 | assert( ret != -1 ); 42 | 43 | struct sockaddr_in client; 44 | socklen_t client_addrlength = sizeof( client ); 45 | int connfd = accept( sock, ( struct sockaddr* )&client, &client_addrlength ); 46 | if ( connfd < 0 ) 47 | { 48 | printf( "errno is: %d\n", errno ); 49 | } 50 | else 51 | { 52 | char header_buf[ BUFFER_SIZE ]; 53 | memset( header_buf, '\0', BUFFER_SIZE ); 54 | char* file_buf; 55 | struct stat file_stat; 56 | bool valid = true; 57 | int len = 0; 58 | if( stat( file_name, &file_stat ) < 0 ) 59 | { 60 | valid = false; 61 | } 62 | else 63 | { 64 | if( S_ISDIR( file_stat.st_mode ) ) 65 | { 66 | valid = false; 67 | } 68 | else if( file_stat.st_mode & S_IROTH ) 69 | { 70 | int fd = open( file_name, O_RDONLY ); 71 | file_buf = new char [ file_stat.st_size + 1 ]; 72 | memset( file_buf, '\0', file_stat.st_size + 1 ); 73 | if ( read( fd, file_buf, file_stat.st_size ) < 0 ) 74 | { 75 | valid = false; 76 | } 77 | } 78 | else 79 | { 80 | valid = false; 81 | } 82 | } 83 | 84 | if( valid ) 85 | { 86 | ret = snprintf( header_buf, BUFFER_SIZE-1, "%s %s\r\n", "HTTP/1.1", status_line[0] ); 87 | len += ret; 88 | ret = snprintf( header_buf + len, BUFFER_SIZE-1-len, 89 | "Content-Length: %d\r\n", file_stat.st_size ); 90 | len += ret; 91 | ret = snprintf( header_buf + len, BUFFER_SIZE-1-len, "%s", "\r\n" ); 92 | struct iovec iv[2]; 93 | iv[ 0 ].iov_base = header_buf; 94 | iv[ 0 ].iov_len = strlen( header_buf ); 95 | iv[ 1 ].iov_base = file_buf; 96 | iv[ 1 ].iov_len = file_stat.st_size; 97 | ret = writev( connfd, iv, 2 ); 98 | } 99 | else 100 | { 101 | ret = snprintf( header_buf, BUFFER_SIZE-1, "%s %s\r\n", "HTTP/1.1", status_line[1] ); 102 | len += ret; 103 | ret = snprintf( header_buf + len, BUFFER_SIZE-1-len, "%s", "\r\n" ); 104 | send( connfd, header_buf, strlen( header_buf ), 0 ); 105 | } 106 | close( connfd ); 107 | delete [] file_buf; 108 | } 109 | 110 | close( sock ); 111 | return 0; 112 | } 113 | 114 | -------------------------------------------------------------------------------- /6/6-3testsendfile.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | int main( int argc, char* argv[] ) 16 | { 17 | if( argc <= 3 ) 18 | { 19 | printf( "usage: %s ip_address port_number filename\n", basename( argv[0] ) ); 20 | return 1; 21 | } 22 | const char* ip = argv[1]; 23 | int port = atoi( argv[2] ); 24 | const char* file_name = argv[3]; 25 | 26 | int filefd = open( file_name, O_RDONLY ); 27 | assert( filefd > 0 ); 28 | struct stat stat_buf; 29 | fstat( filefd, &stat_buf ); 30 | 31 | struct sockaddr_in address; 32 | bzero( &address, sizeof( address ) ); 33 | address.sin_family = AF_INET; 34 | inet_pton( AF_INET, ip, &address.sin_addr ); 35 | address.sin_port = htons( port ); 36 | 37 | int sock = socket( PF_INET, SOCK_STREAM, 0 ); 38 | assert( sock >= 0 ); 39 | 40 | int ret = bind( sock, ( struct sockaddr* )&address, sizeof( address ) ); 41 | assert( ret != -1 ); 42 | 43 | ret = listen( sock, 5 ); 44 | assert( ret != -1 ); 45 | 46 | struct sockaddr_in client; 47 | socklen_t client_addrlength = sizeof( client ); 48 | int connfd = accept( sock, ( struct sockaddr* )&client, &client_addrlength ); 49 | if ( connfd < 0 ) 50 | { 51 | printf( "errno is: %d\n", errno ); 52 | } 53 | else 54 | { 55 | sendfile( connfd, filefd, NULL, stat_buf.st_size ); 56 | close( connfd ); 57 | } 58 | 59 | close( sock ); 60 | return 0; 61 | } 62 | 63 | -------------------------------------------------------------------------------- /6/6-4testsplice.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | int main( int argc, char* argv[] ) 13 | { 14 | if( argc <= 2 ) 15 | { 16 | printf( "usage: %s ip_address port_number\n", basename( argv[0] ) ); 17 | return 1; 18 | } 19 | const char* ip = argv[1]; 20 | int port = atoi( argv[2] ); 21 | 22 | struct sockaddr_in address; 23 | bzero( &address, sizeof( address ) ); 24 | address.sin_family = AF_INET; 25 | inet_pton( AF_INET, ip, &address.sin_addr ); 26 | address.sin_port = htons( port ); 27 | 28 | int sock = socket( PF_INET, SOCK_STREAM, 0 ); 29 | assert( sock >= 0 ); 30 | 31 | int ret = bind( sock, ( struct sockaddr* )&address, sizeof( address ) ); 32 | assert( ret != -1 ); 33 | 34 | ret = listen( sock, 5 ); 35 | assert( ret != -1 ); 36 | 37 | struct sockaddr_in client; 38 | socklen_t client_addrlength = sizeof( client ); 39 | int connfd = accept( sock, ( struct sockaddr* )&client, &client_addrlength ); 40 | if ( connfd < 0 ) 41 | { 42 | printf( "errno is: %d\n", errno ); 43 | } 44 | else 45 | { 46 | int pipefd[2]; 47 | assert( ret != -1 ); 48 | ret = pipe( pipefd ); 49 | ret = splice( connfd, NULL, pipefd[1], NULL, 32768, SPLICE_F_MORE | SPLICE_F_MOVE ); 50 | assert( ret != -1 ); 51 | ret = splice( pipefd[0], NULL, connfd, NULL, 32768, SPLICE_F_MORE | SPLICE_F_MOVE ); 52 | assert( ret != -1 ); 53 | close( connfd ); 54 | } 55 | 56 | close( sock ); 57 | return 0; 58 | } 59 | 60 | -------------------------------------------------------------------------------- /6/6-5testtee.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main( int argc, char* argv[] ) 9 | { 10 | if ( argc != 2 ) 11 | { 12 | printf( "usage: %s \n", argv[0] ); 13 | return 1; 14 | } 15 | int filefd = open( argv[1], O_CREAT | O_WRONLY | O_TRUNC, 0666 ); 16 | assert( filefd > 0 ); 17 | 18 | int pipefd_stdout[2]; 19 | int ret = pipe( pipefd_stdout ); 20 | assert( ret != -1 ); 21 | 22 | int pipefd_file[2]; 23 | ret = pipe( pipefd_file ); 24 | assert( ret != -1 ); 25 | 26 | //close( STDIN_FILENO ); 27 | // dup2( pipefd_stdout[1], STDIN_FILENO ); 28 | //write( pipefd_stdout[1], "abc\n", 4 ); 29 | ret = splice( STDIN_FILENO, NULL, pipefd_stdout[1], NULL, 32768, SPLICE_F_MORE | SPLICE_F_MOVE ); 30 | assert( ret != -1 ); 31 | ret = tee( pipefd_stdout[0], pipefd_file[1], 32768, SPLICE_F_NONBLOCK ); 32 | assert( ret != -1 ); 33 | ret = splice( pipefd_file[0], NULL, filefd, NULL, 32768, SPLICE_F_MORE | SPLICE_F_MOVE ); 34 | assert( ret != -1 ); 35 | ret = splice( pipefd_stdout[0], NULL, STDOUT_FILENO, NULL, 32768, SPLICE_F_MORE | SPLICE_F_MOVE ); 36 | assert( ret != -1 ); 37 | 38 | close( filefd ); 39 | close( pipefd_stdout[0] ); 40 | close( pipefd_stdout[1] ); 41 | close( pipefd_file[0] ); 42 | close( pipefd_file[1] ); 43 | return 0; 44 | } 45 | -------------------------------------------------------------------------------- /7/7-1testeuid.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | uid_t uid = getuid(); 7 | uid_t euid = geteuid(); 8 | printf( "userid is %d, effective userid is: %d\n", uid, euid ); 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /7/7-2switchuser.cpp: -------------------------------------------------------------------------------- 1 | static bool switch_to_user( uid_t user_id, gid_t gp_id ) 2 | { 3 | if ( ( user_id == 0 ) && ( gp_id == 0 ) ) 4 | { 5 | return false; 6 | } 7 | 8 | gid_t gid = getgid(); 9 | uid_t uid = getuid(); 10 | if ( ( ( gid != 0 ) || ( uid != 0 ) ) && ( ( gid != gp_id ) || ( uid != user_id ) ) ) 11 | { 12 | return false; 13 | } 14 | 15 | if ( uid != 0 ) 16 | { 17 | return true; 18 | } 19 | 20 | if ( ( setgid( gp_id ) < 0 ) || ( setuid( user_id ) < 0 ) ) 21 | { 22 | return false; 23 | } 24 | 25 | return true; 26 | } -------------------------------------------------------------------------------- /7/7-3daemonize.cpp: -------------------------------------------------------------------------------- 1 | bool daemonize() 2 | { 3 | pid_t pid = fork(); 4 | if ( pid < 0 ) 5 | { 6 | return false; 7 | } 8 | else if ( pid > 0 ) 9 | { 10 | exit( 0 ); 11 | } 12 | 13 | umask( 0 ); 14 | 15 | pid_t sid = setsid(); 16 | if ( sid < 0 ) 17 | { 18 | return false; 19 | } 20 | 21 | if ( ( chdir( "/" ) ) < 0 ) 22 | { 23 | /* Log the failure */ 24 | return false; 25 | } 26 | 27 | close( STDIN_FILENO ); 28 | close( STDOUT_FILENO ); 29 | close( STDERR_FILENO ); 30 | 31 | open( "/dev/null", O_RDONLY ); 32 | open( "/dev/null", O_RDWR ); 33 | open( "/dev/null", O_RDWR ); 34 | return true; 35 | } -------------------------------------------------------------------------------- /8/8-3httpparser.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define BUFFER_SIZE 4096 13 | enum CHECK_STATE { CHECK_STATE_REQUESTLINE = 0, CHECK_STATE_HEADER, CHECK_STATE_CONTENT }; 14 | enum LINE_STATUS { LINE_OK = 0, LINE_BAD, LINE_OPEN }; 15 | enum HTTP_CODE { NO_REQUEST, GET_REQUEST, BAD_REQUEST, FORBIDDEN_REQUEST, INTERNAL_ERROR, CLOSED_CONNECTION }; 16 | static const char* szret[] = { "I get a correct result\n", "Something wrong\n" }; 17 | 18 | LINE_STATUS parse_line( char* buffer, int& checked_index, int& read_index ) 19 | { 20 | char temp; 21 | for ( ; checked_index < read_index; ++checked_index ) 22 | { 23 | temp = buffer[ checked_index ]; 24 | if ( temp == '\r' ) 25 | { 26 | if ( ( checked_index + 1 ) == read_index ) 27 | { 28 | return LINE_OPEN; 29 | } 30 | else if ( buffer[ checked_index + 1 ] == '\n' ) 31 | { 32 | buffer[ checked_index++ ] = '\0'; 33 | buffer[ checked_index++ ] = '\0'; 34 | return LINE_OK; 35 | } 36 | return LINE_BAD; 37 | } 38 | else if( temp == '\n' ) 39 | { 40 | if( ( checked_index > 1 ) && buffer[ checked_index - 1 ] == '\r' ) 41 | { 42 | buffer[ checked_index-1 ] = '\0'; 43 | buffer[ checked_index++ ] = '\0'; 44 | return LINE_OK; 45 | } 46 | return LINE_BAD; 47 | } 48 | } 49 | return LINE_OPEN; 50 | } 51 | 52 | HTTP_CODE parse_requestline( char* szTemp, CHECK_STATE& checkstate ) 53 | { 54 | char* szURL = strpbrk( szTemp, " \t" ); 55 | if ( ! szURL ) 56 | { 57 | return BAD_REQUEST; 58 | } 59 | *szURL++ = '\0'; 60 | 61 | char* szMethod = szTemp; 62 | if ( strcasecmp( szMethod, "GET" ) == 0 ) 63 | { 64 | printf( "The request method is GET\n" ); 65 | } 66 | else 67 | { 68 | return BAD_REQUEST; 69 | } 70 | 71 | szURL += strspn( szURL, " \t" ); 72 | char* szVersion = strpbrk( szURL, " \t" ); 73 | if ( ! szVersion ) 74 | { 75 | return BAD_REQUEST; 76 | } 77 | *szVersion++ = '\0'; 78 | szVersion += strspn( szVersion, " \t" ); 79 | if ( strcasecmp( szVersion, "HTTP/1.1" ) != 0 ) 80 | { 81 | return BAD_REQUEST; 82 | } 83 | 84 | if ( strncasecmp( szURL, "http://", 7 ) == 0 ) 85 | { 86 | szURL += 7; 87 | szURL = strchr( szURL, '/' ); 88 | } 89 | 90 | if ( ! szURL || szURL[ 0 ] != '/' ) 91 | { 92 | return BAD_REQUEST; 93 | } 94 | 95 | //URLDecode( szURL ); 96 | printf( "The request URL is: %s\n", szURL ); 97 | checkstate = CHECK_STATE_HEADER; 98 | return NO_REQUEST; 99 | } 100 | 101 | HTTP_CODE parse_headers( char* szTemp ) 102 | { 103 | if ( szTemp[ 0 ] == '\0' ) 104 | { 105 | return GET_REQUEST; 106 | } 107 | else if ( strncasecmp( szTemp, "Host:", 5 ) == 0 ) 108 | { 109 | szTemp += 5; 110 | szTemp += strspn( szTemp, " \t" ); 111 | printf( "the request host is: %s\n", szTemp ); 112 | } 113 | else 114 | { 115 | printf( "I can not handle this header\n" ); 116 | } 117 | 118 | return NO_REQUEST; 119 | } 120 | 121 | HTTP_CODE parse_content( char* buffer, int& checked_index, CHECK_STATE& checkstate, int& read_index, int& start_line ) 122 | { 123 | LINE_STATUS linestatus = LINE_OK; 124 | HTTP_CODE retcode = NO_REQUEST; 125 | while( ( linestatus = parse_line( buffer, checked_index, read_index ) ) == LINE_OK ) 126 | { 127 | char* szTemp = buffer + start_line; 128 | start_line = checked_index; 129 | switch ( checkstate ) 130 | { 131 | case CHECK_STATE_REQUESTLINE: 132 | { 133 | retcode = parse_requestline( szTemp, checkstate ); 134 | if ( retcode == BAD_REQUEST ) 135 | { 136 | return BAD_REQUEST; 137 | } 138 | break; 139 | } 140 | case CHECK_STATE_HEADER: 141 | { 142 | retcode = parse_headers( szTemp ); 143 | if ( retcode == BAD_REQUEST ) 144 | { 145 | return BAD_REQUEST; 146 | } 147 | else if ( retcode == GET_REQUEST ) 148 | { 149 | return GET_REQUEST; 150 | } 151 | break; 152 | } 153 | default: 154 | { 155 | return INTERNAL_ERROR; 156 | } 157 | } 158 | } 159 | if( linestatus == LINE_OPEN ) 160 | { 161 | return NO_REQUEST; 162 | } 163 | else 164 | { 165 | return BAD_REQUEST; 166 | } 167 | } 168 | 169 | int main( int argc, char* argv[] ) 170 | { 171 | if( argc <= 2 ) 172 | { 173 | printf( "usage: %s ip_address port_number\n", basename( argv[0] ) ); 174 | return 1; 175 | } 176 | const char* ip = argv[1]; 177 | int port = atoi( argv[2] ); 178 | 179 | struct sockaddr_in address; 180 | bzero( &address, sizeof( address ) ); 181 | address.sin_family = AF_INET; 182 | inet_pton( AF_INET, ip, &address.sin_addr ); 183 | address.sin_port = htons( port ); 184 | 185 | int listenfd = socket( PF_INET, SOCK_STREAM, 0 ); 186 | assert( listenfd >= 0 ); 187 | 188 | int ret = bind( listenfd, ( struct sockaddr* )&address, sizeof( address ) ); 189 | assert( ret != -1 ); 190 | 191 | ret = listen( listenfd, 5 ); 192 | assert( ret != -1 ); 193 | 194 | struct sockaddr_in client_address; 195 | socklen_t client_addrlength = sizeof( client_address ); 196 | int fd = accept( listenfd, ( struct sockaddr* )&client_address, &client_addrlength ); 197 | if( fd < 0 ) 198 | { 199 | printf( "errno is: %d\n", errno ); 200 | } 201 | else 202 | { 203 | char buffer[ BUFFER_SIZE ]; 204 | memset( buffer, '\0', BUFFER_SIZE ); 205 | int data_read = 0; 206 | int read_index = 0; 207 | int checked_index = 0; 208 | int start_line = 0; 209 | CHECK_STATE checkstate = CHECK_STATE_REQUESTLINE; 210 | while( 1 ) 211 | { 212 | data_read = recv( fd, buffer + read_index, BUFFER_SIZE - read_index, 0 ); 213 | if ( data_read == -1 ) 214 | { 215 | printf( "reading failed\n" ); 216 | break; 217 | } 218 | else if ( data_read == 0 ) 219 | { 220 | printf( "remote client has closed the connection\n" ); 221 | break; 222 | } 223 | 224 | read_index += data_read; 225 | HTTP_CODE result = parse_content( buffer, checked_index, checkstate, read_index, start_line ); 226 | if( result == NO_REQUEST ) 227 | { 228 | continue; 229 | } 230 | else if( result == GET_REQUEST ) 231 | { 232 | send( fd, szret[0], strlen( szret[0] ), 0 ); 233 | break; 234 | } 235 | else 236 | { 237 | send( fd, szret[1], strlen( szret[1] ), 0 ); 238 | break; 239 | } 240 | } 241 | close( fd ); 242 | } 243 | 244 | close( listenfd ); 245 | return 0; 246 | } 247 | -------------------------------------------------------------------------------- /9/9-1use_select.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | int main( int argc, char* argv[] ) 14 | { 15 | if( argc <= 2 ) 16 | { 17 | printf( "usage: %s ip_address port_number\n", basename( argv[0] ) ); 18 | return 1; 19 | } 20 | const char* ip = argv[1]; 21 | int port = atoi( argv[2] ); 22 | printf( "ip is %s and port is %d\n", ip, port ); 23 | 24 | int ret = 0; 25 | struct sockaddr_in address; 26 | bzero( &address, sizeof( address ) ); 27 | address.sin_family = AF_INET; 28 | inet_pton( AF_INET, ip, &address.sin_addr ); 29 | address.sin_port = htons( port ); 30 | 31 | int listenfd = socket( PF_INET, SOCK_STREAM, 0 ); 32 | assert( listenfd >= 0 ); 33 | 34 | ret = bind( listenfd, ( struct sockaddr* )&address, sizeof( address ) ); 35 | assert( ret != -1 ); 36 | 37 | ret = listen( listenfd, 5 ); 38 | assert( ret != -1 ); 39 | 40 | struct sockaddr_in client_address; 41 | socklen_t client_addrlength = sizeof( client_address ); 42 | int connfd = accept( listenfd, ( struct sockaddr* )&client_address, &client_addrlength ); 43 | if ( connfd < 0 ) 44 | { 45 | printf( "errno is: %d\n", errno ); 46 | close( listenfd ); 47 | } 48 | 49 | char remote_addr[INET_ADDRSTRLEN]; 50 | printf( "connected with ip: %s and port: %d\n", inet_ntop( AF_INET, &client_address.sin_addr, remote_addr, INET_ADDRSTRLEN ), ntohs( client_address.sin_port ) ); 51 | 52 | char buf[1024]; 53 | fd_set read_fds; 54 | fd_set exception_fds; 55 | 56 | FD_ZERO( &read_fds ); 57 | FD_ZERO( &exception_fds ); 58 | 59 | int nReuseAddr = 1; 60 | setsockopt( connfd, SOL_SOCKET, SO_OOBINLINE, &nReuseAddr, sizeof( nReuseAddr ) ); 61 | while( 1 ) 62 | { 63 | memset( buf, '\0', sizeof( buf ) ); 64 | FD_SET( connfd, &read_fds ); 65 | FD_SET( connfd, &exception_fds ); 66 | 67 | ret = select( connfd + 1, &read_fds, NULL, &exception_fds, NULL ); 68 | printf( "select one\n" ); 69 | if ( ret < 0 ) 70 | { 71 | printf( "selection failure\n" ); 72 | break; 73 | } 74 | 75 | if ( FD_ISSET( connfd, &read_fds ) ) 76 | { 77 | ret = recv( connfd, buf, sizeof( buf )-1, 0 ); 78 | if( ret <= 0 ) 79 | { 80 | break; 81 | } 82 | printf( "get %d bytes of normal data: %s\n", ret, buf ); 83 | } 84 | else if( FD_ISSET( connfd, &exception_fds ) ) 85 | { 86 | ret = recv( connfd, buf, sizeof( buf )-1, MSG_OOB ); 87 | if( ret <= 0 ) 88 | { 89 | break; 90 | } 91 | printf( "get %d bytes of oob data: %s\n", ret, buf ); 92 | } 93 | 94 | } 95 | 96 | close( connfd ); 97 | close( listenfd ); 98 | return 0; 99 | } 100 | -------------------------------------------------------------------------------- /9/9-3mtlt.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #define MAX_EVENT_NUMBER 1024 16 | #define BUFFER_SIZE 10 17 | 18 | int setnonblocking( int fd ) 19 | { 20 | int old_option = fcntl( fd, F_GETFL ); 21 | int new_option = old_option | O_NONBLOCK; 22 | fcntl( fd, F_SETFL, new_option ); 23 | return old_option; 24 | } 25 | 26 | void addfd( int epollfd, int fd, bool enable_et ) 27 | { 28 | epoll_event event; 29 | event.data.fd = fd; 30 | event.events = EPOLLIN; 31 | if( enable_et ) 32 | { 33 | event.events |= EPOLLET; 34 | } 35 | epoll_ctl( epollfd, EPOLL_CTL_ADD, fd, &event ); 36 | setnonblocking( fd ); 37 | } 38 | 39 | void lt( epoll_event* events, int number, int epollfd, int listenfd ) 40 | { 41 | char buf[ BUFFER_SIZE ]; 42 | for ( int i = 0; i < number; i++ ) 43 | { 44 | int sockfd = events[i].data.fd; 45 | if ( sockfd == listenfd ) 46 | { 47 | struct sockaddr_in client_address; 48 | socklen_t client_addrlength = sizeof( client_address ); 49 | int connfd = accept( listenfd, ( struct sockaddr* )&client_address, &client_addrlength ); 50 | addfd( epollfd, connfd, false ); 51 | } 52 | else if ( events[i].events & EPOLLIN ) 53 | { 54 | printf( "event trigger once\n" ); 55 | memset( buf, '\0', BUFFER_SIZE ); 56 | int ret = recv( sockfd, buf, BUFFER_SIZE-1, 0 ); 57 | if( ret <= 0 ) 58 | { 59 | close( sockfd ); 60 | continue; 61 | } 62 | printf( "get %d bytes of content: %s\n", ret, buf ); 63 | } 64 | else 65 | { 66 | printf( "something else happened \n" ); 67 | } 68 | } 69 | } 70 | 71 | void et( epoll_event* events, int number, int epollfd, int listenfd ) 72 | { 73 | char buf[ BUFFER_SIZE ]; 74 | for ( int i = 0; i < number; i++ ) 75 | { 76 | int sockfd = events[i].data.fd; 77 | if ( sockfd == listenfd ) 78 | { 79 | struct sockaddr_in client_address; 80 | socklen_t client_addrlength = sizeof( client_address ); 81 | int connfd = accept( listenfd, ( struct sockaddr* )&client_address, &client_addrlength ); 82 | addfd( epollfd, connfd, true ); 83 | } 84 | else if ( events[i].events & EPOLLIN ) 85 | { 86 | printf( "event trigger once\n" ); 87 | while( 1 ) 88 | { 89 | memset( buf, '\0', BUFFER_SIZE ); 90 | int ret = recv( sockfd, buf, BUFFER_SIZE-1, 0 ); 91 | if( ret < 0 ) 92 | { 93 | if( ( errno == EAGAIN ) || ( errno == EWOULDBLOCK ) ) 94 | { 95 | printf( "read later\n" ); 96 | break; 97 | } 98 | close( sockfd ); 99 | break; 100 | } 101 | else if( ret == 0 ) 102 | { 103 | close( sockfd ); 104 | } 105 | else 106 | { 107 | printf( "get %d bytes of content: %s\n", ret, buf ); 108 | } 109 | } 110 | } 111 | else 112 | { 113 | printf( "something else happened \n" ); 114 | } 115 | } 116 | } 117 | 118 | int main( int argc, char* argv[] ) 119 | { 120 | if( argc <= 2 ) 121 | { 122 | printf( "usage: %s ip_address port_number\n", basename( argv[0] ) ); 123 | return 1; 124 | } 125 | const char* ip = argv[1]; 126 | int port = atoi( argv[2] ); 127 | 128 | int ret = 0; 129 | struct sockaddr_in address; 130 | bzero( &address, sizeof( address ) ); 131 | address.sin_family = AF_INET; 132 | inet_pton( AF_INET, ip, &address.sin_addr ); 133 | address.sin_port = htons( port ); 134 | 135 | int listenfd = socket( PF_INET, SOCK_STREAM, 0 ); 136 | assert( listenfd >= 0 ); 137 | 138 | ret = bind( listenfd, ( struct sockaddr* )&address, sizeof( address ) ); 139 | assert( ret != -1 ); 140 | 141 | ret = listen( listenfd, 5 ); 142 | assert( ret != -1 ); 143 | 144 | epoll_event events[ MAX_EVENT_NUMBER ]; 145 | int epollfd = epoll_create( 5 ); 146 | assert( epollfd != -1 ); 147 | addfd( epollfd, listenfd, true ); 148 | 149 | while( 1 ) 150 | { 151 | int ret = epoll_wait( epollfd, events, MAX_EVENT_NUMBER, -1 ); 152 | if ( ret < 0 ) 153 | { 154 | printf( "epoll failure\n" ); 155 | break; 156 | } 157 | 158 | lt( events, ret, epollfd, listenfd ); 159 | //et( events, ret, epollfd, listenfd ); 160 | } 161 | 162 | close( listenfd ); 163 | return 0; 164 | } 165 | -------------------------------------------------------------------------------- /9/9-4oneshot.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #define MAX_EVENT_NUMBER 1024 16 | #define BUFFER_SIZE 1024 17 | struct fds 18 | { 19 | int epollfd; 20 | int sockfd; 21 | }; 22 | 23 | int setnonblocking( int fd ) 24 | { 25 | int old_option = fcntl( fd, F_GETFL ); 26 | int new_option = old_option | O_NONBLOCK; 27 | fcntl( fd, F_SETFL, new_option ); 28 | return old_option; 29 | } 30 | 31 | void addfd( int epollfd, int fd, bool oneshot ) 32 | { 33 | epoll_event event; 34 | event.data.fd = fd; 35 | event.events = EPOLLIN | EPOLLET; 36 | if( oneshot ) 37 | { 38 | event.events |= EPOLLONESHOT; 39 | } 40 | epoll_ctl( epollfd, EPOLL_CTL_ADD, fd, &event ); 41 | setnonblocking( fd ); 42 | } 43 | 44 | void reset_oneshot( int epollfd, int fd ) 45 | { 46 | epoll_event event; 47 | event.data.fd = fd; 48 | event.events = EPOLLIN | EPOLLET | EPOLLONESHOT; 49 | epoll_ctl( epollfd, EPOLL_CTL_MOD, fd, &event ); 50 | } 51 | 52 | void* worker( void* arg ) 53 | { 54 | int sockfd = ( (fds*)arg )->sockfd; 55 | int epollfd = ( (fds*)arg )->epollfd; 56 | printf( "start new thread to receive data on fd: %d\n", sockfd ); 57 | char buf[ BUFFER_SIZE ]; 58 | memset( buf, '\0', BUFFER_SIZE ); 59 | while( 1 ) 60 | { 61 | int ret = recv( sockfd, buf, BUFFER_SIZE-1, 0 ); 62 | if( ret == 0 ) 63 | { 64 | close( sockfd ); 65 | printf( "foreiner closed the connection\n" ); 66 | break; 67 | } 68 | else if( ret < 0 ) 69 | { 70 | if( errno == EAGAIN ) 71 | { 72 | reset_oneshot( epollfd, sockfd ); 73 | printf( "read later\n" ); 74 | break; 75 | } 76 | } 77 | else 78 | { 79 | printf( "get content: %s\n", buf ); 80 | sleep( 5 ); 81 | } 82 | } 83 | printf( "end thread receiving data on fd: %d\n", sockfd ); 84 | } 85 | 86 | int main( int argc, char* argv[] ) 87 | { 88 | if( argc <= 2 ) 89 | { 90 | printf( "usage: %s ip_address port_number\n", basename( argv[0] ) ); 91 | return 1; 92 | } 93 | const char* ip = argv[1]; 94 | int port = atoi( argv[2] ); 95 | 96 | int ret = 0; 97 | struct sockaddr_in address; 98 | bzero( &address, sizeof( address ) ); 99 | address.sin_family = AF_INET; 100 | inet_pton( AF_INET, ip, &address.sin_addr ); 101 | address.sin_port = htons( port ); 102 | 103 | int listenfd = socket( PF_INET, SOCK_STREAM, 0 ); 104 | assert( listenfd >= 0 ); 105 | 106 | ret = bind( listenfd, ( struct sockaddr* )&address, sizeof( address ) ); 107 | assert( ret != -1 ); 108 | 109 | ret = listen( listenfd, 5 ); 110 | assert( ret != -1 ); 111 | 112 | epoll_event events[ MAX_EVENT_NUMBER ]; 113 | int epollfd = epoll_create( 5 ); 114 | assert( epollfd != -1 ); 115 | addfd( epollfd, listenfd, false ); 116 | 117 | while( 1 ) 118 | { 119 | int ret = epoll_wait( epollfd, events, MAX_EVENT_NUMBER, -1 ); 120 | if ( ret < 0 ) 121 | { 122 | printf( "epoll failure\n" ); 123 | break; 124 | } 125 | 126 | for ( int i = 0; i < ret; i++ ) 127 | { 128 | int sockfd = events[i].data.fd; 129 | if ( sockfd == listenfd ) 130 | { 131 | struct sockaddr_in client_address; 132 | socklen_t client_addrlength = sizeof( client_address ); 133 | int connfd = accept( listenfd, ( struct sockaddr* )&client_address, &client_addrlength ); 134 | addfd( epollfd, connfd, true ); 135 | } 136 | else if ( events[i].events & EPOLLIN ) 137 | { 138 | pthread_t thread; 139 | fds fds_for_new_worker; 140 | fds_for_new_worker.epollfd = epollfd; 141 | fds_for_new_worker.sockfd = sockfd; 142 | pthread_create( &thread, NULL, worker, ( void* )&fds_for_new_worker ); 143 | } 144 | else 145 | { 146 | printf( "something else happened \n" ); 147 | } 148 | } 149 | } 150 | 151 | close( listenfd ); 152 | return 0; 153 | } 154 | -------------------------------------------------------------------------------- /9/9-5unblockconnect.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #define BUFFER_SIZE 1023 16 | 17 | int setnonblocking( int fd ) 18 | { 19 | int old_option = fcntl( fd, F_GETFL ); 20 | int new_option = old_option | O_NONBLOCK; 21 | fcntl( fd, F_SETFL, new_option ); 22 | return old_option; 23 | } 24 | 25 | int unblock_connect( const char* ip, int port, int time ) 26 | { 27 | int ret = 0; 28 | struct sockaddr_in address; 29 | bzero( &address, sizeof( address ) ); 30 | address.sin_family = AF_INET; 31 | inet_pton( AF_INET, ip, &address.sin_addr ); 32 | address.sin_port = htons( port ); 33 | 34 | int sockfd = socket( PF_INET, SOCK_STREAM, 0 ); 35 | int fdopt = setnonblocking( sockfd ); 36 | ret = connect( sockfd, ( struct sockaddr* )&address, sizeof( address ) ); 37 | if ( ret == 0 ) 38 | { 39 | printf( "connect with server immediately\n" ); 40 | fcntl( sockfd, F_SETFL, fdopt ); 41 | return sockfd; 42 | } 43 | else if ( errno != EINPROGRESS ) 44 | { 45 | printf( "unblock connect not support\n" ); 46 | return -1; 47 | } 48 | 49 | fd_set readfds; 50 | fd_set writefds; 51 | struct timeval timeout; 52 | 53 | FD_ZERO( &readfds ); 54 | FD_SET( sockfd, &writefds ); 55 | 56 | timeout.tv_sec = time; 57 | timeout.tv_usec = 0; 58 | 59 | ret = select( sockfd + 1, NULL, &writefds, NULL, &timeout ); 60 | if ( ret <= 0 ) 61 | { 62 | printf( "connection time out\n" ); 63 | close( sockfd ); 64 | return -1; 65 | } 66 | 67 | if ( ! FD_ISSET( sockfd, &writefds ) ) 68 | { 69 | printf( "no events on sockfd found\n" ); 70 | close( sockfd ); 71 | return -1; 72 | } 73 | 74 | int error = 0; 75 | socklen_t length = sizeof( error ); 76 | if( getsockopt( sockfd, SOL_SOCKET, SO_ERROR, &error, &length ) < 0 ) 77 | { 78 | printf( "get socket option failed\n" ); 79 | close( sockfd ); 80 | return -1; 81 | } 82 | 83 | if( error != 0 ) 84 | { 85 | printf( "connection failed after select with the error: %d \n", error ); 86 | close( sockfd ); 87 | return -1; 88 | } 89 | 90 | printf( "connection ready after select with the socket: %d \n", sockfd ); 91 | fcntl( sockfd, F_SETFL, fdopt ); 92 | return sockfd; 93 | } 94 | 95 | int main( int argc, char* argv[] ) 96 | { 97 | if( argc <= 2 ) 98 | { 99 | printf( "usage: %s ip_address port_number\n", basename( argv[0] ) ); 100 | return 1; 101 | } 102 | const char* ip = argv[1]; 103 | int port = atoi( argv[2] ); 104 | 105 | int sockfd = unblock_connect( ip, port, 10 ); 106 | if ( sockfd < 0 ) 107 | { 108 | return 1; 109 | } 110 | shutdown( sockfd, SHUT_WR ); 111 | sleep( 200 ); 112 | printf( "send data out\n" ); 113 | send( sockfd, "abc", 3, 0 ); 114 | //sleep( 600 ); 115 | return 0; 116 | } 117 | -------------------------------------------------------------------------------- /9/9-6mytalk_client.cpp: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 1 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #define BUFFER_SIZE 64 15 | 16 | int main( int argc, char* argv[] ) 17 | { 18 | if( argc <= 2 ) 19 | { 20 | printf( "usage: %s ip_address port_number\n", basename( argv[0] ) ); 21 | return 1; 22 | } 23 | const char* ip = argv[1]; 24 | int port = atoi( argv[2] ); 25 | 26 | struct sockaddr_in server_address; 27 | bzero( &server_address, sizeof( server_address ) ); 28 | server_address.sin_family = AF_INET; 29 | inet_pton( AF_INET, ip, &server_address.sin_addr ); 30 | server_address.sin_port = htons( port ); 31 | 32 | int sockfd = socket( PF_INET, SOCK_STREAM, 0 ); 33 | assert( sockfd >= 0 ); 34 | if ( connect( sockfd, ( struct sockaddr* )&server_address, sizeof( server_address ) ) < 0 ) 35 | { 36 | printf( "connection failed\n" ); 37 | close( sockfd ); 38 | return 1; 39 | } 40 | 41 | pollfd fds[2]; 42 | fds[0].fd = 0; 43 | fds[0].events = POLLIN; 44 | fds[0].revents = 0; 45 | fds[1].fd = sockfd; 46 | fds[1].events = POLLIN | POLLRDHUP; 47 | fds[1].revents = 0; 48 | char read_buf[BUFFER_SIZE]; 49 | int pipefd[2]; 50 | int ret = pipe( pipefd ); 51 | assert( ret != -1 ); 52 | 53 | while( 1 ) 54 | { 55 | ret = poll( fds, 2, -1 ); 56 | if( ret < 0 ) 57 | { 58 | printf( "poll failure\n" ); 59 | break; 60 | } 61 | 62 | if( fds[1].revents & POLLRDHUP ) 63 | { 64 | printf( "server close the connection\n" ); 65 | break; 66 | } 67 | else if( fds[1].revents & POLLIN ) 68 | { 69 | memset( read_buf, '\0', BUFFER_SIZE ); 70 | recv( fds[1].fd, read_buf, BUFFER_SIZE-1, 0 ); 71 | printf( "%s\n", read_buf ); 72 | } 73 | 74 | if( fds[0].revents & POLLIN ) 75 | { 76 | ret = splice( 0, NULL, pipefd[1], NULL, 32768, SPLICE_F_MORE | SPLICE_F_MOVE ); 77 | ret = splice( pipefd[0], NULL, sockfd, NULL, 32768, SPLICE_F_MORE | SPLICE_F_MOVE ); 78 | } 79 | } 80 | 81 | close( sockfd ); 82 | return 0; 83 | } 84 | -------------------------------------------------------------------------------- /9/9-7mytalk_server.cpp: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 1 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #define USER_LIMIT 5 16 | #define BUFFER_SIZE 64 17 | #define FD_LIMIT 65535 18 | 19 | struct client_data 20 | { 21 | sockaddr_in address; 22 | char* write_buf; 23 | char buf[ BUFFER_SIZE ]; 24 | }; 25 | 26 | int setnonblocking( int fd ) 27 | { 28 | int old_option = fcntl( fd, F_GETFL ); 29 | int new_option = old_option | O_NONBLOCK; 30 | fcntl( fd, F_SETFL, new_option ); 31 | return old_option; 32 | } 33 | 34 | int main( int argc, char* argv[] ) 35 | { 36 | if( argc <= 2 ) 37 | { 38 | printf( "usage: %s ip_address port_number\n", basename( argv[0] ) ); 39 | return 1; 40 | } 41 | const char* ip = argv[1]; 42 | int port = atoi( argv[2] ); 43 | 44 | int ret = 0; 45 | struct sockaddr_in address; 46 | bzero( &address, sizeof( address ) ); 47 | address.sin_family = AF_INET; 48 | inet_pton( AF_INET, ip, &address.sin_addr ); 49 | address.sin_port = htons( port ); 50 | 51 | int listenfd = socket( PF_INET, SOCK_STREAM, 0 ); 52 | assert( listenfd >= 0 ); 53 | 54 | ret = bind( listenfd, ( struct sockaddr* )&address, sizeof( address ) ); 55 | assert( ret != -1 ); 56 | 57 | ret = listen( listenfd, 5 ); 58 | assert( ret != -1 ); 59 | 60 | client_data* users = new client_data[FD_LIMIT]; 61 | pollfd fds[USER_LIMIT+1]; 62 | int user_counter = 0; 63 | for( int i = 1; i <= USER_LIMIT; ++i ) 64 | { 65 | fds[i].fd = -1; 66 | fds[i].events = 0; 67 | } 68 | fds[0].fd = listenfd; 69 | fds[0].events = POLLIN | POLLERR; 70 | fds[0].revents = 0; 71 | 72 | while( 1 ) 73 | { 74 | ret = poll( fds, user_counter+1, -1 ); 75 | if ( ret < 0 ) 76 | { 77 | printf( "poll failure\n" ); 78 | break; 79 | } 80 | 81 | for( int i = 0; i < user_counter+1; ++i ) 82 | { 83 | if( ( fds[i].fd == listenfd ) && ( fds[i].revents & POLLIN ) ) 84 | { 85 | struct sockaddr_in client_address; 86 | socklen_t client_addrlength = sizeof( client_address ); 87 | int connfd = accept( listenfd, ( struct sockaddr* )&client_address, &client_addrlength ); 88 | if ( connfd < 0 ) 89 | { 90 | printf( "errno is: %d\n", errno ); 91 | continue; 92 | } 93 | if( user_counter >= USER_LIMIT ) 94 | { 95 | const char* info = "too many users\n"; 96 | printf( "%s", info ); 97 | send( connfd, info, strlen( info ), 0 ); 98 | close( connfd ); 99 | continue; 100 | } 101 | user_counter++; 102 | users[connfd].address = client_address; 103 | setnonblocking( connfd ); 104 | fds[user_counter].fd = connfd; 105 | fds[user_counter].events = POLLIN | POLLRDHUP | POLLERR; 106 | fds[user_counter].revents = 0; 107 | printf( "comes a new user, now have %d users\n", user_counter ); 108 | } 109 | else if( fds[i].revents & POLLERR ) 110 | { 111 | printf( "get an error from %d\n", fds[i].fd ); 112 | char errors[ 100 ]; 113 | memset( errors, '\0', 100 ); 114 | socklen_t length = sizeof( errors ); 115 | if( getsockopt( fds[i].fd, SOL_SOCKET, SO_ERROR, &errors, &length ) < 0 ) 116 | { 117 | printf( "get socket option failed\n" ); 118 | } 119 | continue; 120 | } 121 | else if( fds[i].revents & POLLRDHUP ) 122 | { 123 | users[fds[i].fd] = users[fds[user_counter].fd]; 124 | close( fds[i].fd ); 125 | fds[i] = fds[user_counter]; 126 | i--; 127 | user_counter--; 128 | printf( "a client left\n" ); 129 | } 130 | else if( fds[i].revents & POLLIN ) 131 | { 132 | int connfd = fds[i].fd; 133 | memset( users[connfd].buf, '\0', BUFFER_SIZE ); 134 | ret = recv( connfd, users[connfd].buf, BUFFER_SIZE-1, 0 ); 135 | printf( "get %d bytes of client data %s from %d\n", ret, users[connfd].buf, connfd ); 136 | if( ret < 0 ) 137 | { 138 | if( errno != EAGAIN ) 139 | { 140 | close( connfd ); 141 | users[fds[i].fd] = users[fds[user_counter].fd]; 142 | fds[i] = fds[user_counter]; 143 | i--; 144 | user_counter--; 145 | } 146 | } 147 | else if( ret == 0 ) 148 | { 149 | printf( "code should not come to here\n" ); 150 | } 151 | else 152 | { 153 | for( int j = 1; j <= user_counter; ++j ) 154 | { 155 | if( fds[j].fd == connfd ) 156 | { 157 | continue; 158 | } 159 | 160 | fds[j].events |= ~POLLIN; 161 | fds[j].events |= POLLOUT; 162 | users[fds[j].fd].write_buf = users[connfd].buf; 163 | } 164 | } 165 | } 166 | else if( fds[i].revents & POLLOUT ) 167 | { 168 | int connfd = fds[i].fd; 169 | if( ! users[connfd].write_buf ) 170 | { 171 | continue; 172 | } 173 | ret = send( connfd, users[connfd].write_buf, strlen( users[connfd].write_buf ), 0 ); 174 | users[connfd].write_buf = NULL; 175 | fds[i].events |= ~POLLOUT; 176 | fds[i].events |= POLLIN; 177 | } 178 | } 179 | } 180 | 181 | delete [] users; 182 | close( listenfd ); 183 | return 0; 184 | } 185 | -------------------------------------------------------------------------------- /9/9-8multi_port.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #define MAX_EVENT_NUMBER 1024 16 | #define TCP_BUFFER_SIZE 512 17 | #define UDP_BUFFER_SIZE 1024 18 | 19 | int setnonblocking( int fd ) 20 | { 21 | int old_option = fcntl( fd, F_GETFL ); 22 | int new_option = old_option | O_NONBLOCK; 23 | fcntl( fd, F_SETFL, new_option ); 24 | return old_option; 25 | } 26 | 27 | void addfd( int epollfd, int fd ) 28 | { 29 | epoll_event event; 30 | event.data.fd = fd; 31 | //event.events = EPOLLIN | EPOLLET; 32 | event.events = EPOLLIN; 33 | epoll_ctl( epollfd, EPOLL_CTL_ADD, fd, &event ); 34 | setnonblocking( fd ); 35 | } 36 | 37 | int main( int argc, char* argv[] ) 38 | { 39 | if( argc <= 2 ) 40 | { 41 | printf( "usage: %s ip_address port_number\n", basename( argv[0] ) ); 42 | return 1; 43 | } 44 | const char* ip = argv[1]; 45 | int port = atoi( argv[2] ); 46 | 47 | int ret = 0; 48 | struct sockaddr_in address; 49 | bzero( &address, sizeof( address ) ); 50 | address.sin_family = AF_INET; 51 | inet_pton( AF_INET, ip, &address.sin_addr ); 52 | address.sin_port = htons( port ); 53 | 54 | int listenfd = socket( PF_INET, SOCK_STREAM, 0 ); 55 | assert( listenfd >= 0 ); 56 | 57 | ret = bind( listenfd, ( struct sockaddr* )&address, sizeof( address ) ); 58 | assert( ret != -1 ); 59 | 60 | ret = listen( listenfd, 5 ); 61 | assert( ret != -1 ); 62 | 63 | bzero( &address, sizeof( address ) ); 64 | address.sin_family = AF_INET; 65 | inet_pton( AF_INET, ip, &address.sin_addr ); 66 | address.sin_port = htons( port ); 67 | int udpfd = socket( PF_INET, SOCK_DGRAM, 0 ); 68 | assert( udpfd >= 0 ); 69 | 70 | ret = bind( udpfd, ( struct sockaddr* )&address, sizeof( address ) ); 71 | assert( ret != -1 ); 72 | 73 | epoll_event events[ MAX_EVENT_NUMBER ]; 74 | int epollfd = epoll_create( 5 ); 75 | assert( epollfd != -1 ); 76 | addfd( epollfd, listenfd ); 77 | addfd( epollfd, udpfd ); 78 | 79 | while( 1 ) 80 | { 81 | int number = epoll_wait( epollfd, events, MAX_EVENT_NUMBER, -1 ); 82 | if ( number < 0 ) 83 | { 84 | printf( "epoll failure\n" ); 85 | break; 86 | } 87 | 88 | for ( int i = 0; i < number; i++ ) 89 | { 90 | int sockfd = events[i].data.fd; 91 | if ( sockfd == listenfd ) 92 | { 93 | struct sockaddr_in client_address; 94 | socklen_t client_addrlength = sizeof( client_address ); 95 | int connfd = accept( listenfd, ( struct sockaddr* )&client_address, &client_addrlength ); 96 | addfd( epollfd, connfd ); 97 | } 98 | else if ( sockfd == udpfd ) 99 | { 100 | char buf[ UDP_BUFFER_SIZE ]; 101 | memset( buf, '\0', UDP_BUFFER_SIZE ); 102 | struct sockaddr_in client_address; 103 | socklen_t client_addrlength = sizeof( client_address ); 104 | 105 | ret = recvfrom( udpfd, buf, UDP_BUFFER_SIZE-1, 0, ( struct sockaddr* )&client_address, &client_addrlength ); 106 | if( ret > 0 ) 107 | { 108 | sendto( udpfd, buf, UDP_BUFFER_SIZE-1, 0, ( struct sockaddr* )&client_address, client_addrlength ); 109 | } 110 | } 111 | else if ( events[i].events & EPOLLIN ) 112 | { 113 | char buf[ TCP_BUFFER_SIZE ]; 114 | while( 1 ) 115 | { 116 | memset( buf, '\0', TCP_BUFFER_SIZE ); 117 | ret = recv( sockfd, buf, TCP_BUFFER_SIZE-1, 0 ); 118 | if( ret < 0 ) 119 | { 120 | if( ( errno == EAGAIN ) || ( errno == EWOULDBLOCK ) ) 121 | { 122 | break; 123 | } 124 | close( sockfd ); 125 | break; 126 | } 127 | else if( ret == 0 ) 128 | { 129 | close( sockfd ); 130 | } 131 | else 132 | { 133 | send( sockfd, buf, ret, 0 ); 134 | } 135 | } 136 | } 137 | else 138 | { 139 | printf( "something else happened \n" ); 140 | } 141 | } 142 | } 143 | 144 | close( listenfd ); 145 | return 0; 146 | } 147 | -------------------------------------------------------------------------------- /9/9-8multi_port.cpp.bak: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #define MAX_EVENT_NUMBER 1024 16 | #define TCP_BUFFER_SIZE 512 17 | #define UDP_BUFFER_SIZE 1024 18 | 19 | int setnonblocking( int fd ) 20 | { 21 | int old_option = fcntl( fd, F_GETFL ); 22 | int new_option = old_option | O_NONBLOCK; 23 | fcntl( fd, F_SETFL, new_option ); 24 | return old_option; 25 | } 26 | 27 | void addfd( int epollfd, int fd ) 28 | { 29 | epoll_event event; 30 | event.data.fd = fd; 31 | //event.events = EPOLLIN | EPOLLET; 32 | event.events = EPOLLIN; 33 | epoll_ctl( epollfd, EPOLL_CTL_ADD, fd, &event ); 34 | setnonblocking( fd ); 35 | } 36 | 37 | int main( int argc, char* argv[] ) 38 | { 39 | if( argc <= 2 ) 40 | { 41 | printf( "usage: %s ip_address port_number\n", basename( argv[0] ) ); 42 | return 1; 43 | } 44 | const char* ip = argv[1]; 45 | int port = atoi( argv[2] ); 46 | 47 | int ret = 0; 48 | struct sockaddr_in address; 49 | bzero( &address, sizeof( address ) ); 50 | address.sin_family = AF_INET; 51 | inet_pton( AF_INET, ip, &address.sin_addr ); 52 | address.sin_port = htons( port ); 53 | 54 | int listenfd = socket( PF_INET, SOCK_STREAM, 0 ); 55 | assert( listenfd >= 0 ); 56 | 57 | ret = bind( listenfd, ( struct sockaddr* )&address, sizeof( address ) ); 58 | assert( ret != -1 ); 59 | 60 | ret = listen( listenfd, 5 ); 61 | assert( ret != -1 ); 62 | 63 | bzero( &address, sizeof( address ) ); 64 | address.sin_family = AF_INET; 65 | inet_pton( AF_INET, ip, &address.sin_addr ); 66 | address.sin_port = htons( port ); 67 | int udpfd = socket( PF_INET, SOCK_DGRAM, 0 ); 68 | assert( udpfd >= 0 ); 69 | 70 | ret = bind( udpfd, ( struct sockaddr* )&address, sizeof( address ) ); 71 | assert( ret != -1 ); 72 | 73 | epoll_event events[ MAX_EVENT_NUMBER ]; 74 | int epollfd = epoll_create( 5 ); 75 | assert( epollfd != -1 ); 76 | addfd( epollfd, listenfd ); 77 | addfd( epollfd, udpfd ); 78 | 79 | while( 1 ) 80 | { 81 | int number = epoll_wait( epollfd, events, MAX_EVENT_NUMBER, -1 ); 82 | if ( number < 0 ) 83 | { 84 | printf( "epoll failure\n" ); 85 | break; 86 | } 87 | 88 | for ( int i = 0; i < number; i++ ) 89 | { 90 | int sockfd = events[i].data.fd; 91 | if ( sockfd == listenfd ) 92 | { 93 | struct sockaddr_in client_address; 94 | socklen_t client_addrlength = sizeof( client_address ); 95 | int connfd = accept( listenfd, ( struct sockaddr* )&client_address, &client_addrlength ); 96 | addfd( epollfd, connfd ); 97 | } 98 | else if ( sockfd == udpfd ) 99 | { 100 | char buf[ UDP_BUFFER_SIZE ]; 101 | memset( buf, '\0', UDP_BUFFER_SIZE ); 102 | struct sockaddr_in client_address; 103 | socklen_t client_addrlength = sizeof( client_address ); 104 | 105 | ret = recvfrom( udpfd, buf, UDP_BUFFER_SIZE-1, 0, ( struct sockaddr* )&client_address, &client_addrlength ); 106 | if( ret > 0 ) 107 | { 108 | sendto( udpfd, buf, UDP_BUFFER_SIZE-1, 0, ( struct sockaddr* )&client_address, client_addrlength ); 109 | } 110 | } 111 | else if ( events[i].events & EPOLLIN ) 112 | { 113 | char buf[ TCP_BUFFER_SIZE ]; 114 | while( 1 ) 115 | { 116 | memset( buf, '\0', TCP_BUFFER_SIZE ); 117 | ret = recv( sockfd, buf, TCP_BUFFER_SIZE-1, 0 ); 118 | if( ret < 0 ) 119 | { 120 | if( ( errno == EAGAIN ) || ( errno == EWOULDBLOCK ) ) 121 | { 122 | break; 123 | } 124 | close( sockfd ); 125 | break; 126 | } 127 | else if( ret == 0 ) 128 | { 129 | close( sockfd ); 130 | } 131 | else 132 | { 133 | send( sockfd, buf, 1, 0 ); 134 | send( sockfd, buf, 1, 0 ); 135 | } 136 | } 137 | } 138 | else 139 | { 140 | printf( "something else happened \n" ); 141 | } 142 | } 143 | } 144 | 145 | close( listenfd ); 146 | return 0; 147 | } 148 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LinuxServerCodes 2 | Linux高性能服务器编程源码 3 | 4 | 作者: 游双 5 | 6 | 出版社: 机械工业出版社 7 | 8 | 出版年: 2013-5-1 9 | 10 | ISBN: 9787111425199 11 | 12 | -------------------------------------------------------------------------------- /springsnail/Makefile: -------------------------------------------------------------------------------- 1 | all: log.o fdwrapper.o conn.o mgr.o springsnail 2 | 3 | log.o: log.cpp log.h 4 | g++ -c log.cpp -o log.o 5 | fdwrapper.o: fdwrapper.cpp fdwrapper.h 6 | g++ -c fdwrapper.cpp -o fdwrapper.o 7 | conn.o: conn.cpp conn.h 8 | g++ -c conn.cpp -o conn.o 9 | mgr.o: mgr.cpp mgr.h 10 | g++ -c mgr.cpp -o mgr.o 11 | springsnail: processpool.h main.cpp log.o fdwrapper.o conn.o mgr.o 12 | g++ processpool.h log.o fdwrapper.o conn.o mgr.o main.cpp -o springsnail 13 | 14 | clean: 15 | rm *.o springsnail 16 | -------------------------------------------------------------------------------- /springsnail/config.xml: -------------------------------------------------------------------------------- 1 | Listen 10.194.70.225:12345 2 | 3 | 4 | 10.194.70.225 5 | 13579 6 | 5 7 | 8 | 9 | 10.194.70.79 10 | 13579 11 | 5 12 | 13 | -------------------------------------------------------------------------------- /springsnail/conn.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "conn.h" 5 | #include "log.h" 6 | #include "fdwrapper.h" 7 | 8 | conn::conn() 9 | { 10 | m_srvfd = -1; 11 | m_clt_buf = new char[ BUF_SIZE ]; 12 | if( !m_clt_buf ) 13 | { 14 | throw std::exception(); 15 | } 16 | m_srv_buf = new char[ BUF_SIZE ]; 17 | if( !m_srv_buf ) 18 | { 19 | throw std::exception(); 20 | } 21 | reset(); 22 | } 23 | 24 | conn::~conn() 25 | { 26 | delete [] m_clt_buf; 27 | delete [] m_srv_buf; 28 | } 29 | 30 | void conn::init_clt( int sockfd, const sockaddr_in& client_addr ) 31 | { 32 | m_cltfd = sockfd; 33 | m_clt_address = client_addr; 34 | } 35 | 36 | void conn::init_srv( int sockfd, const sockaddr_in& server_addr ) 37 | { 38 | m_srvfd = sockfd; 39 | m_srv_address = server_addr; 40 | } 41 | 42 | void conn::reset() 43 | { 44 | m_clt_read_idx = 0; 45 | m_clt_write_idx = 0; 46 | m_srv_read_idx = 0; 47 | m_srv_write_idx = 0; 48 | m_srv_closed = false; 49 | m_cltfd = -1; 50 | memset( m_clt_buf, '\0', BUF_SIZE ); 51 | memset( m_srv_buf, '\0', BUF_SIZE ); 52 | } 53 | 54 | RET_CODE conn::read_clt() 55 | { 56 | int bytes_read = 0; 57 | while( true ) 58 | { 59 | if( m_clt_read_idx >= BUF_SIZE ) 60 | { 61 | log( LOG_ERR, __FILE__, __LINE__, "%s", "the client read buffer is full, let server write" ); 62 | return BUFFER_FULL; 63 | } 64 | 65 | bytes_read = recv( m_cltfd, m_clt_buf + m_clt_read_idx, BUF_SIZE - m_clt_read_idx, 0 ); 66 | if ( bytes_read == -1 ) 67 | { 68 | if( errno == EAGAIN || errno == EWOULDBLOCK ) 69 | { 70 | break; 71 | } 72 | return IOERR; 73 | } 74 | else if ( bytes_read == 0 ) 75 | { 76 | return CLOSED; 77 | } 78 | 79 | m_clt_read_idx += bytes_read; 80 | } 81 | return ( ( m_clt_read_idx - m_clt_write_idx ) > 0 ) ? OK : NOTHING; 82 | } 83 | 84 | RET_CODE conn::read_srv() 85 | { 86 | int bytes_read = 0; 87 | while( true ) 88 | { 89 | if( m_srv_read_idx >= BUF_SIZE ) 90 | { 91 | log( LOG_ERR, __FILE__, __LINE__, "%s", "the server read buffer is full, let client write" ); 92 | return BUFFER_FULL; 93 | } 94 | 95 | bytes_read = recv( m_srvfd, m_srv_buf + m_srv_read_idx, BUF_SIZE - m_srv_read_idx, 0 ); 96 | if ( bytes_read == -1 ) 97 | { 98 | if( errno == EAGAIN || errno == EWOULDBLOCK ) 99 | { 100 | break; 101 | } 102 | return IOERR; 103 | } 104 | else if ( bytes_read == 0 ) 105 | { 106 | log( LOG_ERR, __FILE__, __LINE__, "%s", "the server should not close the persist connection" ); 107 | return CLOSED; 108 | } 109 | 110 | m_srv_read_idx += bytes_read; 111 | } 112 | return ( ( m_srv_read_idx - m_srv_write_idx ) > 0 ) ? OK : NOTHING; 113 | } 114 | 115 | RET_CODE conn::write_srv() 116 | { 117 | int bytes_write = 0; 118 | while( true ) 119 | { 120 | if( m_clt_read_idx <= m_clt_write_idx ) 121 | { 122 | m_clt_read_idx = 0; 123 | m_clt_write_idx = 0; 124 | return BUFFER_EMPTY; 125 | } 126 | 127 | bytes_write = send( m_srvfd, m_clt_buf + m_clt_write_idx, m_clt_read_idx - m_clt_write_idx, 0 ); 128 | if ( bytes_write == -1 ) 129 | { 130 | if( errno == EAGAIN || errno == EWOULDBLOCK ) 131 | { 132 | return TRY_AGAIN; 133 | } 134 | log( LOG_ERR, __FILE__, __LINE__, "write server socket failed, %s", strerror( errno ) ); 135 | return IOERR; 136 | } 137 | else if ( bytes_write == 0 ) 138 | { 139 | return CLOSED; 140 | } 141 | 142 | m_clt_write_idx += bytes_write; 143 | } 144 | } 145 | 146 | RET_CODE conn::write_clt() 147 | { 148 | int bytes_write = 0; 149 | while( true ) 150 | { 151 | if( m_srv_read_idx <= m_srv_write_idx ) 152 | { 153 | m_srv_read_idx = 0; 154 | m_srv_write_idx = 0; 155 | return BUFFER_EMPTY; 156 | } 157 | 158 | bytes_write = send( m_cltfd, m_srv_buf + m_srv_write_idx, m_srv_read_idx - m_srv_write_idx, 0 ); 159 | if ( bytes_write == -1 ) 160 | { 161 | if( errno == EAGAIN || errno == EWOULDBLOCK ) 162 | { 163 | return TRY_AGAIN; 164 | } 165 | log( LOG_ERR, __FILE__, __LINE__, "write client socket failed, %s", strerror( errno ) ); 166 | return IOERR; 167 | } 168 | else if ( bytes_write == 0 ) 169 | { 170 | return CLOSED; 171 | } 172 | 173 | m_srv_write_idx += bytes_write; 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /springsnail/conn.h: -------------------------------------------------------------------------------- 1 | #ifndef CONN_H 2 | #define CONN_H 3 | 4 | #include 5 | #include "fdwrapper.h" 6 | 7 | class conn 8 | { 9 | public: 10 | conn(); 11 | ~conn(); 12 | void init_clt( int sockfd, const sockaddr_in& client_addr ); 13 | void init_srv( int sockfd, const sockaddr_in& server_addr ); 14 | void reset(); 15 | RET_CODE read_clt(); 16 | RET_CODE write_clt(); 17 | RET_CODE read_srv(); 18 | RET_CODE write_srv(); 19 | 20 | public: 21 | static const int BUF_SIZE = 2048; 22 | 23 | char* m_clt_buf; 24 | int m_clt_read_idx; 25 | int m_clt_write_idx; 26 | sockaddr_in m_clt_address; 27 | int m_cltfd; 28 | 29 | char* m_srv_buf; 30 | int m_srv_read_idx; 31 | int m_srv_write_idx; 32 | sockaddr_in m_srv_address; 33 | int m_srvfd; 34 | 35 | bool m_srv_closed; 36 | }; 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /springsnail/fdwrapper.cpp: -------------------------------------------------------------------------------- 1 | #ifndef FDWRAPPER_H 2 | #define FDWRAPPER_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | int setnonblocking( int fd ) 9 | { 10 | int old_option = fcntl( fd, F_GETFL ); 11 | int new_option = old_option | O_NONBLOCK; 12 | fcntl( fd, F_SETFL, new_option ); 13 | return old_option; 14 | } 15 | 16 | void add_read_fd( int epollfd, int fd ) 17 | { 18 | epoll_event event; 19 | event.data.fd = fd; 20 | event.events = EPOLLIN | EPOLLET; 21 | epoll_ctl( epollfd, EPOLL_CTL_ADD, fd, &event ); 22 | setnonblocking( fd ); 23 | } 24 | 25 | void add_write_fd( int epollfd, int fd ) 26 | { 27 | epoll_event event; 28 | event.data.fd = fd; 29 | event.events = EPOLLOUT | EPOLLET; 30 | epoll_ctl( epollfd, EPOLL_CTL_ADD, fd, &event ); 31 | setnonblocking( fd ); 32 | } 33 | 34 | void closefd( int epollfd, int fd ) 35 | { 36 | epoll_ctl( epollfd, EPOLL_CTL_DEL, fd, 0 ); 37 | close( fd ); 38 | } 39 | 40 | void removefd( int epollfd, int fd ) 41 | { 42 | epoll_ctl( epollfd, EPOLL_CTL_DEL, fd, 0 ); 43 | } 44 | 45 | void modfd( int epollfd, int fd, int ev ) 46 | { 47 | epoll_event event; 48 | event.data.fd = fd; 49 | event.events = ev | EPOLLET; 50 | epoll_ctl( epollfd, EPOLL_CTL_MOD, fd, &event ); 51 | } 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /springsnail/fdwrapper.h: -------------------------------------------------------------------------------- 1 | #ifndef FDWRAPPER_H 2 | #define FDWRAPPER_H 3 | 4 | enum RET_CODE { OK = 0, NOTHING = 1, IOERR = -1, CLOSED = -2, BUFFER_FULL = -3, BUFFER_EMPTY = -4, TRY_AGAIN }; 5 | enum OP_TYPE { READ = 0, WRITE, ERROR }; 6 | int setnonblocking( int fd ); 7 | void add_read_fd( int epollfd, int fd ); 8 | void add_write_fd( int epollfd, int fd ); 9 | void removefd( int epollfd, int fd ); 10 | void closefd( int epollfd, int fd ); 11 | void modfd( int epollfd, int fd, int ev ); 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /springsnail/log.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "log.h" 5 | 6 | static int level = LOG_INFO; 7 | static int LOG_BUFFER_SIZE = 2048; 8 | static const char* loglevels[] = 9 | { 10 | "emerge!", "alert!", "critical!", "error!", "warn!", "notice:", "info:", "debug:" 11 | }; 12 | 13 | void set_loglevel( int log_level ) 14 | { 15 | level = log_level; 16 | } 17 | 18 | void log( int log_level, const char* file_name, int line_num, const char* format, ... ) 19 | { 20 | if ( log_level > level ) 21 | { 22 | return; 23 | } 24 | 25 | time_t tmp = time( NULL ); 26 | struct tm* cur_time = localtime( &tmp ); 27 | if ( ! cur_time ) 28 | { 29 | return; 30 | } 31 | 32 | char arg_buffer[ LOG_BUFFER_SIZE ]; 33 | memset( arg_buffer, '\0', LOG_BUFFER_SIZE ); 34 | strftime( arg_buffer, LOG_BUFFER_SIZE - 1, "[ %x %X ] ", cur_time ); 35 | printf( "%s", arg_buffer ); 36 | printf( "%s:%04d ", file_name, line_num ); 37 | printf( "%s ", loglevels[ log_level - LOG_EMERG ] ); 38 | 39 | va_list arg_list; 40 | va_start( arg_list, format ); 41 | memset( arg_buffer, '\0', LOG_BUFFER_SIZE ); 42 | vsnprintf( arg_buffer, LOG_BUFFER_SIZE - 1, format, arg_list ); 43 | printf( "%s\n", arg_buffer ); 44 | fflush( stdout ); 45 | va_end( arg_list ); 46 | } 47 | -------------------------------------------------------------------------------- /springsnail/log.h: -------------------------------------------------------------------------------- 1 | #ifndef LOG_H 2 | #define LOG_H 3 | 4 | #include 5 | #include 6 | 7 | void set_loglevel( int log_level = LOG_DEBUG ); 8 | void log( int log_level, const char* file_name, int line_num, const char* format, ... ); 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /springsnail/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "log.h" 19 | #include "conn.h" 20 | #include "mgr.h" 21 | #include "processpool.h" 22 | 23 | using std::vector; 24 | 25 | static const char* version = "1.0"; 26 | 27 | static void usage( const char* prog ) 28 | { 29 | log( LOG_INFO, __FILE__, __LINE__, "usage: %s [-h] [-v] [-f config_file]", prog ); 30 | } 31 | 32 | int main( int argc, char* argv[] ) 33 | { 34 | char cfg_file[1024]; 35 | memset( cfg_file, '\0', 100 ); 36 | int option; 37 | while ( ( option = getopt( argc, argv, "f:xvh" ) ) != -1 ) 38 | { 39 | switch ( option ) 40 | { 41 | case 'x': 42 | { 43 | set_loglevel( LOG_DEBUG ); 44 | break; 45 | } 46 | case 'v': 47 | { 48 | log( LOG_INFO, __FILE__, __LINE__, "%s %s", argv[0], version ); 49 | return 0; 50 | } 51 | case 'h': 52 | { 53 | usage( basename( argv[ 0 ] ) ); 54 | return 0; 55 | } 56 | case 'f': 57 | { 58 | memcpy( cfg_file, optarg, strlen( optarg ) ); 59 | break; 60 | } 61 | case '?': 62 | { 63 | log( LOG_ERR, __FILE__, __LINE__, "un-recognized option %c", option ); 64 | usage( basename( argv[ 0 ] ) ); 65 | return 1; 66 | } 67 | } 68 | } 69 | 70 | if( cfg_file[0] == '\0' ) 71 | { 72 | log( LOG_ERR, __FILE__, __LINE__, "%s", "please specifiy the config file" ); 73 | return 1; 74 | } 75 | int cfg_fd = open( cfg_file, O_RDONLY ); 76 | if( !cfg_fd ) 77 | { 78 | log( LOG_ERR, __FILE__, __LINE__, "read config file met error: %s", strerror( errno ) ); 79 | return 1; 80 | } 81 | struct stat ret_stat; 82 | if( fstat( cfg_fd, &ret_stat ) < 0 ) 83 | { 84 | log( LOG_ERR, __FILE__, __LINE__, "read config file met error: %s", strerror( errno ) ); 85 | return 1; 86 | } 87 | char* buf = new char [ret_stat.st_size + 1]; 88 | memset( buf, '\0', ret_stat.st_size + 1 ); 89 | ssize_t read_sz = read( cfg_fd, buf, ret_stat.st_size ); 90 | if ( read_sz < 0 ) 91 | { 92 | log( LOG_ERR, __FILE__, __LINE__, "read config file met error: %s", strerror( errno ) ); 93 | return 1; 94 | } 95 | vector< host > balance_srv; 96 | vector< host > logical_srv; 97 | host tmp_host; 98 | memset( tmp_host.m_hostname, '\0', 1024 ); 99 | char* tmp_hostname; 100 | char* tmp_port; 101 | char* tmp_conncnt; 102 | bool opentag = false; 103 | char* tmp = buf; 104 | char* tmp2 = NULL; 105 | char* tmp3 = NULL; 106 | char* tmp4 = NULL; 107 | while( tmp2 = strpbrk( tmp, "\n" ) ) 108 | { 109 | *tmp2++ = '\0'; 110 | if( strstr( tmp, "" ) ) 111 | { 112 | if( opentag ) 113 | { 114 | log( LOG_ERR, __FILE__, __LINE__, "%s", "parse config file failed" ); 115 | return 1; 116 | } 117 | opentag = true; 118 | } 119 | else if( strstr( tmp, "" ) ) 120 | { 121 | if( !opentag ) 122 | { 123 | log( LOG_ERR, __FILE__, __LINE__, "%s", "parse config file failed" ); 124 | return 1; 125 | } 126 | logical_srv.push_back( tmp_host ); 127 | memset( tmp_host.m_hostname, '\0', 1024 ); 128 | opentag = false; 129 | } 130 | else if( tmp3 = strstr( tmp, "" ) ) 131 | { 132 | tmp_hostname = tmp3 + 6; 133 | tmp4 = strstr( tmp_hostname, "" ); 134 | if( !tmp4 ) 135 | { 136 | log( LOG_ERR, __FILE__, __LINE__, "%s", "parse config file failed" ); 137 | return 1; 138 | } 139 | *tmp4 = '\0'; 140 | memcpy( tmp_host.m_hostname, tmp_hostname, strlen( tmp_hostname ) ); 141 | } 142 | else if( tmp3 = strstr( tmp, "" ) ) 143 | { 144 | tmp_port = tmp3 + 6; 145 | tmp4 = strstr( tmp_port, "" ); 146 | if( !tmp4 ) 147 | { 148 | log( LOG_ERR, __FILE__, __LINE__, "%s", "parse config file failed" ); 149 | return 1; 150 | } 151 | *tmp4 = '\0'; 152 | tmp_host.m_port = atoi( tmp_port ); 153 | } 154 | else if( tmp3 = strstr( tmp, "" ) ) 155 | { 156 | tmp_conncnt = tmp3 + 7; 157 | tmp4 = strstr( tmp_conncnt, "" ); 158 | if( !tmp4 ) 159 | { 160 | log( LOG_ERR, __FILE__, __LINE__, "%s", "parse config file failed" ); 161 | return 1; 162 | } 163 | *tmp4 = '\0'; 164 | tmp_host.m_conncnt = atoi( tmp_conncnt ); 165 | } 166 | else if( tmp3 = strstr( tmp, "Listen" ) ) 167 | { 168 | tmp_hostname = tmp3 + 6; 169 | tmp4 = strstr( tmp_hostname, ":" ); 170 | if( !tmp4 ) 171 | { 172 | log( LOG_ERR, __FILE__, __LINE__, "%s", "parse config file failed" ); 173 | return 1; 174 | } 175 | *tmp4++ = '\0'; 176 | tmp_host.m_port = atoi( tmp4 ); 177 | memcpy( tmp_host.m_hostname, tmp3, strlen( tmp3 ) ); 178 | balance_srv.push_back( tmp_host ); 179 | memset( tmp_host.m_hostname, '\0', 1024 ); 180 | } 181 | tmp = tmp2; 182 | } 183 | 184 | if( balance_srv.size() == 0 || logical_srv.size() == 0 ) 185 | { 186 | log( LOG_ERR, __FILE__, __LINE__, "%s", "parse config file failed" ); 187 | return 1; 188 | } 189 | const char* ip = balance_srv[0].m_hostname; 190 | int port = balance_srv[0].m_port; 191 | 192 | int listenfd = socket( PF_INET, SOCK_STREAM, 0 ); 193 | assert( listenfd >= 0 ); 194 | 195 | int ret = 0; 196 | struct sockaddr_in address; 197 | bzero( &address, sizeof( address ) ); 198 | address.sin_family = AF_INET; 199 | inet_pton( AF_INET, ip, &address.sin_addr ); 200 | address.sin_port = htons( port ); 201 | 202 | ret = bind( listenfd, ( struct sockaddr* )&address, sizeof( address ) ); 203 | assert( ret != -1 ); 204 | 205 | ret = listen( listenfd, 5 ); 206 | assert( ret != -1 ); 207 | 208 | //memset( cfg_host.m_hostname, '\0', 1024 ); 209 | //memcpy( cfg_host.m_hostname, "127.0.0.1", strlen( "127.0.0.1" ) ); 210 | //cfg_host.m_port = 54321; 211 | //cfg_host.m_conncnt = 5; 212 | processpool< conn, host, mgr >* pool = processpool< conn, host, mgr >::create( listenfd, logical_srv.size() ); 213 | if( pool ) 214 | { 215 | pool->run( logical_srv ); 216 | delete pool; 217 | } 218 | 219 | close( listenfd ); 220 | return 0; 221 | } 222 | -------------------------------------------------------------------------------- /springsnail/mgr.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | #include "log.h" 19 | #include "mgr.h" 20 | 21 | using std::pair; 22 | 23 | int mgr::m_epollfd = -1; 24 | int mgr::conn2srv( const sockaddr_in& address ) 25 | { 26 | int sockfd = socket( PF_INET, SOCK_STREAM, 0 ); 27 | if( sockfd < 0 ) 28 | { 29 | return -1; 30 | } 31 | 32 | if ( connect( sockfd, ( struct sockaddr* )&address, sizeof( address ) ) != 0 ) 33 | { 34 | close( sockfd ); 35 | return -1; 36 | } 37 | return sockfd; 38 | } 39 | 40 | mgr::mgr( int epollfd, const host& srv ) : m_logic_srv( srv ) 41 | { 42 | m_epollfd = epollfd; 43 | int ret = 0; 44 | struct sockaddr_in address; 45 | bzero( &address, sizeof( address ) ); 46 | address.sin_family = AF_INET; 47 | inet_pton( AF_INET, srv.m_hostname, &address.sin_addr ); 48 | address.sin_port = htons( srv.m_port ); 49 | log( LOG_INFO, __FILE__, __LINE__, "logcial srv host info: (%s, %d)", srv.m_hostname, srv.m_port ); 50 | 51 | for( int i = 0; i < srv.m_conncnt; ++i ) 52 | { 53 | sleep( 1 ); 54 | int sockfd = conn2srv( address ); 55 | if( sockfd < 0 ) 56 | { 57 | log( LOG_ERR, __FILE__, __LINE__, "build connection %d failed", i ); 58 | } 59 | else 60 | { 61 | log( LOG_INFO, __FILE__, __LINE__, "build connection %d to server success", i ); 62 | conn* tmp = NULL; 63 | try 64 | { 65 | tmp = new conn; 66 | } 67 | catch( ... ) 68 | { 69 | close( sockfd ); 70 | continue; 71 | } 72 | tmp->init_srv( sockfd, address ); 73 | m_conns.insert( pair< int, conn* >( sockfd, tmp ) ); 74 | } 75 | } 76 | } 77 | 78 | mgr::~mgr() 79 | { 80 | } 81 | 82 | int mgr::get_used_conn_cnt() 83 | { 84 | return m_used.size(); 85 | } 86 | 87 | conn* mgr::pick_conn( int cltfd ) 88 | { 89 | if( m_conns.empty() ) 90 | { 91 | log( LOG_ERR, __FILE__, __LINE__, "%s", "not enough srv connections to server" ); 92 | return NULL; 93 | } 94 | 95 | map< int, conn* >::iterator iter = m_conns.begin(); 96 | int srvfd = iter->first; 97 | conn* tmp = iter->second; 98 | if( !tmp ) 99 | { 100 | log( LOG_ERR, __FILE__, __LINE__, "%s", "empty server connection object" ); 101 | return NULL; 102 | } 103 | m_conns.erase( iter ); 104 | m_used.insert( pair< int, conn* >( cltfd, tmp ) ); 105 | m_used.insert( pair< int, conn* >( srvfd, tmp ) ); 106 | add_read_fd( m_epollfd, cltfd ); 107 | add_read_fd( m_epollfd, srvfd ); 108 | log( LOG_INFO, __FILE__, __LINE__, "bind client sock %d with server sock %d", cltfd, srvfd ); 109 | return tmp; 110 | } 111 | 112 | void mgr::free_conn( conn* connection ) 113 | { 114 | int cltfd = connection->m_cltfd; 115 | int srvfd = connection->m_srvfd; 116 | closefd( m_epollfd, cltfd ); 117 | closefd( m_epollfd, srvfd ); 118 | m_used.erase( cltfd ); 119 | m_used.erase( srvfd ); 120 | connection->reset(); 121 | m_freed.insert( pair< int, conn* >( srvfd, connection ) ); 122 | } 123 | 124 | void mgr::recycle_conns() 125 | { 126 | if( m_freed.empty() ) 127 | { 128 | return; 129 | } 130 | for( map< int, conn* >::iterator iter = m_freed.begin(); iter != m_freed.end(); iter++ ) 131 | { 132 | sleep( 1 ); 133 | int srvfd = iter->first; 134 | conn* tmp = iter->second; 135 | srvfd = conn2srv( tmp->m_srv_address ); 136 | if( srvfd < 0 ) 137 | { 138 | log( LOG_ERR, __FILE__, __LINE__, "%s", "fix connection failed"); 139 | } 140 | else 141 | { 142 | log( LOG_INFO, __FILE__, __LINE__, "%s", "fix connection success" ); 143 | tmp->init_srv( srvfd, tmp->m_srv_address ); 144 | m_conns.insert( pair< int, conn* >( srvfd, tmp ) ); 145 | } 146 | } 147 | m_freed.clear(); 148 | } 149 | 150 | RET_CODE mgr::process( int fd, OP_TYPE type ) 151 | { 152 | conn* connection = m_used[ fd ]; 153 | if( !connection ) 154 | { 155 | return NOTHING; 156 | } 157 | if( connection->m_cltfd == fd ) 158 | { 159 | int srvfd = connection->m_srvfd; 160 | switch( type ) 161 | { 162 | case READ: 163 | { 164 | RET_CODE res = connection->read_clt(); 165 | switch( res ) 166 | { 167 | case OK: 168 | { 169 | log( LOG_DEBUG, __FILE__, __LINE__, "content read from client: %s", connection->m_clt_buf ); 170 | } 171 | case BUFFER_FULL: 172 | { 173 | modfd( m_epollfd, srvfd, EPOLLOUT ); 174 | break; 175 | } 176 | case IOERR: 177 | case CLOSED: 178 | { 179 | free_conn( connection ); 180 | return CLOSED; 181 | } 182 | default: 183 | break; 184 | } 185 | if( connection->m_srv_closed ) 186 | { 187 | free_conn( connection ); 188 | return CLOSED; 189 | } 190 | break; 191 | } 192 | case WRITE: 193 | { 194 | RET_CODE res = connection->write_clt(); 195 | switch( res ) 196 | { 197 | case TRY_AGAIN: 198 | { 199 | modfd( m_epollfd, fd, EPOLLOUT ); 200 | break; 201 | } 202 | case BUFFER_EMPTY: 203 | { 204 | modfd( m_epollfd, srvfd, EPOLLIN ); 205 | modfd( m_epollfd, fd, EPOLLIN ); 206 | break; 207 | } 208 | case IOERR: 209 | case CLOSED: 210 | { 211 | free_conn( connection ); 212 | return CLOSED; 213 | } 214 | default: 215 | break; 216 | } 217 | if( connection->m_srv_closed ) 218 | { 219 | free_conn( connection ); 220 | return CLOSED; 221 | } 222 | break; 223 | } 224 | default: 225 | { 226 | log( LOG_ERR, __FILE__, __LINE__, "%s", "other operation not support yet" ); 227 | break; 228 | } 229 | } 230 | } 231 | else if( connection->m_srvfd == fd ) 232 | { 233 | int cltfd = connection->m_cltfd; 234 | switch( type ) 235 | { 236 | case READ: 237 | { 238 | RET_CODE res = connection->read_srv(); 239 | switch( res ) 240 | { 241 | case OK: 242 | { 243 | log( LOG_DEBUG, __FILE__, __LINE__, "content read from server: %s", connection->m_srv_buf ); 244 | } 245 | case BUFFER_FULL: 246 | { 247 | modfd( m_epollfd, cltfd, EPOLLOUT ); 248 | break; 249 | } 250 | case IOERR: 251 | case CLOSED: 252 | { 253 | modfd( m_epollfd, cltfd, EPOLLOUT ); 254 | connection->m_srv_closed = true; 255 | break; 256 | } 257 | default: 258 | break; 259 | } 260 | break; 261 | } 262 | case WRITE: 263 | { 264 | RET_CODE res = connection->write_srv(); 265 | switch( res ) 266 | { 267 | case TRY_AGAIN: 268 | { 269 | modfd( m_epollfd, fd, EPOLLOUT ); 270 | break; 271 | } 272 | case BUFFER_EMPTY: 273 | { 274 | modfd( m_epollfd, cltfd, EPOLLIN ); 275 | modfd( m_epollfd, fd, EPOLLIN ); 276 | break; 277 | } 278 | case IOERR: 279 | case CLOSED: 280 | { 281 | /* 282 | if( connection->m_srv_write_idx == connection->m_srvread_idx ) 283 | { 284 | free_conn( connection ); 285 | } 286 | else 287 | { 288 | modfd( m_epollfd, cltfd, EPOLLOUT ); 289 | } 290 | */ 291 | modfd( m_epollfd, cltfd, EPOLLOUT ); 292 | connection->m_srv_closed = true; 293 | break; 294 | } 295 | default: 296 | break; 297 | } 298 | break; 299 | } 300 | default: 301 | { 302 | log( LOG_ERR, __FILE__, __LINE__, "%s", "other operation not support yet" ); 303 | break; 304 | } 305 | } 306 | } 307 | else 308 | { 309 | return NOTHING; 310 | } 311 | return OK; 312 | } 313 | -------------------------------------------------------------------------------- /springsnail/mgr.h: -------------------------------------------------------------------------------- 1 | #ifndef SRVMGR_H 2 | #define SRVMGR_H 3 | 4 | #include 5 | #include 6 | #include "fdwrapper.h" 7 | #include "conn.h" 8 | 9 | using std::map; 10 | 11 | class host 12 | { 13 | public: 14 | char m_hostname[1024]; 15 | int m_port; 16 | int m_conncnt; 17 | }; 18 | 19 | class mgr 20 | { 21 | public: 22 | mgr( int epollfd, const host& srv ); 23 | ~mgr(); 24 | int conn2srv( const sockaddr_in& address ); 25 | conn* pick_conn( int sockfd ); 26 | void free_conn( conn* connection ); 27 | int get_used_conn_cnt(); 28 | void recycle_conns(); 29 | RET_CODE process( int fd, OP_TYPE type ); 30 | 31 | private: 32 | static int m_epollfd; 33 | map< int, conn* > m_conns; 34 | map< int, conn* > m_used; 35 | map< int, conn* > m_freed; 36 | host m_logic_srv; 37 | }; 38 | 39 | #endif 40 | --------------------------------------------------------------------------------