├── .gitignore ├── CMakeLists.txt ├── README.md ├── chap-11 ├── CMakeLists.txt ├── graceclient.c ├── graceserver.c ├── tcpclient.c.bak └── tcpserver.c.bak ├── chap-12 ├── CMakeLists.txt ├── message_objecte.h ├── pingclient.c └── pingserver.c ├── chap-13 ├── CMakeLists.txt └── batchwrite.c ├── chap-14 ├── CMakeLists.txt ├── udpconnectclient.c ├── udpconnectclient02.c └── udpconnectserver.c ├── chap-15 ├── CMakeLists.txt ├── addressused.c └── addressused02.c ├── chap-16 ├── CMakeLists.txt ├── streamclient.c └── streamserver.c ├── chap-17 ├── CMakeLists.txt ├── reliable_client01.c ├── reliable_client02.c ├── reliable_server01.c └── reliable_server02.c ├── chap-18 ├── CMakeLists.txt ├── bufferclient.c ├── samplebuffer01.c ├── samplebuffer02.c └── samplebuffer03.c ├── chap-20 ├── CMakeLists.txt └── select01.c ├── chap-21 ├── CMakeLists.txt ├── pollserver.c └── pollserver02.c ├── chap-22 ├── CMakeLists.txt ├── nonblockingclient.c └── nonblockingserver.c ├── chap-23 ├── CMakeLists.txt ├── epoll01.c ├── epoll02.c └── epoll03.c ├── chap-25 ├── CMakeLists.txt └── fork01.c ├── chap-26 ├── CMakeLists.txt ├── echo.c ├── thread-helloworld.c ├── thread01.c └── thread02.c ├── chap-27 ├── CMakeLists.txt └── poll-server-onethread.c ├── chap-28 ├── CMakeLists.txt ├── poll-server-multithreads.c └── test01.c ├── chap-29 ├── CMakeLists.txt └── epoll-server-multithreads.c ├── chap-30 ├── CMakeLists.txt ├── aio01.c └── test.txt ├── chap-34 ├── CMakeLists.txt ├── http_server01.c └── http_server_test.c ├── chap-4 ├── CMakeLists.txt └── make_socket.c ├── chap-5 ├── CMakeLists.txt ├── tcp_server.c └── tcpclient.c ├── chap-6 ├── CMakeLists.txt ├── udpclient.c └── udpserver.c ├── chap-7 ├── CMakeLists.txt ├── unixdataclient.c ├── unixdataserver.c ├── unixstreamclient.c └── unixstreamserver.c ├── clean.sh ├── config.h.cmake ├── lib ├── CMakeLists.txt ├── acceptor.c ├── acceptor.h ├── buffer.c ├── buffer.h ├── channel.c ├── channel.h ├── channel_map.c ├── channel_map.h ├── common.h ├── epoll_dispatcher.c ├── event_dispatcher.h ├── event_loop.c ├── event_loop.h ├── event_loop_thread.c ├── event_loop_thread.h ├── http_request.c ├── http_request.h ├── http_response.c ├── http_response.h ├── http_server.c ├── http_server.h ├── inetaddress.h ├── log.c ├── log.h ├── poll_dispatcher.c ├── read.c ├── sock_ntop.c ├── tcp_client.c ├── tcp_connection.c ├── tcp_connection.h ├── tcp_server.c ├── tcp_server.h ├── thread_pool.c ├── thread_pool.h ├── utils.c └── utils.h └── mid-homework ├── CMakeLists.txt ├── telnet-client.c └── telnet-server.c /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | .idea/* 3 | cmake-build-debug/* 4 | build/* 5 | bin/* 6 | CMakeCache.txt 7 | CMakeFiles/* 8 | Makefile 9 | cmake_install.cmake 10 | .vscode/* 11 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.1) 2 | project(yolanda C CXX) 3 | 4 | set(CMAKE_CXX_STANDARD 11) 5 | set(CMAKE_C_STANDARD 99) 6 | 7 | # Put the libaries and binaries that get built into directories at the 8 | # top of the build tree rather than in hard-to-find leaf directories. 9 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin) 10 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib) 11 | set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib) 12 | 13 | include_directories(${PROJECT_SOURCE_DIR}) 14 | 15 | # check epoll and add config.h for the macro compilation 16 | include(CheckSymbolExists) 17 | check_symbol_exists(epoll_create "sys/epoll.h" EPOLL_EXISTS) 18 | if (EPOLL_EXISTS) 19 | # Linux下设置为epoll 20 | set(EPOLL_ENABLE 1 CACHE INTERNAL "enable epoll") 21 | 22 | # Linux下也设置为poll 23 | # set(EPOLL_ENABLE "" CACHE INTERNAL "not enable epoll") 24 | else () 25 | set(EPOLL_ENABLE "" CACHE INTERNAL "not enable epoll") 26 | endif () 27 | 28 | configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.cmake 29 | ${CMAKE_CURRENT_BINARY_DIR}/include/config.h) 30 | 31 | include_directories(${CMAKE_CURRENT_BINARY_DIR}/include) 32 | 33 | add_subdirectory(lib/) 34 | add_subdirectory(chap-4/) 35 | add_subdirectory(chap-5/) 36 | add_subdirectory(chap-6/) 37 | add_subdirectory(chap-7/) 38 | add_subdirectory(chap-11) 39 | add_subdirectory(chap-12) 40 | add_subdirectory(chap-13) 41 | add_subdirectory(chap-14/) 42 | add_subdirectory(chap-15) 43 | add_subdirectory(chap-16) 44 | add_subdirectory(chap-17) 45 | add_subdirectory(chap-18) 46 | add_subdirectory(mid-homework) 47 | add_subdirectory(chap-20) 48 | add_subdirectory(chap-21) 49 | add_subdirectory(chap-22) 50 | add_subdirectory(chap-23) 51 | add_subdirectory(chap-25) 52 | add_subdirectory(chap-26) 53 | add_subdirectory(chap-27) 54 | add_subdirectory(chap-28) 55 | add_subdirectory(chap-29) 56 | add_subdirectory(chap-30) 57 | add_subdirectory(chap-34) 58 | 59 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 如何编译和执行 2 | 3 | 本工程使用CMake来编译,CMake的好处是方便跨平台执行。关于CMake,可以访问(https://cmake.org/)。 4 | 5 | 在Linux环境下,请先创建build目录,并到目录build下,执行cmake 6 | ```bash 7 | mkdir build && cd build 8 | cmake ../ 9 | ``` 10 | 11 | 再执行 12 | ```bash 13 | make 14 | ``` 15 | 16 | 如果你的Linux中无法运行cmake或make命令,可以按照如下命令安装它 17 | ```bash 18 | sudo apt-get install cmake g++ make 19 | ``` 20 | 21 | 所有的可执行程序在目录build/bin下面 22 | 23 | 24 | 如果你有CLion或者其他可视化的IDE,可以直接在IDE中执行"Build Project"来完成整个项目的编译。 25 | 26 | 27 | -------------------------------------------------------------------------------- /chap-11/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(graceclient graceclient.c) 2 | target_link_libraries(graceclient yolanda) 3 | 4 | add_executable(graceserver graceserver.c) 5 | target_link_libraries(graceserver yolanda) 6 | 7 | -------------------------------------------------------------------------------- /chap-11/graceclient.c: -------------------------------------------------------------------------------- 1 | # include "lib/common.h" 2 | 3 | # define MAXLINE 4096 4 | 5 | int main(int argc, char **argv) { 6 | if (argc != 2) { 7 | error(1, 0, "usage: graceclient "); 8 | 9 | } 10 | int socket_fd; 11 | socket_fd = socket(AF_INET, SOCK_STREAM, 0); 12 | 13 | struct sockaddr_in server_addr; 14 | bzero(&server_addr, sizeof(server_addr)); 15 | server_addr.sin_family = AF_INET; 16 | server_addr.sin_port = htons(SERV_PORT); 17 | inet_pton(AF_INET, argv[1], &server_addr.sin_addr); 18 | 19 | socklen_t server_len = sizeof(server_addr); 20 | int connect_rt = connect(socket_fd, (struct sockaddr *) &server_addr, server_len); 21 | if (connect_rt < 0) { 22 | error(1, errno, "connect failed "); 23 | } 24 | 25 | char send_line[MAXLINE], recv_line[MAXLINE + 1]; 26 | int n; 27 | 28 | fd_set readmask; 29 | fd_set allreads; 30 | 31 | FD_ZERO(&allreads); 32 | FD_SET(0, &allreads); 33 | FD_SET(socket_fd, &allreads); 34 | for (;;) { 35 | readmask = allreads; 36 | int rc = select(socket_fd + 1, &readmask, NULL, NULL, NULL); 37 | if (rc <= 0) 38 | error(1, errno, "select failed"); 39 | if (FD_ISSET(socket_fd, &readmask)) { 40 | n = read(socket_fd, recv_line, MAXLINE); 41 | if (n < 0) { 42 | error(1, errno, "read error"); 43 | } else if (n == 0) { 44 | error(1, 0, "server terminated \n"); 45 | } 46 | recv_line[n] = 0; 47 | fputs(recv_line, stdout); 48 | fputs("\n", stdout); 49 | } 50 | if (FD_ISSET(0, &readmask)) { 51 | if (fgets(send_line, MAXLINE, stdin) != NULL) { 52 | if (strncmp(send_line, "shutdown", 8) == 0) { 53 | FD_CLR(0, &allreads); 54 | if (shutdown(socket_fd, 1)) { 55 | error(1, errno, "shutdown failed"); 56 | } 57 | } else if (strncmp(send_line, "close", 5) == 0) { 58 | FD_CLR(0, &allreads); 59 | if (close(socket_fd)) { 60 | error(1, errno, "close failed"); 61 | } 62 | sleep(6); 63 | exit(0); 64 | } else { 65 | int i = strlen(send_line); 66 | if (send_line[i - 1] == '\n') { 67 | send_line[i - 1] = 0; 68 | } 69 | 70 | printf("now sending %s\n", send_line); 71 | size_t rt = write(socket_fd, send_line, strlen(send_line)); 72 | if (rt < 0) { 73 | error(1, errno, "write failed "); 74 | } 75 | printf("send bytes: %zu \n", rt); 76 | } 77 | 78 | } 79 | } 80 | 81 | } 82 | 83 | } 84 | 85 | -------------------------------------------------------------------------------- /chap-11/graceserver.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by shengym on 2019-07-07. 3 | // 4 | 5 | #include "lib/common.h" 6 | 7 | static int count; 8 | 9 | static void sig_int(int signo) { 10 | printf("\nreceived %d datagrams\n", count); 11 | exit(0); 12 | } 13 | 14 | 15 | int main(int argc, char **argv) { 16 | int listenfd; 17 | listenfd = socket(AF_INET, SOCK_STREAM, 0); 18 | 19 | struct sockaddr_in server_addr; 20 | bzero(&server_addr, sizeof(server_addr)); 21 | server_addr.sin_family = AF_INET; 22 | server_addr.sin_addr.s_addr = htonl(INADDR_ANY); 23 | server_addr.sin_port = htons(SERV_PORT); 24 | 25 | int rt1 = bind(listenfd, (struct sockaddr *) &server_addr, sizeof(server_addr)); 26 | if (rt1 < 0) { 27 | error(1, errno, "bind failed "); 28 | } 29 | 30 | int rt2 = listen(listenfd, LISTENQ); 31 | if (rt2 < 0) { 32 | error(1, errno, "listen failed "); 33 | } 34 | 35 | signal(SIGINT, sig_int); 36 | signal(SIGPIPE, SIG_DFL); 37 | 38 | int connfd; 39 | struct sockaddr_in client_addr; 40 | socklen_t client_len = sizeof(client_addr); 41 | 42 | if ((connfd = accept(listenfd, (struct sockaddr *) &client_addr, &client_len)) < 0) { 43 | error(1, errno, "bind failed "); 44 | } 45 | 46 | char message[MAXLINE]; 47 | count = 0; 48 | 49 | for (;;) { 50 | int n = read(connfd, message, MAXLINE); 51 | if (n < 0) { 52 | error(1, errno, "error read"); 53 | } else if (n == 0) { 54 | error(1, 0, "client closed \n"); 55 | } 56 | message[n] = 0; 57 | printf("received %d bytes: %s\n", n, message); 58 | count++; 59 | 60 | char send_line[MAXLINE]; 61 | sprintf(send_line, "Hi, %s", message); 62 | 63 | sleep(5); 64 | 65 | int write_nc = send(connfd, send_line, strlen(send_line), 0); 66 | printf("send bytes: %zu \n", write_nc); 67 | if (write_nc < 0) { 68 | error(1, errno, "error write"); 69 | } 70 | } 71 | 72 | } 73 | 74 | 75 | -------------------------------------------------------------------------------- /chap-11/tcpclient.c.bak: -------------------------------------------------------------------------------- 1 | #include "lib/common.h" 2 | 3 | 4 | # define NDG 2000 /* datagrams to send */ 5 | # define DGLEN 1400 /* length of each datagram */ 6 | # define MAXLINE 4096 7 | 8 | void send_data(char *send_line, int socket_fd) { 9 | int i = strlen(send_line); 10 | if (send_line[i - 1] == '\n') { 11 | send_line[i - 1] = 0; 12 | } 13 | 14 | printf("now sending %s\n", send_line); 15 | size_t rt = write(socket_fd, send_line, strlen(send_line)); 16 | if (rt < 0) { 17 | error(1, errno, "write failed "); 18 | } 19 | printf("send bytes: %zu \n", rt); 20 | 21 | } 22 | 23 | int main(int argc, char **argv) { 24 | if (argc != 2) { 25 | error(1, 0, "usage: tcpclient "); 26 | 27 | } 28 | int socket_fd; 29 | socket_fd = socket(AF_INET, SOCK_STREAM, 0); 30 | 31 | struct sockaddr_in server_addr; 32 | bzero(&server_addr, sizeof(server_addr)); 33 | server_addr.sin_family = AF_INET; 34 | server_addr.sin_port = htons(SERV_PORT); 35 | inet_pton(AF_INET, argv[1], &server_addr.sin_addr); 36 | 37 | socklen_t server_len = sizeof(server_addr); 38 | int connect_rt = connect(socket_fd, (struct sockaddr *) &server_addr, server_len); 39 | if (connect_rt < 0) { 40 | error(1, errno, "connect failed "); 41 | } 42 | 43 | char send_line[MAXLINE], recv_line[MAXLINE + 1]; 44 | int n; 45 | 46 | fd_set readmask; 47 | fd_set allreads; 48 | 49 | FD_ZERO(&allreads); 50 | FD_SET(0, &allreads); 51 | FD_SET(socket_fd, &allreads); 52 | for (;;) { 53 | readmask = allreads; 54 | int rc = select(socket_fd + 1, &readmask, NULL, NULL, NULL); 55 | if (rc <= 0) 56 | error(1, errno, "select failed"); 57 | if (FD_ISSET(socket_fd, &readmask)) { 58 | n = read(socket_fd, recv_line, MAXLINE); 59 | if (n < 0) { 60 | error(1, errno, "read error"); 61 | } else if (n == 0) { 62 | error(1, 0, "server terminated"); 63 | } 64 | recv_line[n] = 0; 65 | fputs(recv_line, stdout); 66 | fputs("\n", stdout); 67 | } 68 | if (FD_ISSET(0, &readmask)) { 69 | if (fgets(send_line, MAXLINE, stdin) != NULL) { 70 | 71 | if (strncmp(send_line, "exit", 4) == 0) { 72 | FD_CLR(0, &allreads); 73 | shutdown(socket_fd, 1); 74 | // close(socket_fd); 75 | // sleep(5); 76 | // exit(0); 77 | } else { 78 | int i = strlen(send_line); 79 | if (send_line[i - 1] == '\n') { 80 | send_line[i - 1] = 0; 81 | } 82 | 83 | printf("now sending %s\n", send_line); 84 | size_t rt = write(socket_fd, send_line, strlen(send_line)); 85 | if (rt < 0) { 86 | error(1, errno, "write failed "); 87 | } 88 | printf("send bytes: %zu \n", rt); 89 | } 90 | 91 | } 92 | } 93 | 94 | 95 | // 96 | // while (fgets(send_line, MAXLINE, stdin) != NULL) { 97 | // 98 | // if (strncmp(send_line, "exit", 4) == 0) { 99 | // shutdown(socket_fd, 1); 100 | // } 101 | // int i = strlen(send_line); 102 | // if (send_line[i - 1] == '\n') { 103 | // send_line[i - 1] = 0; 104 | // } 105 | // 106 | // printf("now sending %s\n", send_line); 107 | // size_t rt = write(socket_fd, send_line, strlen(send_line)); 108 | // if (rt < 0) { 109 | // error(1, errno, "write failed "); 110 | // } 111 | // printf("send bytes: %zu \n", rt); 112 | 113 | // n = read(socket_fd, recv_line, MAXLINE); 114 | // if (n < 0) { 115 | // error(1, errno, "server terminated"); 116 | // } else if (n == 0) { 117 | // shutdown(socket_fd, 1); 118 | // } 119 | // recv_line[n] = 0; 120 | // fputs(recv_line, stdout); 121 | // fputs("\n", stdout); 122 | } 123 | 124 | exit(0); 125 | } 126 | 127 | 128 | -------------------------------------------------------------------------------- /chap-11/tcpserver.c.bak: -------------------------------------------------------------------------------- 1 | // 2 | // Created by shengym on 2019-07-07. 3 | // 4 | 5 | #include "lib/common.h" 6 | 7 | static int count; 8 | 9 | static void sig_int(int signo) { 10 | printf("\nreceived %d datagrams\n", count); 11 | exit(0); 12 | } 13 | 14 | 15 | int main(int argc, char **argv) { 16 | int listenfd; 17 | listenfd = socket(AF_INET, SOCK_STREAM, 0); 18 | 19 | struct sockaddr_in server_addr; 20 | bzero(&server_addr, sizeof(server_addr)); 21 | server_addr.sin_family = AF_INET; 22 | server_addr.sin_addr.s_addr = htonl(INADDR_ANY); 23 | server_addr.sin_port = htons(SERV_PORT); 24 | 25 | int rt1 = bind(listenfd, (struct sockaddr *) &server_addr, sizeof(server_addr)); 26 | if (rt1 < 0) { 27 | error(1, errno, "bind failed "); 28 | } 29 | 30 | int rt2 = listen(listenfd, LISTENQ); 31 | if (rt2 < 0) { 32 | error(1, errno, "listen failed "); 33 | } 34 | 35 | signal(SIGINT, sig_int); 36 | 37 | int connfd; 38 | struct sockaddr_in client_addr; 39 | socklen_t client_len = sizeof(client_addr); 40 | 41 | if ((connfd = accept(listenfd, (struct sockaddr *) &client_addr, &client_len)) < 0) { 42 | error(1, errno, "bind failed "); 43 | } 44 | 45 | char message[MAXLINE]; 46 | count = 0; 47 | 48 | for (;;) { 49 | int n = read(connfd, message, MAXLINE); 50 | if (n < 0) { 51 | error(1, errno, "error read"); 52 | } else if (n == 0) { 53 | error(1, 0, "client closed"); 54 | } 55 | message[n] = 0; 56 | printf("received %d bytes: %s\n", n, message); 57 | count++; 58 | 59 | char send_line[MAXLINE]; 60 | sprintf(send_line, "Hi, %s", message); 61 | 62 | sleep(4); 63 | 64 | write(connfd, send_line, strlen(send_line)); 65 | } 66 | 67 | } 68 | 69 | 70 | -------------------------------------------------------------------------------- /chap-12/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(pingclient pingclient.c) 2 | target_link_libraries(pingclient yolanda) 3 | 4 | add_executable(pingserver pingserver.c) 5 | target_link_libraries(pingserver yolanda) 6 | -------------------------------------------------------------------------------- /chap-12/message_objecte.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by shengym on 2019-08-02. 3 | // 4 | 5 | #ifndef YOLANDA_MESSAGE_OBJECTE_H 6 | #define YOLANDA_MESSAGE_OBJECTE_H 7 | 8 | 9 | typedef struct { 10 | u_int32_t type; 11 | char data[1024]; 12 | } messageObject; 13 | 14 | #define MSG_PING 1 15 | #define MSG_PONG 2 16 | #define MSG_TYPE1 11 17 | #define MSG_TYPE2 21 18 | 19 | 20 | #endif //YOLANDA_MESSAGE_OBJECTE_H 21 | -------------------------------------------------------------------------------- /chap-12/pingclient.c: -------------------------------------------------------------------------------- 1 | #include "lib/common.h" 2 | #include "message_objecte.h" 3 | 4 | #define MAXLINE 4096 5 | #define KEEP_ALIVE_TIME 10 6 | #define KEEP_ALIVE_INTERVAL 3 7 | #define KEEP_ALIVE_PROBETIMES 3 8 | 9 | 10 | int main(int argc, char **argv) { 11 | if (argc != 2) { 12 | error(1, 0, "usage: tcpclient "); 13 | } 14 | 15 | int socket_fd; 16 | socket_fd = socket(AF_INET, SOCK_STREAM, 0); 17 | 18 | struct sockaddr_in server_addr; 19 | bzero(&server_addr, sizeof(server_addr)); 20 | server_addr.sin_family = AF_INET; 21 | server_addr.sin_port = htons(SERV_PORT); 22 | inet_pton(AF_INET, argv[1], &server_addr.sin_addr); 23 | 24 | socklen_t server_len = sizeof(server_addr); 25 | int connect_rt = connect(socket_fd, (struct sockaddr *) &server_addr, server_len); 26 | if (connect_rt < 0) { 27 | error(1, errno, "connect failed "); 28 | } 29 | 30 | char recv_line[MAXLINE + 1]; 31 | int n; 32 | 33 | fd_set readmask; 34 | fd_set allreads; 35 | 36 | 37 | struct timeval tv; 38 | int heartbeats = 0; 39 | 40 | tv.tv_sec = KEEP_ALIVE_TIME; 41 | tv.tv_usec = 0; 42 | 43 | messageObject messageObject; 44 | 45 | FD_ZERO(&allreads); 46 | FD_SET(0, &allreads); 47 | FD_SET(socket_fd, &allreads); 48 | for (;;) { 49 | readmask = allreads; 50 | int rc = select(socket_fd + 1, &readmask, NULL, NULL, &tv); 51 | if (rc < 0) { 52 | error(1, errno, "select failed"); 53 | } 54 | if (rc == 0) { 55 | if (++heartbeats > KEEP_ALIVE_PROBETIMES) { 56 | error(1, 0, "connection dead\n"); 57 | } 58 | printf("sending heartbeat #%d\n", heartbeats); 59 | messageObject.type = htonl(MSG_PING); 60 | rc = send(socket_fd, (char *) &messageObject, sizeof(messageObject), 0); 61 | if (rc < 0) { 62 | error(1, errno, "send failure"); 63 | } 64 | tv.tv_sec = KEEP_ALIVE_INTERVAL; 65 | continue; 66 | } 67 | if (FD_ISSET(socket_fd, &readmask)) { 68 | n = read(socket_fd, recv_line, MAXLINE); 69 | if (n < 0) { 70 | error(1, errno, "read error"); 71 | } else if (n == 0) { 72 | error(1, 0, "server terminated \n"); 73 | } 74 | printf("received heartbeat, make heartbeats to 0 \n"); 75 | heartbeats = 0; 76 | tv.tv_sec = KEEP_ALIVE_TIME; 77 | } 78 | } 79 | } 80 | 81 | -------------------------------------------------------------------------------- /chap-12/pingserver.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by shengym on 2019-07-07. 3 | // 4 | 5 | #include "lib/common.h" 6 | #include "message_objecte.h" 7 | 8 | static int count; 9 | 10 | static void sig_int(int signo) { 11 | printf("\nreceived %d datagrams\n", count); 12 | exit(0); 13 | } 14 | 15 | 16 | int main(int argc, char **argv) { 17 | if (argc != 2) { 18 | error(1, 0, "usage: tcpsever "); 19 | } 20 | 21 | int sleepingTime = atoi(argv[1]); 22 | 23 | int listenfd; 24 | listenfd = socket(AF_INET, SOCK_STREAM, 0); 25 | 26 | struct sockaddr_in server_addr; 27 | bzero(&server_addr, sizeof(server_addr)); 28 | server_addr.sin_family = AF_INET; 29 | server_addr.sin_addr.s_addr = htonl(INADDR_ANY); 30 | server_addr.sin_port = htons(SERV_PORT); 31 | 32 | int rt1 = bind(listenfd, (struct sockaddr *) &server_addr, sizeof(server_addr)); 33 | if (rt1 < 0) { 34 | error(1, errno, "bind failed "); 35 | } 36 | 37 | int rt2 = listen(listenfd, LISTENQ); 38 | if (rt2 < 0) { 39 | error(1, errno, "listen failed "); 40 | } 41 | 42 | signal(SIGINT, sig_int); 43 | signal(SIGPIPE, SIG_IGN); 44 | 45 | int connfd; 46 | struct sockaddr_in client_addr; 47 | socklen_t client_len = sizeof(client_addr); 48 | 49 | if ((connfd = accept(listenfd, (struct sockaddr *) &client_addr, &client_len)) < 0) { 50 | error(1, errno, "bind failed "); 51 | } 52 | 53 | messageObject message; 54 | count = 0; 55 | 56 | for (;;) { 57 | int n = read(connfd, (char *) &message, sizeof(messageObject)); 58 | if (n < 0) { 59 | error(1, errno, "error read"); 60 | } else if (n == 0) { 61 | error(1, 0, "client closed \n"); 62 | } 63 | 64 | printf("received %d bytes\n", n, message); 65 | count++; 66 | 67 | switch (ntohl(message.type)) { 68 | case MSG_TYPE1 : 69 | printf("process MSG_TYPE1 \n"); 70 | break; 71 | 72 | case MSG_TYPE2 : 73 | printf("process MSG_TYPE2 \n"); 74 | break; 75 | 76 | case MSG_PING: { 77 | messageObject pong_message; 78 | pong_message.type = MSG_PONG; 79 | sleep(sleepingTime); 80 | ssize_t rc = send(connfd, (char *) &pong_message, sizeof(pong_message), 0); 81 | if (rc < 0) 82 | error(1, errno, "send failure"); 83 | break; 84 | } 85 | 86 | default : 87 | error(1, 0, "unknown message type (%d)\n", ntohl(message.type)); 88 | } 89 | 90 | } 91 | 92 | } 93 | 94 | 95 | -------------------------------------------------------------------------------- /chap-13/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(batchwrite batchwrite.c) 2 | target_link_libraries(batchwrite yolanda) 3 | 4 | -------------------------------------------------------------------------------- /chap-13/batchwrite.c: -------------------------------------------------------------------------------- 1 | #include "lib/common.h" 2 | 3 | int main(int argc, char **argv) { 4 | if (argc != 2) { 5 | error(1, 0, "usage: batchwrite "); 6 | } 7 | 8 | int socket_fd; 9 | socket_fd = socket(AF_INET, SOCK_STREAM, 0); 10 | 11 | struct sockaddr_in server_addr; 12 | bzero(&server_addr, sizeof(server_addr)); 13 | server_addr.sin_family = AF_INET; 14 | server_addr.sin_port = htons(SERV_PORT); 15 | inet_pton(AF_INET, argv[1], &server_addr.sin_addr); 16 | 17 | socklen_t server_len = sizeof(server_addr); 18 | int connect_rt = connect(socket_fd, (struct sockaddr *) &server_addr, server_len); 19 | if (connect_rt < 0) { 20 | error(1, errno, "connect failed "); 21 | } 22 | 23 | char buf[128]; 24 | struct iovec iov[2]; 25 | 26 | char *send_one = "hello,"; 27 | iov[0].iov_base = send_one; 28 | iov[0].iov_len = strlen(send_one); 29 | iov[1].iov_base = buf; 30 | while (fgets(buf, sizeof(buf), stdin) != NULL) { 31 | iov[1].iov_len = strlen(buf); 32 | int n = htonl(iov[1].iov_len); 33 | if (writev(socket_fd, iov, 2) < 0) 34 | error(1, errno, "writev failure"); 35 | } 36 | exit(0); 37 | } 38 | 39 | -------------------------------------------------------------------------------- /chap-14/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(udpconnectclient udpconnectclient.c) 2 | target_link_libraries(udpconnectclient yolanda) 3 | 4 | add_executable(udpconnectserver udpconnectserver.c) 5 | target_link_libraries(udpconnectserver yolanda) 6 | 7 | add_executable(udpconnectclient02 udpconnectclient02.c) 8 | target_link_libraries(udpconnectclient02 yolanda) 9 | 10 | 11 | -------------------------------------------------------------------------------- /chap-14/udpconnectclient.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by shengym on 2019-07-12. 3 | // 4 | #include "lib/common.h" 5 | 6 | #define MAXLINE 4096 7 | 8 | int main(int argc, char **argv) { 9 | if (argc != 2) { 10 | error(1, 0, "usage: udpclient1 "); 11 | } 12 | 13 | int socket_fd; 14 | socket_fd = socket(AF_INET, SOCK_DGRAM, 0); 15 | 16 | struct sockaddr_in server_addr; 17 | bzero(&server_addr, sizeof(server_addr)); 18 | server_addr.sin_family = AF_INET; 19 | server_addr.sin_port = htons(SERV_PORT); 20 | inet_pton(AF_INET, argv[1], &server_addr.sin_addr); 21 | 22 | socklen_t server_len = sizeof(server_addr); 23 | 24 | if (connect(socket_fd, (struct sockaddr *) &server_addr, server_len)) { 25 | error(1, errno, "connect failed"); 26 | } 27 | 28 | struct sockaddr *reply_addr; 29 | reply_addr = malloc(server_len); 30 | 31 | char send_line[MAXLINE], recv_line[MAXLINE + 1]; 32 | socklen_t len; 33 | int n; 34 | 35 | while (fgets(send_line, MAXLINE, stdin) != NULL) { 36 | int i = strlen(send_line); 37 | if (send_line[i - 1] == '\n') { 38 | send_line[i - 1] = 0; 39 | } 40 | 41 | printf("now sending %s\n", send_line); 42 | size_t rt = sendto(socket_fd, send_line, strlen(send_line), 0, (struct sockaddr *) &server_addr, server_len); 43 | if (rt < 0) { 44 | error(1, errno, "sendto failed"); 45 | } 46 | printf("send bytes: %zu \n", rt); 47 | 48 | len = 0; 49 | recv_line[0] = 0; 50 | n = recvfrom(socket_fd, recv_line, MAXLINE, 0, reply_addr, &len); 51 | if (n < 0) 52 | error(1, errno, "recvfrom failed"); 53 | recv_line[n] = 0; 54 | fputs(recv_line, stdout); 55 | fputs("\n", stdout); 56 | 57 | } 58 | 59 | exit(0); 60 | } 61 | 62 | 63 | -------------------------------------------------------------------------------- /chap-14/udpconnectclient02.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by shengym on 2019-07-12. 3 | // 4 | 5 | #include "lib/common.h" 6 | 7 | 8 | # define NDG 2000 /* datagrams to send */ 9 | # define DGLEN 1400 /* length of each datagram */ 10 | # define MAXLINE 4096 11 | 12 | 13 | int main(int argc, char **argv) { 14 | if (argc != 2) { 15 | error(1, 0, "usage: udpclient2 "); 16 | } 17 | 18 | int socket_fd; 19 | socket_fd = socket(AF_INET, SOCK_DGRAM, 0); 20 | 21 | struct sockaddr_in server_addr; 22 | bzero(&server_addr, sizeof(server_addr)); 23 | server_addr.sin_family = AF_INET; 24 | server_addr.sin_port = htons(SERV_PORT); 25 | inet_pton(AF_INET, argv[1], &server_addr.sin_addr); 26 | 27 | socklen_t server_len = sizeof(server_addr); 28 | 29 | if (connect(socket_fd, (struct sockaddr *) &server_addr, server_len)) { 30 | error(1, errno, "connect failed"); 31 | } 32 | 33 | char send_line[MAXLINE], recv_line[MAXLINE + 1]; 34 | int n; 35 | 36 | while (fgets(send_line, MAXLINE, stdin) != NULL) { 37 | int i = strlen(send_line); 38 | if (send_line[i - 1] == '\n') { 39 | send_line[i - 1] = 0; 40 | } 41 | 42 | printf("now sending %s\n", send_line); 43 | size_t rt = send(socket_fd, send_line, strlen(send_line), 0); 44 | if (rt < 0) { 45 | error(1, errno, "send failed "); 46 | } 47 | printf("send bytes: %zu \n", rt); 48 | 49 | recv_line[0] = 0; 50 | n = recv(socket_fd, recv_line, MAXLINE, 0); 51 | if (n < 0) 52 | error(1, errno, "recv failed"); 53 | recv_line[n] = 0; 54 | fputs(recv_line, stdout); 55 | fputs("\n", stdout); 56 | } 57 | 58 | exit(0); 59 | } 60 | 61 | 62 | -------------------------------------------------------------------------------- /chap-14/udpconnectserver.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by shengym on 2019-07-13. 3 | // 4 | 5 | // 6 | // Created by shengym on 2019-07-07. 7 | // 8 | 9 | #include "lib/common.h" 10 | 11 | static int count; 12 | 13 | static void recvfrom_int(int signo) { 14 | printf("\nreceived %d datagrams\n", count); 15 | exit(0); 16 | } 17 | 18 | 19 | int main(int argc, char **argv) { 20 | int socket_fd; 21 | socket_fd = socket(AF_INET, SOCK_DGRAM, 0); 22 | 23 | struct sockaddr_in server_addr; 24 | bzero(&server_addr, sizeof(server_addr)); 25 | server_addr.sin_family = AF_INET; 26 | server_addr.sin_addr.s_addr = htonl(INADDR_ANY); 27 | server_addr.sin_port = htons(SERV_PORT); 28 | 29 | bind(socket_fd, (struct sockaddr *) &server_addr, sizeof(server_addr)); 30 | 31 | socklen_t client_len; 32 | char message[MAXLINE]; 33 | message[0] = 0; 34 | count = 0; 35 | 36 | signal(SIGINT, recvfrom_int); 37 | 38 | struct sockaddr_in client_addr; 39 | client_len = sizeof(client_addr); 40 | 41 | int n = recvfrom(socket_fd, message, MAXLINE, 0, (struct sockaddr *) &client_addr, &client_len); 42 | if (n < 0) { 43 | error(1, errno, "recvfrom failed"); 44 | } 45 | message[n] = 0; 46 | printf("received %d bytes: %s\n", n, message); 47 | 48 | if (connect(socket_fd, (struct sockaddr *) &client_addr, client_len)) { 49 | error(1, errno, "connect failed"); 50 | } 51 | 52 | while (strncmp(message, "goodbye", 7) != 0) { 53 | char send_line[MAXLINE]; 54 | sprintf(send_line, "Hi, %s", message); 55 | 56 | size_t rt = send(socket_fd, send_line, strlen(send_line), 0); 57 | if (rt < 0) { 58 | error(1, errno, "send failed "); 59 | } 60 | printf("send bytes: %zu \n", rt); 61 | 62 | size_t rc = recv(socket_fd, message, MAXLINE, 0); 63 | if (rc < 0) { 64 | error(1, errno, "recv failed"); 65 | } 66 | 67 | count++; 68 | } 69 | 70 | exit(0); 71 | } 72 | 73 | 74 | -------------------------------------------------------------------------------- /chap-15/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(addressused addressused.c) 2 | target_link_libraries(addressused yolanda) 3 | 4 | add_executable(addressused02 addressused02.c) 5 | target_link_libraries(addressused02 yolanda) 6 | -------------------------------------------------------------------------------- /chap-15/addressused.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by shengym on 2019-07-07. 3 | // 4 | 5 | #include "lib/common.h" 6 | 7 | static int count; 8 | 9 | static void sig_int(int signo) { 10 | printf("\nreceived %d datagrams\n", count); 11 | exit(0); 12 | } 13 | 14 | 15 | int main(int argc, char **argv) { 16 | int listenfd; 17 | listenfd = socket(AF_INET, SOCK_STREAM, 0); 18 | 19 | struct sockaddr_in server_addr; 20 | bzero(&server_addr, sizeof(server_addr)); 21 | server_addr.sin_family = AF_INET; 22 | server_addr.sin_addr.s_addr = htonl(INADDR_ANY); 23 | server_addr.sin_port = htons(SERV_PORT); 24 | 25 | int rt1 = bind(listenfd, (struct sockaddr *) &server_addr, sizeof(server_addr)); 26 | if (rt1 < 0) { 27 | error(1, errno, "bind failed "); 28 | } 29 | 30 | int rt2 = listen(listenfd, LISTENQ); 31 | if (rt2 < 0) { 32 | error(1, errno, "listen failed "); 33 | } 34 | 35 | signal(SIGPIPE, SIG_IGN); 36 | 37 | int connfd; 38 | struct sockaddr_in client_addr; 39 | socklen_t client_len = sizeof(client_addr); 40 | 41 | if ((connfd = accept(listenfd, (struct sockaddr *) &client_addr, &client_len)) < 0) { 42 | error(1, errno, "bind failed "); 43 | } 44 | 45 | char message[MAXLINE]; 46 | count = 0; 47 | 48 | for (;;) { 49 | int n = read(connfd, message, MAXLINE); 50 | if (n < 0) { 51 | error(1, errno, "error read"); 52 | } else if (n == 0) { 53 | error(1, 0, "client closed \n"); 54 | } 55 | message[n] = 0; 56 | printf("received %d bytes: %s\n", n, message); 57 | count++; 58 | } 59 | 60 | } 61 | 62 | 63 | -------------------------------------------------------------------------------- /chap-15/addressused02.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by shengym on 2019-07-07. 3 | // 4 | 5 | #include "lib/common.h" 6 | 7 | static int count; 8 | 9 | static void sig_int(int signo) { 10 | printf("\nreceived %d datagrams\n", count); 11 | exit(0); 12 | } 13 | 14 | 15 | int main(int argc, char **argv) { 16 | int listenfd; 17 | listenfd = socket(AF_INET, SOCK_STREAM, 0); 18 | 19 | struct sockaddr_in server_addr; 20 | bzero(&server_addr, sizeof(server_addr)); 21 | server_addr.sin_family = AF_INET; 22 | server_addr.sin_addr.s_addr = htonl(INADDR_ANY); 23 | server_addr.sin_port = htons(SERV_PORT); 24 | 25 | int on = 1; 26 | setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); 27 | 28 | int rt1 = bind(listenfd, (struct sockaddr *) &server_addr, sizeof(server_addr)); 29 | if (rt1 < 0) { 30 | error(1, errno, "bind failed "); 31 | } 32 | 33 | int rt2 = listen(listenfd, LISTENQ); 34 | if (rt2 < 0) { 35 | error(1, errno, "listen failed "); 36 | } 37 | 38 | signal(SIGPIPE, SIG_IGN); 39 | 40 | int connfd; 41 | struct sockaddr_in client_addr; 42 | socklen_t client_len = sizeof(client_addr); 43 | 44 | if ((connfd = accept(listenfd, (struct sockaddr *) &client_addr, &client_len)) < 0) { 45 | error(1, errno, "bind failed "); 46 | } 47 | 48 | char message[MAXLINE]; 49 | count = 0; 50 | 51 | for (;;) { 52 | int n = read(connfd, message, MAXLINE); 53 | if (n < 0) { 54 | error(1, errno, "error read"); 55 | } else if (n == 0) { 56 | error(1, 0, "client closed \n"); 57 | } 58 | message[n] = 0; 59 | printf("received %d bytes: %s\n", n, message); 60 | count++; 61 | } 62 | 63 | } 64 | 65 | 66 | -------------------------------------------------------------------------------- /chap-16/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(streamserver streamserver.c) 2 | target_link_libraries(streamserver yolanda) 3 | 4 | add_executable(streamclient streamclient.c) 5 | target_link_libraries(streamclient yolanda) 6 | -------------------------------------------------------------------------------- /chap-16/streamclient.c: -------------------------------------------------------------------------------- 1 | #include "lib/common.h" 2 | 3 | int main(int argc, char **argv) { 4 | if (argc != 2) { 5 | error(1, 0, "usage: tcpclient "); 6 | } 7 | 8 | int socket_fd; 9 | socket_fd = socket(AF_INET, SOCK_STREAM, 0); 10 | 11 | struct sockaddr_in server_addr; 12 | bzero(&server_addr, sizeof(server_addr)); 13 | server_addr.sin_family = AF_INET; 14 | server_addr.sin_port = htons(SERV_PORT); 15 | inet_pton(AF_INET, argv[1], &server_addr.sin_addr); 16 | 17 | socklen_t server_len = sizeof(server_addr); 18 | int connect_rt = connect(socket_fd, (struct sockaddr *) &server_addr, server_len); 19 | if (connect_rt < 0) { 20 | error(1, errno, "connect failed "); 21 | } 22 | 23 | struct { 24 | u_int32_t message_length; 25 | u_int32_t message_type; 26 | char data[128]; 27 | } message; 28 | 29 | 30 | int n; 31 | 32 | while (fgets(message.data, sizeof(message.data), stdin) != NULL) { 33 | n = strlen(message.data); 34 | message.message_length = htonl(n); 35 | message.message_type = 1; 36 | if (send(socket_fd, (char *) &message, sizeof(message.message_length) + sizeof(message.message_type) + n, 0) < 37 | 0) 38 | error(1, errno, "send failure"); 39 | 40 | } 41 | exit(0); 42 | } 43 | 44 | -------------------------------------------------------------------------------- /chap-16/streamserver.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by shengym on 2019-07-07. 3 | // 4 | 5 | #include "lib/common.h" 6 | 7 | static int count; 8 | 9 | static void sig_int(int signo) { 10 | printf("\nreceived %d datagrams\n", count); 11 | exit(0); 12 | } 13 | 14 | 15 | int main(int argc, char **argv) { 16 | int listenfd; 17 | listenfd = socket(AF_INET, SOCK_STREAM, 0); 18 | 19 | struct sockaddr_in server_addr; 20 | bzero(&server_addr, sizeof(server_addr)); 21 | server_addr.sin_family = AF_INET; 22 | server_addr.sin_addr.s_addr = htonl(INADDR_ANY); 23 | server_addr.sin_port = htons(SERV_PORT); 24 | 25 | int on = 1; 26 | setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); 27 | 28 | int rt1 = bind(listenfd, (struct sockaddr *) &server_addr, sizeof(server_addr)); 29 | if (rt1 < 0) { 30 | error(1, errno, "bind failed "); 31 | } 32 | 33 | int rt2 = listen(listenfd, LISTENQ); 34 | if (rt2 < 0) { 35 | error(1, errno, "listen failed "); 36 | } 37 | 38 | signal(SIGPIPE, SIG_IGN); 39 | 40 | int connfd; 41 | struct sockaddr_in client_addr; 42 | socklen_t client_len = sizeof(client_addr); 43 | 44 | if ((connfd = accept(listenfd, (struct sockaddr *) &client_addr, &client_len)) < 0) { 45 | error(1, errno, "bind failed "); 46 | } 47 | 48 | char buf[128]; 49 | count = 0; 50 | 51 | while (1) { 52 | int n = read_message(connfd, buf, sizeof(buf)); 53 | if (n < 0) { 54 | error(1, errno, "error read message"); 55 | } else if (n == 0) { 56 | error(1, 0, "client closed \n"); 57 | } 58 | buf[n] = 0; 59 | printf("received %d bytes: %s\n", n, buf); 60 | count++; 61 | } 62 | 63 | exit(0); 64 | 65 | } 66 | 67 | 68 | -------------------------------------------------------------------------------- /chap-17/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(reliable_client01 reliable_client01.c) 2 | target_link_libraries(reliable_client01 yolanda) 3 | 4 | add_executable(reliable_server01 reliable_server01.c) 5 | target_link_libraries(reliable_server01 yolanda) 6 | 7 | 8 | add_executable(reliable_server02 reliable_server02.c) 9 | target_link_libraries(reliable_server02 yolanda) 10 | 11 | add_executable(reliable_client02 reliable_client02.c) 12 | target_link_libraries(reliable_client02 yolanda) 13 | 14 | 15 | -------------------------------------------------------------------------------- /chap-17/reliable_client01.c: -------------------------------------------------------------------------------- 1 | #include "lib/common.h" 2 | 3 | # define MESSAGE_SIZE 102400000 4 | 5 | int main(int argc, char **argv) { 6 | if (argc != 2) { 7 | error(1, 0, "usage: reliable_client01 "); 8 | } 9 | 10 | int socket_fd = tcp_client(argv[1], SERV_PORT); 11 | char buf[129]; 12 | int len; 13 | int rc; 14 | 15 | while (fgets(buf, sizeof(buf), stdin) != NULL) { 16 | len = strlen(buf); 17 | rc = send(socket_fd, buf, len, 0); 18 | if (rc < 0) 19 | error(1, errno, "write failed"); 20 | sleep(3); 21 | rc = read(socket_fd, buf, sizeof(buf)); 22 | if (rc < 0) 23 | error(1, errno, "read failed"); 24 | else if (rc == 0) 25 | error(1, 0, "peer connection closed\n"); 26 | else 27 | fputs(buf, stdout); 28 | } 29 | exit(0); 30 | } 31 | 32 | -------------------------------------------------------------------------------- /chap-17/reliable_client02.c: -------------------------------------------------------------------------------- 1 | #include "lib/common.h" 2 | 3 | # define MESSAGE_SIZE 102400 4 | 5 | int main(int argc, char **argv) { 6 | if (argc != 2) { 7 | error(1, 0, "usage: reliable_client02 "); 8 | } 9 | 10 | int socket_fd = tcp_client(argv[1], SERV_PORT); 11 | 12 | signal(SIGPIPE, SIG_IGN); 13 | 14 | char *msg = "network programming"; 15 | ssize_t n_written; 16 | 17 | int count = 10000000; 18 | while (count > 0) { 19 | n_written = send(socket_fd, msg, strlen(msg), 0); 20 | fprintf(stdout, "send into buffer %ld \n", n_written); 21 | if (n_written <= 0) { 22 | error(1, errno, "send error"); 23 | return -1; 24 | } 25 | count--; 26 | } 27 | return 0; 28 | } 29 | 30 | -------------------------------------------------------------------------------- /chap-17/reliable_server01.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by shengym on 2019-07-07. 3 | // 4 | 5 | #include "lib/common.h" 6 | 7 | 8 | int main(int argc, char **argv) { 9 | int connfd; 10 | char buf[1024]; 11 | 12 | connfd = tcp_server(SERV_PORT); 13 | 14 | for (;;) { 15 | int n = read(connfd, buf, 1024); 16 | if (n < 0) { 17 | error(1, errno, "error read"); 18 | } else if (n == 0) { 19 | error(1, 0, "client closed \n"); 20 | } 21 | 22 | sleep(5); 23 | 24 | int write_nc = send(connfd, buf, n, 0); 25 | printf("send bytes: %zu \n", write_nc); 26 | if (write_nc < 0) { 27 | error(1, errno, "error write"); 28 | } 29 | } 30 | 31 | exit(0); 32 | 33 | } 34 | 35 | 36 | -------------------------------------------------------------------------------- /chap-17/reliable_server02.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by shengym on 2019-07-07. 3 | // 4 | 5 | #include "lib/common.h" 6 | 7 | 8 | int main(int argc, char **argv) { 9 | int connfd; 10 | char buf[1024]; 11 | int time = 0; 12 | 13 | connfd = tcp_server(SERV_PORT); 14 | 15 | while (1) { 16 | int n = read(connfd, buf, 1024); 17 | if (n < 0) { 18 | error(1, errno, "error read"); 19 | } else if (n == 0) { 20 | error(1, 0, "client closed \n"); 21 | } 22 | 23 | time++; 24 | fprintf(stdout, "1K read for %d \n", time); 25 | usleep(10000); 26 | } 27 | 28 | exit(0); 29 | 30 | } 31 | 32 | 33 | -------------------------------------------------------------------------------- /chap-18/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(bufferclient bufferclient.c) 2 | target_link_libraries(bufferclient yolanda) 3 | 4 | add_executable(samplebuffer01 samplebuffer01.c) 5 | target_link_libraries(samplebuffer01 yolanda) 6 | 7 | add_executable(samplebuffer02 samplebuffer02.c) 8 | target_link_libraries(samplebuffer02 yolanda) 9 | 10 | add_executable(samplebuffer03 samplebuffer03.c) 11 | target_link_libraries(samplebuffer03 yolanda) 12 | -------------------------------------------------------------------------------- /chap-18/bufferclient.c: -------------------------------------------------------------------------------- 1 | #include "lib/common.h" 2 | 3 | int main(int argc, char **argv) { 4 | if (argc != 2) { 5 | error(1, 0, "usage: tcpclient "); 6 | } 7 | 8 | int socket_fd; 9 | socket_fd = socket(AF_INET, SOCK_STREAM, 0); 10 | 11 | struct sockaddr_in server_addr; 12 | bzero(&server_addr, sizeof(server_addr)); 13 | server_addr.sin_family = AF_INET; 14 | server_addr.sin_port = htons(SERV_PORT); 15 | inet_pton(AF_INET, argv[1], &server_addr.sin_addr); 16 | 17 | socklen_t server_len = sizeof(server_addr); 18 | int connect_rt = connect(socket_fd, (struct sockaddr *) &server_addr, server_len); 19 | if (connect_rt < 0) { 20 | error(1, errno, "connect failed "); 21 | } 22 | 23 | 24 | char buf[12]; 25 | int n; 26 | 27 | while (fgets(buf, sizeof(buf), stdin) != NULL) { 28 | n = strlen(buf); 29 | if (send(socket_fd, (char *) &buf, n, 0) < 0) 30 | error(1, errno, "send failure"); 31 | 32 | } 33 | exit(0); 34 | } 35 | 36 | -------------------------------------------------------------------------------- /chap-18/samplebuffer01.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by shengym on 2019-07-07. 3 | // 4 | 5 | #include "lib/common.h" 6 | 7 | static int count; 8 | 9 | static void sig_int(int signo) { 10 | printf("\nreceived %d datagrams\n", count); 11 | exit(0); 12 | } 13 | 14 | 15 | int main(int argc, char **argv) { 16 | int listenfd; 17 | listenfd = socket(AF_INET, SOCK_STREAM, 0); 18 | 19 | struct sockaddr_in server_addr; 20 | bzero(&server_addr, sizeof(server_addr)); 21 | server_addr.sin_family = AF_INET; 22 | server_addr.sin_addr.s_addr = htonl(INADDR_ANY); 23 | server_addr.sin_port = htons(SERV_PORT); 24 | 25 | int on = 1; 26 | setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); 27 | 28 | int rt1 = bind(listenfd, (struct sockaddr *) &server_addr, sizeof(server_addr)); 29 | if (rt1 < 0) { 30 | error(1, errno, "bind failed "); 31 | } 32 | 33 | int rt2 = listen(listenfd, LISTENQ); 34 | if (rt2 < 0) { 35 | error(1, errno, "listen failed "); 36 | } 37 | 38 | signal(SIGPIPE, SIG_IGN); 39 | 40 | int connfd; 41 | struct sockaddr_in client_addr; 42 | socklen_t client_len = sizeof(client_addr); 43 | 44 | if ((connfd = accept(listenfd, (struct sockaddr *) &client_addr, &client_len)) < 0) { 45 | error(1, errno, "bind failed "); 46 | } 47 | 48 | char buffer[128]; 49 | while (1) { 50 | char Response[] = "COMMAND OK"; 51 | 52 | int nBytes = recv(connfd, buffer, sizeof(buffer), 0); 53 | if (nBytes == -1) { 54 | error(1, errno, "error read message"); 55 | } else if (nBytes == 0) { 56 | error(1, 0, "client closed \n"); 57 | } 58 | 59 | buffer[nBytes] = '\0'; 60 | 61 | if (strcmp(buffer, "quit") == 0) { 62 | printf("client quit\n"); 63 | send(socket, Response, sizeof(Response), 0); 64 | } 65 | 66 | printf("received %d bytes: %s\n", nBytes, buffer); 67 | } 68 | 69 | exit(0); 70 | } 71 | 72 | 73 | -------------------------------------------------------------------------------- /chap-18/samplebuffer02.c: -------------------------------------------------------------------------------- 1 | #include "lib/common.h" 2 | 3 | int main(int argc, char **argv) { 4 | if (argc != 2) { 5 | error(1, 0, "usage: tcpclient "); 6 | } 7 | 8 | int socket_fd; 9 | socket_fd = socket(AF_INET, SOCK_STREAM, 0); 10 | 11 | struct sockaddr_in server_addr; 12 | bzero(&server_addr, sizeof(server_addr)); 13 | server_addr.sin_family = AF_INET; 14 | server_addr.sin_port = htons(SERV_PORT); 15 | inet_pton(AF_INET, argv[1], &server_addr.sin_addr); 16 | 17 | socklen_t server_len = sizeof(server_addr); 18 | int connect_rt = connect(socket_fd, (struct sockaddr *) &server_addr, server_len); 19 | if (connect_rt < 0) { 20 | error(1, errno, "connect failed "); 21 | } 22 | 23 | struct { 24 | u_int32_t message_length; 25 | u_int32_t message_type; 26 | char data[128]; 27 | } message; 28 | 29 | int n = 65535; 30 | message.message_length = htonl(n); 31 | message.message_type = 1; 32 | char buf[128] = "just for fun\0"; 33 | strncpy(message.data, buf, strlen(buf)); 34 | if (send(socket_fd, (char *) &message, 35 | sizeof(message.message_length) + sizeof(message.message_type) + strlen(message.data), 0) < 0) 36 | error(1, errno, "send failure"); 37 | 38 | sleep(100); 39 | exit(0); 40 | } 41 | 42 | -------------------------------------------------------------------------------- /chap-18/samplebuffer03.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by shengym on 2019-07-07. 3 | // 4 | 5 | #include "lib/common.h" 6 | 7 | static int count; 8 | 9 | static void sig_int(int signo) { 10 | printf("\nreceived %d datagrams\n", count); 11 | exit(0); 12 | } 13 | 14 | 15 | int main(int argc, char **argv) { 16 | int listenfd; 17 | listenfd = socket(AF_INET, SOCK_STREAM, 0); 18 | 19 | struct sockaddr_in server_addr; 20 | bzero(&server_addr, sizeof(server_addr)); 21 | server_addr.sin_family = AF_INET; 22 | server_addr.sin_addr.s_addr = htonl(INADDR_ANY); 23 | server_addr.sin_port = htons(SERV_PORT); 24 | 25 | int on = 1; 26 | setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); 27 | 28 | int rt1 = bind(listenfd, (struct sockaddr *) &server_addr, sizeof(server_addr)); 29 | if (rt1 < 0) { 30 | error(1, errno, "bind failed "); 31 | } 32 | 33 | int rt2 = listen(listenfd, LISTENQ); 34 | if (rt2 < 0) { 35 | error(1, errno, "listen failed "); 36 | } 37 | 38 | signal(SIGPIPE, SIG_IGN); 39 | 40 | int connfd; 41 | struct sockaddr_in client_addr; 42 | socklen_t client_len = sizeof(client_addr); 43 | 44 | if ((connfd = accept(listenfd, (struct sockaddr *) &client_addr, &client_len)) < 0) { 45 | error(1, errno, "bind failed "); 46 | } 47 | 48 | char buf[10]; 49 | 50 | while (1) { 51 | int nBytes = readline(connfd, buf,10); 52 | if (nBytes == -1) { 53 | error(1, errno, "error read message"); 54 | } else if (nBytes == 0) { 55 | error(1, 0, "client closed \n"); 56 | } 57 | 58 | printf("received %d bytes: %s\n", nBytes, buf); 59 | } 60 | 61 | exit(0); 62 | 63 | } 64 | 65 | 66 | -------------------------------------------------------------------------------- /chap-20/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(select01 select01.c) 2 | target_link_libraries(select01 yolanda) 3 | -------------------------------------------------------------------------------- /chap-20/select01.c: -------------------------------------------------------------------------------- 1 | #include "lib/common.h" 2 | 3 | #define MAXLINE 1024 4 | 5 | 6 | int main(int argc, char **argv) { 7 | if (argc != 2) { 8 | error(1, 0, "usage: select01 "); 9 | } 10 | int socket_fd = tcp_client(argv[1], SERV_PORT); 11 | 12 | char recv_line[MAXLINE], send_line[MAXLINE]; 13 | int n; 14 | 15 | fd_set readmask; 16 | fd_set allreads; 17 | FD_ZERO(&allreads); 18 | FD_SET(0, &allreads); 19 | FD_SET(socket_fd, &allreads); 20 | 21 | for (;;) { 22 | readmask = allreads; 23 | int rc = select(socket_fd + 1, &readmask, NULL, NULL, NULL); 24 | 25 | if (rc <= 0) { 26 | error(1, errno, "select failed"); 27 | } 28 | 29 | if (FD_ISSET(socket_fd, &readmask)) { 30 | n = read(socket_fd, recv_line, MAXLINE); 31 | if (n < 0) { 32 | error(1, errno, "read error"); 33 | } else if (n == 0) { 34 | error(1, 0, "server terminated \n"); 35 | } 36 | recv_line[n] = 0; 37 | fputs(recv_line, stdout); 38 | fputs("\n", stdout); 39 | } 40 | 41 | if (FD_ISSET(STDIN_FILENO, &readmask)) { 42 | if (fgets(send_line, MAXLINE, stdin) != NULL) { 43 | int i = strlen(send_line); 44 | if (send_line[i - 1] == '\n') { 45 | send_line[i - 1] = 0; 46 | } 47 | 48 | printf("now sending %s\n", send_line); 49 | ssize_t rt = write(socket_fd, send_line, strlen(send_line)); 50 | if (rt < 0) { 51 | error(1, errno, "write failed "); 52 | } 53 | printf("send bytes: %zu \n", rt); 54 | } 55 | } 56 | } 57 | 58 | } 59 | 60 | 61 | -------------------------------------------------------------------------------- /chap-21/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(pollserver pollserver.c) 2 | target_link_libraries(pollserver yolanda) 3 | -------------------------------------------------------------------------------- /chap-21/pollserver.c: -------------------------------------------------------------------------------- 1 | #include "lib/common.h" 2 | 3 | #define INIT_SIZE 128 4 | 5 | int main(int argc, char **argv) { 6 | int listen_fd, connected_fd; 7 | int ready_number; 8 | ssize_t n; 9 | char buf[MAXLINE]; 10 | struct sockaddr_in client_addr; 11 | 12 | listen_fd = tcp_server_listen(SERV_PORT); 13 | 14 | //初始化pollfd数组,这个数组的第一个元素是listen_fd,其余的用来记录将要连接的connect_fd 15 | struct pollfd event_set[INIT_SIZE]; 16 | event_set[0].fd = listen_fd; 17 | event_set[0].events = POLLRDNORM; 18 | 19 | // 用-1表示这个数组位置还没有被占用 20 | int i; 21 | for (i = 1; i < INIT_SIZE; i++) { 22 | event_set[i].fd = -1; 23 | } 24 | 25 | for (;;) { 26 | if ((ready_number = poll(event_set, INIT_SIZE, -1)) < 0) { 27 | error(1, errno, "poll failed "); 28 | } 29 | 30 | if (event_set[0].revents & POLLRDNORM) { 31 | socklen_t client_len = sizeof(client_addr); 32 | connected_fd = accept(listen_fd, (struct sockaddr *) &client_addr, &client_len); 33 | 34 | //找到一个可以记录该连接套接字的位置 35 | for (i = 1; i < INIT_SIZE; i++) { 36 | if (event_set[i].fd < 0) { 37 | event_set[i].fd = connected_fd; 38 | event_set[i].events = POLLRDNORM; 39 | break; 40 | } 41 | } 42 | 43 | if (i == INIT_SIZE) { 44 | error(1, errno, "can not hold so many clients"); 45 | } 46 | 47 | if (--ready_number <= 0) 48 | continue; 49 | } 50 | 51 | for (i = 1; i < INIT_SIZE; i++) { 52 | int socket_fd; 53 | if ((socket_fd = event_set[i].fd) < 0) 54 | continue; 55 | if (event_set[i].revents & (POLLRDNORM | POLLERR)) { 56 | if ((n = read(socket_fd, buf, MAXLINE)) > 0) { 57 | if (write(socket_fd, buf, n) < 0) { 58 | error(1, errno, "write error"); 59 | } 60 | } else if (n == 0 || errno == ECONNRESET) { 61 | close(socket_fd); 62 | event_set[i].fd = -1; 63 | } else { 64 | error(1, errno, "read error"); 65 | } 66 | 67 | if (--ready_number <= 0) 68 | break; 69 | } 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /chap-21/pollserver02.c: -------------------------------------------------------------------------------- 1 | #include "lib/common.h" 2 | 3 | #define INIT_SIZE 24 4 | 5 | struct pollop { 6 | int event_count; 7 | int nfds; 8 | int realloc_copy; 9 | struct pollfd *event_set; 10 | struct pollfd *event_set_copy; 11 | }; 12 | 13 | static struct pollop *my_pollop; 14 | 15 | void init_event_set() { 16 | my_pollop = malloc(sizeof(struct pollop)); 17 | my_pollop->event_count = my_pollop->nfds = my_pollop->realloc_copy = 0; 18 | 19 | my_pollop->event_set = malloc(INIT_SIZE * sizeof(struct pollfd)); 20 | 21 | } 22 | 23 | void add_event_set(int fd, int event) { 24 | //找到一个可以记录该连接套接字的位置 25 | for (i = 1; i < FOPEN_MAX; i++) { 26 | if (client[i].fd < 0) { 27 | client[i].fd = connected_fd; 28 | client[i].events = POLLRDNORM; 29 | break; 30 | } 31 | } 32 | } 33 | 34 | 35 | int main(int argc, char **argv) { 36 | int listen_fd, connected_fd; 37 | int ready_number; 38 | ssize_t n; 39 | char buf[MAXLINE]; 40 | struct sockaddr_in client_addr; 41 | 42 | listen_fd = tcp_server_listen(SERV_PORT); 43 | 44 | //初始化pollfd数组,这个数组的第一个元素是listen_fd,其余的用来记录将要连接的connect_fd 45 | struct pollfd client[FOPEN_MAX]; 46 | client[0].fd = listen_fd; 47 | client[0].events = POLLRDNORM; 48 | 49 | // 用-1表示这个数组位置还没有被占用 50 | int i; 51 | for (i = 1; i < FOPEN_MAX; i++) 52 | client[i].fd = -1; 53 | int maxi = 0; 54 | 55 | 56 | for (;;) { 57 | if ((ready_number = poll(client, maxi + 1, -1)) < 0) { 58 | error(1, errno, "poll failed "); 59 | } 60 | 61 | if (client[0].revents & POLLRDNORM) { 62 | socklen_t client_len = sizeof(client_addr); 63 | connected_fd = accept(listen_fd, (struct sockaddr *) &client_addr, &client_len); 64 | 65 | add_event_set(connected_fd,POLLRDNORM); 66 | 67 | if (i == FOPEN_MAX) { 68 | error(1, errno, "can not hold so many clients"); 69 | } 70 | 71 | if (i > maxi) 72 | maxi = i; 73 | 74 | if (--ready_number <= 0) 75 | continue; 76 | } 77 | 78 | for (i = 1; i <= maxi; i++) { 79 | int socket_fd; 80 | if ((socket_fd = client[i].fd) < 0) 81 | continue; 82 | if (client[i].revents & (POLLRDNORM | POLLERR)) { 83 | if ((n = read(socket_fd, buf, MAXLINE)) < 0) { 84 | if (errno == ECONNRESET) { 85 | close(socket_fd); 86 | client[i].fd = -1; 87 | } else 88 | error(1, errno, "read error"); 89 | } else if (n == 0) { 90 | close(socket_fd); 91 | client[i].fd = -1; 92 | } else { 93 | if (write(socket_fd, buf, n) < 0) { 94 | error(1, errno, "write error"); 95 | } 96 | } 97 | 98 | if (--ready_number <= 0) 99 | break; 100 | } 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /chap-22/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(nonblockingserver nonblockingserver.c) 2 | target_link_libraries(nonblockingserver yolanda) 3 | 4 | 5 | add_executable(nonblockingclient nonblockingclient.c) 6 | target_link_libraries(nonblockingclient yolanda) 7 | -------------------------------------------------------------------------------- /chap-22/nonblockingclient.c: -------------------------------------------------------------------------------- 1 | #include "lib/common.h" 2 | 3 | #define MAXLINE 4096 4 | #define KEEP_ALIVE_TIME 10 5 | #define KEEP_ALIVE_INTERVAL 3 6 | #define KEEP_ALIVE_PROBETIMES 3 7 | 8 | 9 | int main(int argc, char **argv) { 10 | if (argc != 2) { 11 | error(1, 0, "usage: nonblockingclient "); 12 | } 13 | 14 | int socket_fd; 15 | socket_fd = socket(AF_INET, SOCK_STREAM, 0); 16 | 17 | struct sockaddr_in server_addr; 18 | bzero(&server_addr, sizeof(server_addr)); 19 | server_addr.sin_family = AF_INET; 20 | server_addr.sin_port = htons(SERV_PORT); 21 | inet_pton(AF_INET, argv[1], &server_addr.sin_addr); 22 | 23 | socklen_t server_len = sizeof(server_addr); 24 | int connect_rt = connect(socket_fd, (struct sockaddr *) &server_addr, server_len); 25 | if (connect_rt < 0) { 26 | error(1, errno, "connect failed "); 27 | } 28 | 29 | struct linger ling; 30 | ling.l_onoff = 1; 31 | ling.l_linger = 0; 32 | setsockopt(socket_fd, SOL_SOCKET, SO_LINGER, &ling, sizeof(ling)); 33 | close(socket_fd); 34 | 35 | exit(0); 36 | } 37 | 38 | -------------------------------------------------------------------------------- /chap-22/nonblockingserver.c: -------------------------------------------------------------------------------- 1 | #include "lib/common.h" 2 | 3 | #define MAX_LINE 1024 4 | #define FD_INIT_SIZE 128 5 | 6 | char rot13_char(char c) { 7 | if ((c >= 'a' && c <= 'm') || (c >= 'A' && c <= 'M')) 8 | return c + 13; 9 | else if ((c >= 'n' && c <= 'z') || (c >= 'N' && c <= 'Z')) 10 | return c - 13; 11 | else 12 | return c; 13 | } 14 | 15 | //数据缓冲区 16 | struct Buffer { 17 | int connect_fd; //连接字 18 | char buffer[MAX_LINE]; //实际缓冲 19 | size_t writeIndex; //缓冲写入位置 20 | size_t readIndex; //缓冲读取位置 21 | int readable; //是否可以读 22 | }; 23 | 24 | 25 | //分配一个Buffer对象,初始化writeIdnex和readIndex等 26 | struct Buffer *alloc_Buffer() { 27 | struct Buffer *buffer = malloc(sizeof(struct Buffer)); 28 | if (!buffer) 29 | return NULL; 30 | buffer->connect_fd = 0; 31 | buffer->writeIndex = buffer->readIndex = buffer->readable = 0; 32 | return buffer; 33 | } 34 | 35 | //释放Buffer对象 36 | void free_Buffer(struct Buffer *buffer) { 37 | free(buffer); 38 | } 39 | 40 | //这里从fd套接字读取数据,数据先读取到本地buf数组中,再逐个拷贝到buffer对象缓冲中 41 | int onSocketRead(int fd, struct Buffer *buffer) { 42 | char buf[1024]; 43 | int i; 44 | ssize_t result; 45 | while (1) { 46 | result = recv(fd, buf, sizeof(buf), 0); 47 | if (result <= 0) 48 | break; 49 | 50 | //按char对每个字节进行拷贝,每个字节都会先调用rot13_char来完成编码,之后拷贝到buffer对象的缓冲中, 51 | //其中writeIndex标志了缓冲中写的位置 52 | for (i = 0; i < result; ++i) { 53 | if (buffer->writeIndex < sizeof(buffer->buffer)) 54 | buffer->buffer[buffer->writeIndex++] = rot13_char(buf[i]); 55 | //如果读取了回车符,则认为client端发送结束,此时可以把编码后的数据回送给客户端 56 | if (buf[i] == '\n') { 57 | buffer->readable = 1; //缓冲区可以读 58 | } 59 | } 60 | } 61 | 62 | if (result == 0) { 63 | return 1; 64 | } else if (result < 0) { 65 | if (errno == EAGAIN) 66 | return 0; 67 | return -1; 68 | } 69 | 70 | return 0; 71 | } 72 | 73 | //从buffer对象的readIndex开始读,一直读到writeIndex的位置,这段区间是有效数据 74 | int onSocketWrite(int fd, struct Buffer *buffer) { 75 | while (buffer->readIndex < buffer->writeIndex) { 76 | ssize_t result = send(fd, buffer->buffer + buffer->readIndex, buffer->writeIndex - buffer->readIndex, 0); 77 | if (result < 0) { 78 | if (errno == EAGAIN) 79 | return 0; 80 | return -1; 81 | } 82 | 83 | buffer->readIndex += result; 84 | } 85 | 86 | //readindex已经追上writeIndex,说明有效发送区间已经全部读完,将readIndex和writeIndex设置为0,复用这段缓冲 87 | if (buffer->readIndex == buffer->writeIndex) 88 | buffer->readIndex = buffer->writeIndex = 0; 89 | 90 | //缓冲数据已经全部读完,不需要再读 91 | buffer->readable = 0; 92 | 93 | return 0; 94 | } 95 | 96 | 97 | int main(int argc, char **argv) { 98 | int listen_fd; 99 | int i, maxfd; 100 | 101 | struct Buffer *buffer[FD_INIT_SIZE]; 102 | for (i = 0; i < FD_INIT_SIZE; ++i) { 103 | buffer[i] = alloc_Buffer(); 104 | } 105 | 106 | listen_fd = tcp_nonblocking_server_listen(SERV_PORT); 107 | 108 | fd_set readset, writeset, exset; 109 | FD_ZERO(&readset); 110 | FD_ZERO(&writeset); 111 | FD_ZERO(&exset); 112 | 113 | while (1) { 114 | maxfd = listen_fd; 115 | 116 | FD_ZERO(&readset); 117 | FD_ZERO(&writeset); 118 | FD_ZERO(&exset); 119 | 120 | // listener加入readset 121 | FD_SET(listen_fd, &readset); 122 | 123 | for (i = 0; i < FD_INIT_SIZE; ++i) { 124 | if (buffer[i]->connect_fd > 0) { 125 | if (buffer[i]->connect_fd > maxfd) 126 | maxfd = buffer[i]->connect_fd; 127 | FD_SET(buffer[i]->connect_fd, &readset); 128 | if (buffer[i]->readable) { 129 | FD_SET(buffer[i]->connect_fd, &writeset); 130 | } 131 | } 132 | } 133 | 134 | if (select(maxfd + 1, &readset, &writeset, &exset, NULL) < 0) { 135 | error(1, errno, "select error"); 136 | } 137 | 138 | if (FD_ISSET(listen_fd, &readset)) { 139 | printf("listening socket readable\n"); 140 | sleep(5); 141 | struct sockaddr_storage ss; 142 | socklen_t slen = sizeof(ss); 143 | int fd = accept(listen_fd, (struct sockaddr *) &ss, &slen); 144 | if (fd < 0) { 145 | error(1, errno, "accept failed"); 146 | } else if (fd > FD_INIT_SIZE) { 147 | error(1, 0, "too many connections"); 148 | close(fd); 149 | } else { 150 | make_nonblocking(fd); 151 | if (buffer[fd]->connect_fd == 0) { 152 | buffer[fd]->connect_fd = fd; 153 | } else { 154 | error(1, 0, "too many connections"); 155 | } 156 | } 157 | } 158 | 159 | for (i = 0; i < maxfd + 1; ++i) { 160 | int r = 0; 161 | if (i == listen_fd) 162 | continue; 163 | 164 | if (FD_ISSET(i, &readset)) { 165 | r = onSocketRead(i, buffer[i]); 166 | } 167 | if (r == 0 && FD_ISSET(i, &writeset)) { 168 | r = onSocketWrite(i, buffer[i]); 169 | } 170 | if (r) { 171 | buffer[i]->connect_fd = 0; 172 | close(i); 173 | } 174 | } 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /chap-23/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | if (EPOLL_EXISTS) 2 | add_executable(epoll01 epoll01.c) 3 | target_link_libraries(epoll01 yolanda) 4 | 5 | add_executable(epoll02 epoll02.c) 6 | target_link_libraries(epoll02 yolanda) 7 | 8 | add_executable(epoll03 epoll03.c) 9 | target_link_libraries(epoll03 yolanda) 10 | endif () -------------------------------------------------------------------------------- /chap-23/epoll01.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "lib/common.h" 3 | 4 | #define MAXEVENTS 128 5 | 6 | char rot13_char(char c) { 7 | if ((c >= 'a' && c <= 'm') || (c >= 'A' && c <= 'M')) 8 | return c + 13; 9 | else if ((c >= 'n' && c <= 'z') || (c >= 'N' && c <= 'Z')) 10 | return c - 13; 11 | else 12 | return c; 13 | } 14 | 15 | int main(int argc, char **argv) { 16 | int listen_fd, socket_fd; 17 | int n, i; 18 | int efd; 19 | struct epoll_event event; 20 | struct epoll_event *events; 21 | 22 | listen_fd = tcp_nonblocking_server_listen(SERV_PORT); 23 | 24 | efd = epoll_create1(0); 25 | if (efd == -1) { 26 | error(1, errno, "epoll create failed"); 27 | } 28 | 29 | event.data.fd = listen_fd; 30 | event.events = EPOLLIN | EPOLLET; 31 | if (epoll_ctl(efd, EPOLL_CTL_ADD, listen_fd, &event) == -1) { 32 | error(1, errno, "epoll_ctl add listen fd failed"); 33 | } 34 | 35 | /* Buffer where events are returned */ 36 | events = calloc(MAXEVENTS, sizeof(event)); 37 | 38 | while (1) { 39 | n = epoll_wait(efd, events, MAXEVENTS, -1); 40 | printf("epoll_wait wakeup\n"); 41 | for (i = 0; i < n; i++) { 42 | if ((events[i].events & EPOLLERR) || 43 | (events[i].events & EPOLLHUP) || 44 | (!(events[i].events & EPOLLIN))) { 45 | fprintf(stderr, "epoll error\n"); 46 | close(events[i].data.fd); 47 | continue; 48 | } else if (listen_fd == events[i].data.fd) { 49 | struct sockaddr_storage ss; 50 | socklen_t slen = sizeof(ss); 51 | int fd = accept(listen_fd, (struct sockaddr *) &ss, &slen); 52 | if (fd < 0) { 53 | error(1, errno, "accept failed"); 54 | } else { 55 | make_nonblocking(fd); 56 | event.data.fd = fd; 57 | event.events = EPOLLIN | EPOLLET; //edge-triggered 58 | if (epoll_ctl(efd, EPOLL_CTL_ADD, fd, &event) == -1) { 59 | error(1, errno, "epoll_ctl add connection fd failed"); 60 | } 61 | } 62 | continue; 63 | } else { 64 | socket_fd = events[i].data.fd; 65 | printf("get event on socket fd == %d \n", socket_fd); 66 | while (1) { 67 | char buf[512]; 68 | if ((n = read(socket_fd, buf, sizeof(buf))) < 0) { 69 | if (errno != EAGAIN) { 70 | error(1, errno, "read error"); 71 | close(socket_fd); 72 | } 73 | break; 74 | } else if (n == 0) { 75 | close(socket_fd); 76 | break; 77 | } else { 78 | for (i = 0; i < n; ++i) { 79 | buf[i] = rot13_char(buf[i]); 80 | } 81 | if (write(socket_fd, buf, n) < 0) { 82 | error(1, errno, "write error"); 83 | } 84 | } 85 | } 86 | } 87 | } 88 | } 89 | 90 | free(events); 91 | close(listen_fd); 92 | } 93 | -------------------------------------------------------------------------------- /chap-23/epoll02.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "lib/common.h" 3 | 4 | #define MAXEVENTS 128 5 | 6 | int main(int argc, char **argv) { 7 | int listen_fd, socket_fd; 8 | int n, i; 9 | int efd; 10 | struct epoll_event event; 11 | struct epoll_event *events; 12 | 13 | listen_fd = tcp_nonblocking_server_listen(SERV_PORT); 14 | 15 | efd = epoll_create1(0); 16 | if (efd == -1) { 17 | error(1, errno, "epoll create failed"); 18 | } 19 | 20 | event.data.fd = listen_fd; 21 | event.events = EPOLLIN | EPOLLET; 22 | if (epoll_ctl(efd, EPOLL_CTL_ADD, listen_fd, &event) == -1) { 23 | error(1, errno, "epoll_ctl add listen fd failed"); 24 | } 25 | 26 | /* Buffer where events are returned */ 27 | events = calloc(MAXEVENTS, sizeof(event)); 28 | 29 | while (1) { 30 | n = epoll_wait(efd, events, MAXEVENTS, -1); 31 | printf("epoll_wait wakeup\n"); 32 | for (i = 0; i < n; i++) { 33 | if ((events[i].events & EPOLLERR) || 34 | (events[i].events & EPOLLHUP) || 35 | (!(events[i].events & EPOLLIN))) { 36 | fprintf(stderr, "epoll error\n"); 37 | close(events[i].data.fd); 38 | continue; 39 | } else if (listen_fd == events[i].data.fd) { 40 | struct sockaddr_storage ss; 41 | socklen_t slen = sizeof(ss); 42 | int fd = accept(listen_fd, (struct sockaddr *) &ss, &slen); 43 | if (fd < 0) { 44 | error(1, errno, "accept failed"); 45 | } else { 46 | make_nonblocking(fd); 47 | event.data.fd = fd; 48 | event.events = EPOLLIN | EPOLLET; //edge-triggered 49 | if (epoll_ctl(efd, EPOLL_CTL_ADD, fd, &event) == -1) { 50 | error(1, errno, "epoll_ctl add connection fd failed"); 51 | } 52 | } 53 | continue; 54 | } else { 55 | socket_fd = events[i].data.fd; 56 | printf("get event on socket fd == %d \n", socket_fd); 57 | } 58 | } 59 | } 60 | 61 | free(events); 62 | close(listen_fd); 63 | 64 | } 65 | -------------------------------------------------------------------------------- /chap-23/epoll03.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "lib/common.h" 3 | 4 | #define MAXEVENTS 128 5 | 6 | 7 | int main(int argc, char **argv) { 8 | int listen_fd, socket_fd; 9 | int n, i; 10 | int efd; 11 | struct epoll_event event; 12 | struct epoll_event *events; 13 | 14 | listen_fd = tcp_nonblocking_server_listen(SERV_PORT); 15 | 16 | efd = epoll_create1(0); 17 | if (efd == -1) { 18 | error(1, errno, "epoll create failed"); 19 | } 20 | 21 | event.data.fd = listen_fd; 22 | event.events = EPOLLIN | EPOLLET; 23 | if (epoll_ctl(efd, EPOLL_CTL_ADD, listen_fd, &event) == -1) { 24 | error(1, errno, "epoll_ctl add listen fd failed"); 25 | } 26 | 27 | /* Buffer where events are returned */ 28 | events = calloc(MAXEVENTS, sizeof(event)); 29 | 30 | while (1) { 31 | n = epoll_wait(efd, events, MAXEVENTS, -1); 32 | printf("epoll_wait wakeup\n"); 33 | for (i = 0; i < n; i++) { 34 | if ((events[i].events & EPOLLERR) || 35 | (events[i].events & EPOLLHUP) || 36 | (!(events[i].events & EPOLLIN))) { 37 | fprintf(stderr, "epoll error\n"); 38 | close(events[i].data.fd); 39 | continue; 40 | } else if (listen_fd == events[i].data.fd) { 41 | struct sockaddr_storage ss; 42 | socklen_t slen = sizeof(ss); 43 | int fd = accept(listen_fd, (struct sockaddr *) &ss, &slen); 44 | if (fd < 0) { 45 | error(1, errno, "accept failed"); 46 | } else { 47 | make_nonblocking(fd); 48 | event.data.fd = fd; 49 | event.events = EPOLLIN; //level-triggered 50 | if (epoll_ctl(efd, EPOLL_CTL_ADD, fd, &event) == -1) { 51 | error(1, errno, "epoll_ctl add connection fd failed"); 52 | } 53 | } 54 | continue; 55 | } else { 56 | socket_fd = events[i].data.fd; 57 | printf("get event on socket fd == %d \n", socket_fd); 58 | } 59 | } 60 | } 61 | 62 | free(events); 63 | close(listen_fd); 64 | 65 | } 66 | -------------------------------------------------------------------------------- /chap-25/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(fork01 fork01.c) 2 | target_link_libraries(fork01 yolanda) 3 | -------------------------------------------------------------------------------- /chap-25/fork01.c: -------------------------------------------------------------------------------- 1 | #include "lib/common.h" 2 | 3 | #define MAX_LINE 4096 4 | 5 | char 6 | rot13_char(char c) { 7 | if ((c >= 'a' && c <= 'm') || (c >= 'A' && c <= 'M')) 8 | return c + 13; 9 | else if ((c >= 'n' && c <= 'z') || (c >= 'N' && c <= 'Z')) 10 | return c - 13; 11 | else 12 | return c; 13 | } 14 | 15 | void child_run(int fd) { 16 | char outbuf[MAX_LINE + 1]; 17 | size_t outbuf_used = 0; 18 | ssize_t result; 19 | 20 | while (1) { 21 | char ch; 22 | result = recv(fd, &ch, 1, 0); 23 | if (result == 0) { 24 | break; 25 | } else if (result == -1) { 26 | perror("read"); 27 | break; 28 | } 29 | 30 | /* We do this test to keep the user from overflowing the buffer. */ 31 | if (outbuf_used < sizeof(outbuf)) { 32 | outbuf[outbuf_used++] = rot13_char(ch); 33 | } 34 | 35 | if (ch == '\n') { 36 | send(fd, outbuf, outbuf_used, 0); 37 | outbuf_used = 0; 38 | continue; 39 | } 40 | } 41 | } 42 | 43 | 44 | void sigchld_handler(int sig) { 45 | while (waitpid(-1, 0, WNOHANG) > 0); 46 | return; 47 | } 48 | 49 | int main(int c, char **v) { 50 | int listener_fd = tcp_server_listen(SERV_PORT); 51 | signal(SIGCHLD, sigchld_handler); 52 | while (1) { 53 | struct sockaddr_storage ss; 54 | socklen_t slen = sizeof(ss); 55 | int fd = accept(listener_fd, (struct sockaddr *) &ss, &slen); 56 | if (fd < 0) { 57 | error(1, errno, "accept failed"); 58 | exit(1); 59 | } 60 | 61 | if (fork() == 0) { 62 | close(listener_fd); 63 | child_run(fd); 64 | exit(0); 65 | } else { 66 | close(fd); 67 | } 68 | } 69 | 70 | return 0; 71 | } -------------------------------------------------------------------------------- /chap-26/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(thread-helloworld thread-helloworld.c ) 2 | target_link_libraries(thread-helloworld yolanda) 3 | 4 | 5 | add_executable(thread01 thread01.c echo.c) 6 | target_link_libraries(thread01 yolanda) 7 | 8 | 9 | add_executable(thread02 thread02.c echo.c) 10 | target_link_libraries(thread02 yolanda) 11 | -------------------------------------------------------------------------------- /chap-26/echo.c: -------------------------------------------------------------------------------- 1 | #include "lib/common.h" 2 | 3 | #define MAX_LINE 16384 4 | 5 | char rot13_char(char c) { 6 | if ((c >= 'a' && c <= 'm') || (c >= 'A' && c <= 'M')) 7 | return c + 13; 8 | else if ((c >= 'n' && c <= 'z') || (c >= 'N' && c <= 'Z')) 9 | return c - 13; 10 | else 11 | return c; 12 | } 13 | 14 | void loop_echo(int fd) { 15 | char outbuf[MAX_LINE + 1]; 16 | size_t outbuf_used = 0; 17 | ssize_t result; 18 | while (1) { 19 | char ch; 20 | result = recv(fd, &ch, 1, 0); 21 | 22 | //断开连接或者出错 23 | if (result == 0) { 24 | break; 25 | } else if (result == -1) { 26 | error(1, errno, "read error"); 27 | break; 28 | } 29 | 30 | if (outbuf_used < sizeof(outbuf)) { 31 | outbuf[outbuf_used++] = rot13_char(ch); 32 | } 33 | 34 | if (ch == '\n') { 35 | send(fd, outbuf, outbuf_used, 0); 36 | outbuf_used = 0; 37 | continue; 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /chap-26/thread-helloworld.c: -------------------------------------------------------------------------------- 1 | #include "lib/common.h" 2 | 3 | int another_shared = 0; 4 | 5 | void * thread_run(void *arg) { 6 | int *calculator = (int *) arg; 7 | printf("hello, world, tid == %d \n", pthread_self()); 8 | for (int i = 0; i < 1000; i++) { 9 | *calculator += 1; 10 | another_shared += 1; 11 | } 12 | } 13 | 14 | int main(int c, char **v) { 15 | int calculator; 16 | 17 | pthread_t tid1; 18 | pthread_t tid2; 19 | 20 | pthread_create(&tid1, NULL, thread_run, &calculator); 21 | pthread_create(&tid2, NULL, thread_run, &calculator); 22 | 23 | pthread_join(tid1, NULL); 24 | pthread_join(tid2, NULL); 25 | 26 | printf("calculator is %d \n", calculator); 27 | printf("another_shared is %d \n", another_shared); 28 | } -------------------------------------------------------------------------------- /chap-26/thread01.c: -------------------------------------------------------------------------------- 1 | #include "lib/common.h" 2 | 3 | extern void loop_echo(int); 4 | 5 | void thread_run(void *arg) { 6 | pthread_detach(pthread_self()); 7 | int fd = (int) arg; 8 | loop_echo(fd); 9 | } 10 | 11 | int main(int c, char **v) { 12 | int listener_fd = tcp_server_listen(SERV_PORT); 13 | pthread_t tid; 14 | 15 | while (1) { 16 | struct sockaddr_storage ss; 17 | socklen_t slen = sizeof(ss); 18 | int fd = accept(listener_fd, (struct sockaddr *) &ss, &slen); 19 | if (fd < 0) { 20 | error(1, errno, "accept failed"); 21 | } else { 22 | pthread_create(&tid, NULL, &thread_run, (void *) fd); 23 | } 24 | } 25 | 26 | return 0; 27 | } -------------------------------------------------------------------------------- /chap-26/thread02.c: -------------------------------------------------------------------------------- 1 | #include "lib/common.h" 2 | 3 | #define THREAD_NUMBER 4 4 | #define BLOCK_QUEUE_SIZE 100 5 | 6 | extern void loop_echo(int); 7 | 8 | typedef struct { 9 | pthread_t thread_tid; /* thread ID */ 10 | long thread_count; /* # connections handled */ 11 | } Thread; 12 | 13 | Thread *thread_array; 14 | 15 | typedef struct { 16 | int number; 17 | int *fd; 18 | int front; 19 | int rear; 20 | pthread_mutex_t mutex; 21 | pthread_cond_t cond; 22 | } block_queue; 23 | 24 | 25 | void block_queue_init(block_queue *blockQueue, int number) { 26 | blockQueue->number = number; 27 | blockQueue->fd = calloc(number, sizeof(int)); 28 | blockQueue->front = blockQueue->rear = 0; 29 | pthread_mutex_init(&blockQueue->mutex, NULL); 30 | pthread_cond_init(&blockQueue->cond, NULL); 31 | } 32 | 33 | void block_queue_push(block_queue *blockQueue, int fd) { 34 | pthread_mutex_lock(&blockQueue->mutex); 35 | blockQueue->fd[blockQueue->rear] = fd; 36 | if (++blockQueue->rear == blockQueue->number) { 37 | blockQueue->rear = 0; 38 | } 39 | printf("push fd %d", fd); 40 | pthread_cond_signal(&blockQueue->cond); 41 | pthread_mutex_unlock(&blockQueue->mutex); 42 | } 43 | 44 | 45 | int block_queue_pop(block_queue *blockQueue) { 46 | pthread_mutex_lock(&blockQueue->mutex); 47 | while (blockQueue->front == blockQueue->rear) 48 | pthread_cond_wait(&blockQueue->cond, &blockQueue->mutex); 49 | int fd = blockQueue->fd[blockQueue->front]; 50 | if (++blockQueue->front == blockQueue->number) { 51 | blockQueue->front = 0; 52 | } 53 | printf("pop fd %d", fd); 54 | pthread_mutex_unlock(&blockQueue->mutex); 55 | return fd; 56 | } 57 | 58 | void thread_run(void *arg) { 59 | pthread_t tid = pthread_self(); 60 | pthread_detach(tid); 61 | 62 | block_queue *blockQueue = (block_queue *) arg; 63 | while (1) { 64 | int fd = block_queue_pop(blockQueue); 65 | printf("get fd in thread, fd==%d, tid == %d", fd, tid); 66 | loop_echo(fd); 67 | } 68 | } 69 | 70 | int main(int c, char **v) { 71 | int listener_fd = tcp_server_listen(SERV_PORT); 72 | 73 | block_queue blockQueue; 74 | block_queue_init(&blockQueue, BLOCK_QUEUE_SIZE); 75 | 76 | thread_array = calloc(THREAD_NUMBER, sizeof(Thread)); 77 | int i; 78 | for (i = 0; i < THREAD_NUMBER; i++) { 79 | pthread_create(&(thread_array[i].thread_tid), NULL, &thread_run, (void *) &blockQueue); 80 | } 81 | 82 | while (1) { 83 | struct sockaddr_storage ss; 84 | socklen_t slen = sizeof(ss); 85 | int fd = accept(listener_fd, (struct sockaddr *) &ss, &slen); 86 | if (fd < 0) { 87 | error(1, errno, "accept failed"); 88 | } else { 89 | block_queue_push(&blockQueue, fd); 90 | } 91 | } 92 | 93 | return 0; 94 | } -------------------------------------------------------------------------------- /chap-27/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(poll-server-onethread poll-server-onethread.c) 2 | target_link_libraries(poll-server-onethread yolanda) 3 | -------------------------------------------------------------------------------- /chap-27/poll-server-onethread.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "lib/common.h" 3 | #include "lib/event_loop.h" 4 | #include "lib/tcp_server.h" 5 | 6 | char rot13_char(char c) { 7 | if ((c >= 'a' && c <= 'm') || (c >= 'A' && c <= 'M')) 8 | return c + 13; 9 | else if ((c >= 'n' && c <= 'z') || (c >= 'N' && c <= 'Z')) 10 | return c - 13; 11 | else 12 | return c; 13 | } 14 | 15 | //连接建立之后的callback 16 | int onConnectionCompleted(struct tcp_connection *tcpConnection) { 17 | printf("connection completed\n"); 18 | return 0; 19 | } 20 | 21 | //数据读到buffer之后的callback 22 | int onMessage(struct buffer *input, struct tcp_connection *tcpConnection) { 23 | printf("get message from tcp connection %s\n", tcpConnection->name); 24 | printf("%s", input->data); 25 | 26 | struct buffer *output = buffer_new(); 27 | int size = buffer_readable_size(input); 28 | for (int i = 0; i < size; i++) { 29 | buffer_append_char(output, rot13_char(buffer_read_char(input))); 30 | } 31 | tcp_connection_send_buffer(tcpConnection, output); 32 | return 0; 33 | } 34 | 35 | //数据通过buffer写完之后的callback 36 | int onWriteCompleted(struct tcp_connection *tcpConnection) { 37 | printf("write completed\n"); 38 | return 0; 39 | } 40 | 41 | //连接关闭之后的callback 42 | int onConnectionClosed(struct tcp_connection *tcpConnection) { 43 | printf("connection closed\n"); 44 | return 0; 45 | } 46 | 47 | int main(int c, char **v) { 48 | //主线程event_loop 49 | struct event_loop *eventLoop = event_loop_init(); 50 | 51 | //初始化acceptor 52 | struct acceptor *acceptor = acceptor_init(SERV_PORT); 53 | 54 | //初始tcp_server,可以指定线程数目,如果线程是0,就只有一个线程,既负责acceptor,也负责I/O 55 | struct TCPserver *tcpServer = tcp_server_init(eventLoop, acceptor, onConnectionCompleted, onMessage, 56 | onWriteCompleted, onConnectionClosed, 0); 57 | tcp_server_start(tcpServer); 58 | 59 | // main thread for acceptor 60 | event_loop_run(eventLoop); 61 | } -------------------------------------------------------------------------------- /chap-28/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(poll-server-multithreads poll-server-multithreads.c) 2 | target_link_libraries(poll-server-multithreads yolanda) 3 | 4 | add_executable(test01 test01.c) 5 | target_link_libraries(test01 yolanda) -------------------------------------------------------------------------------- /chap-28/poll-server-multithreads.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "lib/common.h" 3 | #include "lib/event_loop.h" 4 | #include "lib/tcp_server.h" 5 | 6 | char rot13_char(char c) { 7 | if ((c >= 'a' && c <= 'm') || (c >= 'A' && c <= 'M')) 8 | return c + 13; 9 | else if ((c >= 'n' && c <= 'z') || (c >= 'N' && c <= 'Z')) 10 | return c - 13; 11 | else 12 | return c; 13 | } 14 | 15 | //连接建立之后的callback 16 | int onConnectionCompleted(struct tcp_connection *tcpConnection) { 17 | printf("connection completed\n"); 18 | return 0; 19 | } 20 | 21 | //数据读到buffer之后的callback 22 | int onMessage(struct buffer *input, struct tcp_connection *tcpConnection) { 23 | printf("get message from tcp connection %s\n", tcpConnection->name); 24 | printf("%s", input->data); 25 | 26 | struct buffer *output = buffer_new(); 27 | int size = buffer_readable_size(input); 28 | for (int i = 0; i < size; i++) { 29 | buffer_append_char(output, rot13_char(buffer_read_char(input))); 30 | } 31 | tcp_connection_send_buffer(tcpConnection, output); 32 | return 0; 33 | } 34 | 35 | //数据通过buffer写完之后的callback 36 | int onWriteCompleted(struct tcp_connection *tcpConnection) { 37 | printf("write completed\n"); 38 | return 0; 39 | } 40 | 41 | //连接关闭之后的callback 42 | int onConnectionClosed(struct tcp_connection *tcpConnection) { 43 | printf("connection closed\n"); 44 | return 0; 45 | } 46 | 47 | int main(int c, char **v) { 48 | //主线程event_loop 49 | struct event_loop *eventLoop = event_loop_init(); 50 | 51 | //初始化acceptor 52 | struct acceptor *acceptor = acceptor_init(SERV_PORT); 53 | 54 | //初始tcp_server,可以指定线程数目,这里线程是4,说明是一个acceptor线程,4个I/O线程,没一个I/O线程 55 | //tcp_server自己带一个event_loop 56 | struct TCPserver *tcpServer = tcp_server_init(eventLoop, acceptor, onConnectionCompleted, onMessage, 57 | onWriteCompleted, onConnectionClosed, 4); 58 | tcp_server_start(tcpServer); 59 | 60 | // main thread for acceptor 61 | event_loop_run(eventLoop); 62 | } -------------------------------------------------------------------------------- /chap-28/test01.c: -------------------------------------------------------------------------------- 1 | #include "lib/common.h" 2 | 3 | int socket_init() 4 | { 5 | struct protoent* protocol = NULL; 6 | protocol=getprotobyname("icmp"); 7 | int sock=socket(AF_INET,SOCK_RAW,protocol->p_proto); 8 | if(sock == -1){ 9 | error(1,errno,"create socket failed"); 10 | } 11 | return sock; 12 | } 13 | 14 | int main(int c, char **v) { 15 | printf("fd == %ld\n", htonl((uint32_t)2000)); 16 | printf("socket %d \n", socket_init()); 17 | printf("socket %d \n", socket_init()); 18 | } -------------------------------------------------------------------------------- /chap-29/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(epoll-server-multithreads epoll-server-multithreads.c) 2 | target_link_libraries(epoll-server-multithreads yolanda) 3 | -------------------------------------------------------------------------------- /chap-29/epoll-server-multithreads.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "lib/common.h" 3 | #include "lib/event_loop.h" 4 | #include "lib/tcp_server.h" 5 | 6 | char rot13_char(char c) { 7 | if ((c >= 'a' && c <= 'm') || (c >= 'A' && c <= 'M')) 8 | return c + 13; 9 | else if ((c >= 'n' && c <= 'z') || (c >= 'N' && c <= 'Z')) 10 | return c - 13; 11 | else 12 | return c; 13 | } 14 | 15 | //连接建立之后的callback 16 | int onConnectionCompleted(struct tcp_connection *tcpConnection) { 17 | printf("connection completed\n"); 18 | return 0; 19 | } 20 | 21 | //数据读到buffer之后的callback 22 | int onMessage(struct buffer *input, struct tcp_connection *tcpConnection) { 23 | printf("get message from tcp connection %s\n", tcpConnection->name); 24 | printf("%s", input->data); 25 | 26 | struct buffer *output = buffer_new(); 27 | int size = buffer_readable_size(input); 28 | for (int i = 0; i < size; i++) { 29 | buffer_append_char(output, rot13_char(buffer_read_char(input))); 30 | } 31 | tcp_connection_send_buffer(tcpConnection, output); 32 | return 0; 33 | } 34 | 35 | //数据通过buffer写完之后的callback 36 | int onWriteCompleted(struct tcp_connection *tcpConnection) { 37 | printf("write completed\n"); 38 | return 0; 39 | } 40 | 41 | //连接关闭之后的callback 42 | int onConnectionClosed(struct tcp_connection *tcpConnection) { 43 | printf("connection closed\n"); 44 | return 0; 45 | } 46 | 47 | int main(int c, char **v) { 48 | //主线程event_loop 49 | struct event_loop *eventLoop = event_loop_init(); 50 | 51 | //初始化acceptor 52 | struct acceptor *acceptor = acceptor_init(SERV_PORT); 53 | 54 | //初始tcp_server,可以指定线程数目,这里线程是4,说明是一个acceptor线程,4个I/O线程,没一个I/O线程 55 | //tcp_server自己带一个event_loop 56 | struct TCPserver *tcpServer = tcp_server_init(eventLoop, acceptor, onConnectionCompleted, onMessage, 57 | onWriteCompleted, onConnectionClosed, 4); 58 | tcp_server_start(tcpServer); 59 | 60 | // main thread for acceptor 61 | event_loop_run(eventLoop); 62 | } -------------------------------------------------------------------------------- /chap-30/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(aio01 aio01.c) 2 | target_link_libraries(aio01 yolanda) 3 | -------------------------------------------------------------------------------- /chap-30/aio01.c: -------------------------------------------------------------------------------- 1 | #include "lib/common.h" 2 | #include 3 | 4 | const int BUF_SIZE = 512; 5 | 6 | int main() { 7 | int err; 8 | int result_size; 9 | 10 | // 创建一个临时文件 11 | char tmpname[256]; 12 | snprintf(tmpname, sizeof(tmpname), "/tmp/aio_test_%d", getpid()); 13 | unlink(tmpname); 14 | int fd = open(tmpname, O_CREAT | O_RDWR | O_EXCL, S_IRUSR | S_IWUSR); 15 | if (fd == -1) { 16 | error(1, errno, "open file failed "); 17 | } 18 | unlink(tmpname); 19 | 20 | 21 | char buf[BUF_SIZE]; 22 | struct aiocb aiocb; 23 | 24 | //初始化buf缓冲,写入的数据应该为0xfafa这样的, 25 | memset(buf, 0xfa, BUF_SIZE); 26 | memset(&aiocb, 0, sizeof(struct aiocb)); 27 | aiocb.aio_fildes = fd; 28 | aiocb.aio_buf = buf; 29 | aiocb.aio_nbytes = BUF_SIZE; 30 | 31 | //开始写 32 | if (aio_write(&aiocb) == -1) { 33 | printf(" Error at aio_write(): %s\n", strerror(errno)); 34 | close(fd); 35 | exit(1); 36 | } 37 | 38 | //因为是异步的,需要判断什么时候写完 39 | while (aio_error(&aiocb) == EINPROGRESS) { 40 | printf("writing... \n"); 41 | } 42 | 43 | //判断写入的是否正确 44 | err = aio_error(&aiocb); 45 | result_size = aio_return(&aiocb); 46 | if (err != 0 || result_size != BUF_SIZE) { 47 | printf(" aio_write failed() : %s\n", strerror(err)); 48 | close(fd); 49 | exit(1); 50 | } 51 | 52 | //下面准备开始读数据 53 | char buffer[BUF_SIZE]; 54 | struct aiocb cb; 55 | cb.aio_nbytes = BUF_SIZE; 56 | cb.aio_fildes = fd; 57 | cb.aio_offset = 0; 58 | cb.aio_buf = buffer; 59 | 60 | // 开始读数据 61 | if (aio_read(&cb) == -1) { 62 | printf(" air_read failed() : %s\n", strerror(err)); 63 | close(fd); 64 | } 65 | 66 | //因为是异步的,需要判断什么时候读完 67 | while (aio_error(&cb) == EINPROGRESS) { 68 | printf("Reading... \n"); 69 | } 70 | 71 | // 判断读是否成功 72 | int numBytes = aio_return(&cb); 73 | if (numBytes != -1) { 74 | printf("Success.\n"); 75 | } else { 76 | printf("Error.\n"); 77 | } 78 | 79 | // 清理文件句柄 80 | close(fd); 81 | return 0; 82 | } -------------------------------------------------------------------------------- /chap-30/test.txt: -------------------------------------------------------------------------------- 1 | afsdfasddsfsdfasafadsfasdfasdff 2 | afsdfasddsfsdfasafadsfasdfasdff 3 | afsdfasddsfsdfasafadsfasdfasdffvafsdfasddsfsdfasafadsfasdfasdff 4 | afsdfasddsfsdfasafadsfasdfasdffafsdfasddsfsdfasafadsfasdfasdff 5 | afsdfasddsfsdfasafadsfasdfasdffafsdfasddsfsdfasafadsfasdfasdffafsdfasddsfsdfasafadsfasdfasdffafsdfasddsfsdfasafadsfasdfasdff 6 | afsdfasddsfsdfasafadsfasdfasdffafsdfasddsfsdfasafadsfasdfasdffafsdfasddsfsdfasafadsfasdfasdffafsdfasddsfsdfasafadsfasdfasdff 7 | 8 | vafsdfasddsfsdfasafadsfasdfasdff 9 | afsdfasddsfsdfasafadsfasdfasdff -------------------------------------------------------------------------------- /chap-34/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(http_server01 http_server01.c) 2 | target_link_libraries(http_server01 yolanda) 3 | 4 | add_executable(http_server_test http_server_test.c) 5 | target_link_libraries(http_server_test yolanda) 6 | -------------------------------------------------------------------------------- /chap-34/http_server01.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "lib/common.h" 4 | #include "lib/event_loop.h" 5 | 6 | //数据读到buffer之后的callback 7 | int onRequest(struct http_request *httpRequest, struct http_response *httpResponse) { 8 | char *url = httpRequest->url; 9 | char *question = memmem(url, strlen(url), "?", 1); 10 | char *path = NULL; 11 | if (question != NULL) { 12 | path = malloc(question - url); 13 | strncpy(path, url, question - url); 14 | } else { 15 | path = malloc(strlen(url)); 16 | strncpy(path, url, strlen(url)); 17 | } 18 | 19 | if (strcmp(path, "/") == 0) { 20 | httpResponse->statusCode = OK; 21 | httpResponse->statusMessage = "OK"; 22 | httpResponse->contentType = "text/html"; 23 | httpResponse->body = "This is network programming

Hello, network programming

"; 24 | } else if (strcmp(path, "/network") == 0) { 25 | httpResponse->statusCode = OK; 26 | httpResponse->statusMessage = "OK"; 27 | httpResponse->contentType = "text/plain"; 28 | httpResponse->body = "hello, network programming"; 29 | } else { 30 | httpResponse->statusCode = NotFound; 31 | httpResponse->statusMessage = "Not Found"; 32 | httpResponse->keep_connected = 1; 33 | } 34 | 35 | return 0; 36 | } 37 | 38 | 39 | int main(int c, char **v) { 40 | //主线程event_loop 41 | struct event_loop *eventLoop = event_loop_init(); 42 | 43 | //初始tcp_server,可以指定线程数目,如果线程是0,就是在这个线程里acceptor+i/o;如果是1,有一个I/O线程 44 | //tcp_server自己带一个event_loop 45 | struct http_server *httpServer = http_server_new(eventLoop, SERV_PORT, onRequest, 2); 46 | http_server_start(httpServer); 47 | 48 | // main thread for acceptor 49 | event_loop_run(eventLoop); 50 | } -------------------------------------------------------------------------------- /chap-34/http_server_test.c: -------------------------------------------------------------------------------- 1 | #include "lib/http_request.h" 2 | #include "lib/http_server.h" 3 | #include "lib/http_response.h" 4 | 5 | char *data = "GET / HTTP/1.1\r\nHost: localhost:43211\r\nUser-Agent: curl/7.54.0\r\nAccept: */*\r\n\r\n"; 6 | 7 | 8 | //数据读到buffer之后的callback 9 | int onRequest(struct http_request *httpRequest, struct http_response *httpResponse) { 10 | char *url = httpRequest->url; 11 | char *question = memmem(url, strlen(url), "?", 1); 12 | char *path = NULL; 13 | if (question != NULL) { 14 | path = malloc(question - url); 15 | strncpy(path, url, question - url); 16 | } else { 17 | path = malloc(strlen(url)); 18 | strncpy(path, url, strlen(url)); 19 | } 20 | 21 | if (strcmp(path, "/") == 0) { 22 | httpResponse->statusCode = OK; 23 | httpResponse->statusMessage = "OK"; 24 | httpResponse->contentType = "text/html"; 25 | httpResponse->body = "This is network programming

Hello, network programing

"; 26 | } else if (strcmp(path, "network") == 0) { 27 | httpResponse->statusCode = OK; 28 | httpResponse->statusMessage = "OK"; 29 | httpResponse->contentType = "text/plain"; 30 | httpResponse->body = "hello, network programming"; 31 | } else { 32 | httpResponse->statusCode = NotFound; 33 | httpResponse->statusMessage = "Not Found"; 34 | httpResponse->keep_connected = 1; 35 | } 36 | 37 | return 0; 38 | } 39 | 40 | 41 | int main() { 42 | struct buffer *input = buffer_new(); 43 | buffer_append_string(input, data); 44 | 45 | struct http_request *httpRequest = http_request_new(); 46 | parse_http_request(input, httpRequest); 47 | 48 | for (int i = 0; i < httpRequest->request_headers_number; i++) { 49 | char *key = httpRequest->request_headers[i].key; 50 | char *value = httpRequest->request_headers[i].value; 51 | printf("key == %s, value == %s\n", key, value); 52 | } 53 | 54 | struct http_response *httpResponse = http_response_new(); 55 | onRequest(httpRequest, httpResponse); 56 | 57 | struct buffer *output = buffer_new(); 58 | http_response_encode_buffer(httpResponse, output); 59 | } -------------------------------------------------------------------------------- /chap-4/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(make_socket make_socket.c) 2 | target_link_libraries(make_socket yolanda) 3 | 4 | -------------------------------------------------------------------------------- /chap-4/make_socket.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int make_socket(uint16_t port) { 7 | int sock; 8 | struct sockaddr_in name; 9 | 10 | /* 创建字节流类型的IPV4 socket. */ 11 | sock = socket(PF_INET, SOCK_STREAM, 0); 12 | if (sock < 0) { 13 | perror("socket"); 14 | exit(EXIT_FAILURE); 15 | } 16 | 17 | /* 绑定到port和ip. */ 18 | name.sin_family = AF_INET; /* IPV4 */ 19 | name.sin_port = htons (port); /* 指定端口 */ 20 | name.sin_addr.s_addr = htonl (INADDR_ANY); /* 通配地址 */ 21 | /* 把IPV4地址转换成通用地址格式,同时传递长度 */ 22 | if (bind(sock, (struct sockaddr *) &name, sizeof(name)) < 0) { 23 | perror("bind"); 24 | exit(EXIT_FAILURE); 25 | } 26 | 27 | return sock; 28 | } 29 | 30 | int main(int argc, char **argv) { 31 | int sockfd = make_socket(12345); 32 | exit(0); 33 | } -------------------------------------------------------------------------------- /chap-5/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(tcpclient tcpclient.c) 2 | target_link_libraries(tcpclient yolanda) 3 | 4 | add_executable(tcpserver tcp_server.c) 5 | target_link_libraries(tcpserver yolanda) 6 | 7 | -------------------------------------------------------------------------------- /chap-5/tcp_server.c: -------------------------------------------------------------------------------- 1 | #include "lib/common.h" 2 | 3 | void read_data(int sockfd) { 4 | ssize_t n; 5 | char buf[1024]; 6 | 7 | int time = 0; 8 | for (;;) { 9 | fprintf(stdout, "block in read\n"); 10 | if ((n = readn(sockfd, buf, 1024)) == 0) 11 | return; 12 | 13 | time++; 14 | fprintf(stdout, "1K read for %d \n", time); 15 | usleep(1000); 16 | } 17 | } 18 | 19 | 20 | int main(int argc, char **argv) { 21 | int listenfd, connfd; 22 | socklen_t clilen; 23 | struct sockaddr_in cliaddr, servaddr; 24 | 25 | listenfd = socket(AF_INET, SOCK_STREAM, 0); 26 | 27 | bzero(&servaddr, sizeof(servaddr)); 28 | servaddr.sin_family = AF_INET; 29 | servaddr.sin_addr.s_addr = htonl(INADDR_ANY); 30 | servaddr.sin_port = htons(12345); 31 | 32 | /* bind到本地地址,端口为12345 */ 33 | bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr)); 34 | /* listen的backlog为1024 */ 35 | listen(listenfd, 1024); 36 | 37 | /* 循环处理用户请求 */ 38 | for (;;) { 39 | clilen = sizeof(cliaddr); 40 | connfd = accept(listenfd, (struct sockaddr *) &cliaddr, &clilen); 41 | read_data(connfd); /* 读取数据 */ 42 | close(connfd); /* 关闭连接套接字,注意不是监听套接字*/ 43 | } 44 | } 45 | 46 | -------------------------------------------------------------------------------- /chap-5/tcpclient.c: -------------------------------------------------------------------------------- 1 | #include "lib/common.h" 2 | 3 | # define MESSAGE_SIZE 102400 4 | 5 | void send_data(int sockfd) { 6 | char *query; 7 | query = malloc(MESSAGE_SIZE + 1); 8 | for (int i = 0; i < MESSAGE_SIZE; i++) { 9 | query[i] = 'a'; 10 | } 11 | query[MESSAGE_SIZE] = '\0'; 12 | 13 | const char *cp; 14 | cp = query; 15 | size_t remaining = strlen(query); 16 | while (remaining) { 17 | int n_written = send(sockfd, cp, remaining, 0); 18 | fprintf(stdout, "send into buffer %ld \n", n_written); 19 | if (n_written <= 0) { 20 | error(1, errno, "send failed"); 21 | return; 22 | } 23 | remaining -= n_written; 24 | cp += n_written; 25 | } 26 | 27 | return; 28 | } 29 | 30 | int main(int argc, char **argv) { 31 | int sockfd; 32 | struct sockaddr_in servaddr; 33 | 34 | if (argc != 2) 35 | error(1, 0, "usage: tcpclient "); 36 | 37 | sockfd = socket(AF_INET, SOCK_STREAM, 0); 38 | 39 | bzero(&servaddr, sizeof(servaddr)); 40 | servaddr.sin_family = AF_INET; 41 | servaddr.sin_port = htons(12345); 42 | inet_pton(AF_INET, argv[1], &servaddr.sin_addr); 43 | int connect_rt = connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)); 44 | if (connect_rt < 0) { 45 | error(1, errno, "connect failed "); 46 | } 47 | send_data(sockfd); 48 | exit(0); 49 | } 50 | 51 | -------------------------------------------------------------------------------- /chap-6/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(udpclient udpclient.c) 2 | target_link_libraries(udpclient yolanda) 3 | 4 | add_executable(udpserver udpserver.c) 5 | target_link_libraries(udpserver yolanda) 6 | 7 | -------------------------------------------------------------------------------- /chap-6/udpclient.c: -------------------------------------------------------------------------------- 1 | //#include 2 | #include "lib/common.h" 3 | 4 | 5 | # define NDG 2000 /* datagrams to send */ 6 | # define DGLEN 1400 /* length of each datagram */ 7 | # define MAXLINE 4096 8 | 9 | 10 | int main(int argc, char **argv) { 11 | if (argc != 2) { 12 | error(1, 0, "usage: udpclient "); 13 | 14 | } 15 | int socket_fd; 16 | socket_fd = socket(AF_INET, SOCK_DGRAM, 0); 17 | 18 | struct sockaddr_in server_addr; 19 | bzero(&server_addr, sizeof(server_addr)); 20 | server_addr.sin_family = AF_INET; 21 | server_addr.sin_port = htons(SERV_PORT); 22 | inet_pton(AF_INET, argv[1], &server_addr.sin_addr); 23 | 24 | socklen_t server_len = sizeof(server_addr); 25 | 26 | struct sockaddr *reply_addr; 27 | reply_addr = malloc(server_len); 28 | 29 | char send_line[MAXLINE], recv_line[MAXLINE + 1]; 30 | socklen_t len; 31 | int n; 32 | 33 | while (fgets(send_line, MAXLINE, stdin) != NULL) { 34 | int i = strlen(send_line); 35 | if (send_line[i - 1] == '\n') { 36 | send_line[i - 1] = 0; 37 | } 38 | 39 | printf("now sending %s\n", send_line); 40 | size_t rt = sendto(socket_fd, send_line, strlen(send_line), 0, (struct sockaddr *) &server_addr, server_len); 41 | if (rt < 0) { 42 | error(1, errno, "send failed "); 43 | } 44 | printf("send bytes: %zu \n", rt); 45 | 46 | len = 0; 47 | n = recvfrom(socket_fd, recv_line, MAXLINE, 0, reply_addr, &len); 48 | if (n < 0) 49 | error(1, errno, "recvfrom failed"); 50 | recv_line[n] = 0; 51 | fputs(recv_line, stdout); 52 | fputs("\n", stdout); 53 | } 54 | 55 | exit(0); 56 | } 57 | 58 | 59 | -------------------------------------------------------------------------------- /chap-6/udpserver.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by shengym on 2019-07-07. 3 | // 4 | 5 | #include "lib/common.h" 6 | 7 | static int count; 8 | 9 | static void recvfrom_int(int signo) { 10 | printf("\nreceived %d datagrams\n", count); 11 | exit(0); 12 | } 13 | 14 | 15 | int main(int argc, char **argv) { 16 | int socket_fd; 17 | socket_fd = socket(AF_INET, SOCK_DGRAM, 0); 18 | 19 | struct sockaddr_in server_addr; 20 | bzero(&server_addr, sizeof(server_addr)); 21 | server_addr.sin_family = AF_INET; 22 | server_addr.sin_addr.s_addr = htonl(INADDR_ANY); 23 | server_addr.sin_port = htons(SERV_PORT); 24 | 25 | bind(socket_fd, (struct sockaddr *) &server_addr, sizeof(server_addr)); 26 | 27 | socklen_t client_len; 28 | char message[MAXLINE]; 29 | count = 0; 30 | 31 | signal(SIGINT, recvfrom_int); 32 | 33 | struct sockaddr_in client_addr; 34 | client_len = sizeof(client_addr); 35 | for (;;) { 36 | int n = recvfrom(socket_fd, message, MAXLINE, 0, (struct sockaddr *) &client_addr, &client_len); 37 | message[n] = 0; 38 | printf("received %d bytes: %s\n", n, message); 39 | 40 | char send_line[MAXLINE]; 41 | sprintf(send_line, "Hi, %s", message); 42 | 43 | sendto(socket_fd, send_line, strlen(send_line), 0, (struct sockaddr *) &client_addr, client_len); 44 | 45 | count++; 46 | } 47 | 48 | } 49 | 50 | 51 | -------------------------------------------------------------------------------- /chap-7/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(unixstreamserver unixstreamserver.c) 2 | target_link_libraries(unixstreamserver yolanda) 3 | 4 | add_executable(unixstreamclient unixstreamclient.c) 5 | target_link_libraries(unixstreamclient yolanda) 6 | 7 | add_executable(unixdataserver unixdataserver.c) 8 | target_link_libraries(unixdataserver yolanda) 9 | 10 | add_executable(unixdataclient unixdataclient.c) 11 | target_link_libraries(unixdataclient yolanda) 12 | -------------------------------------------------------------------------------- /chap-7/unixdataclient.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by shengym on 2019-07-15. 3 | // 4 | 5 | #include "lib/common.h" 6 | 7 | int main(int argc, char **argv) { 8 | if (argc != 2) { 9 | error(1, 0, "usage: unixdataclient "); 10 | } 11 | 12 | int sockfd; 13 | struct sockaddr_un client_addr, server_addr; 14 | 15 | sockfd = socket(AF_LOCAL, SOCK_DGRAM, 0); 16 | if (sockfd < 0) { 17 | error(1, errno, "create socket failed"); 18 | } 19 | 20 | bzero(&client_addr, sizeof(client_addr)); /* bind an address for us */ 21 | client_addr.sun_family = AF_LOCAL; 22 | strcpy(client_addr.sun_path, tmpnam(NULL)); 23 | 24 | if (bind(sockfd, (struct sockaddr *) &client_addr, sizeof(client_addr)) < 0) { 25 | error(1, errno, "bind failed"); 26 | } 27 | 28 | bzero(&server_addr, sizeof(server_addr)); 29 | server_addr.sun_family = AF_LOCAL; 30 | strcpy(server_addr.sun_path, argv[1]); 31 | 32 | char send_line[MAXLINE]; 33 | bzero(send_line, MAXLINE); 34 | char recv_line[MAXLINE]; 35 | 36 | while (fgets(send_line, MAXLINE, stdin) != NULL) { 37 | int i = strlen(send_line); 38 | if (send_line[i - 1] == '\n') { 39 | send_line[i - 1] = 0; 40 | } 41 | size_t nbytes = strlen(send_line); 42 | printf("now sending %s \n", send_line); 43 | 44 | if (sendto(sockfd, send_line, nbytes, 0, (struct sockaddr *) &server_addr, sizeof(server_addr)) != nbytes) 45 | error(1, errno, "sendto error"); 46 | 47 | int n = recvfrom(sockfd, recv_line, MAXLINE, 0, NULL, NULL); 48 | recv_line[n] = 0; 49 | 50 | fputs(recv_line, stdout); 51 | fputs("\n", stdout); 52 | } 53 | 54 | exit(0); 55 | } -------------------------------------------------------------------------------- /chap-7/unixdataserver.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by shengym on 2019-07-15. 3 | // 4 | 5 | #include "lib/common.h" 6 | 7 | 8 | int main(int argc, char **argv) { 9 | if (argc != 2) { 10 | error(1, 0, "usage: unixdataserver "); 11 | } 12 | 13 | int socket_fd; 14 | socket_fd = socket(AF_LOCAL, SOCK_DGRAM, 0); 15 | if (socket_fd < 0) { 16 | error(1, errno, "socket create failed"); 17 | } 18 | 19 | struct sockaddr_un servaddr; 20 | char *local_path = argv[1]; 21 | unlink(local_path); 22 | bzero(&servaddr, sizeof(servaddr)); 23 | servaddr.sun_family = AF_LOCAL; 24 | strcpy(servaddr.sun_path, local_path); 25 | 26 | if (bind(socket_fd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0) { 27 | error(1, errno, "bind failed"); 28 | } 29 | 30 | char buf[BUFFER_SIZE]; 31 | 32 | struct sockaddr_un client_addr; 33 | socklen_t client_len = sizeof(client_addr); 34 | while (1) { 35 | bzero(buf, sizeof(buf)); 36 | if (recvfrom(socket_fd, buf, BUFFER_SIZE, 0, (struct sockadd *) &client_addr, &client_len) == 0) { 37 | printf("client quit"); 38 | break; 39 | } 40 | printf("Receive: %s \n", buf); 41 | 42 | char send_line[MAXLINE]; 43 | bzero(send_line, MAXLINE); 44 | sprintf(send_line, "Hi, %s", buf); 45 | 46 | size_t nbytes = strlen(send_line); 47 | printf("now sending: %s \n", send_line); 48 | 49 | if (sendto(socket_fd, send_line, nbytes, 0, (struct sockadd *) &client_addr, client_len) != nbytes) 50 | error(1, errno, "sendto error"); 51 | } 52 | 53 | close(socket_fd); 54 | 55 | exit(0); 56 | 57 | } -------------------------------------------------------------------------------- /chap-7/unixstreamclient.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by shengym on 2019-07-15. 3 | // 4 | #include "lib/common.h" 5 | 6 | int main(int argc, char **argv) { 7 | if (argc != 2) { 8 | error(1, 0, "usage: unixstreamclient "); 9 | } 10 | 11 | int sockfd; 12 | struct sockaddr_un servaddr; 13 | 14 | sockfd = socket(AF_LOCAL, SOCK_STREAM, 0); 15 | if (sockfd < 0) { 16 | error(1, errno, "create socket failed"); 17 | } 18 | 19 | bzero(&servaddr, sizeof(servaddr)); 20 | servaddr.sun_family = AF_LOCAL; 21 | strcpy(servaddr.sun_path, argv[1]); 22 | 23 | if (connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0) { 24 | error(1, errno, "connect failed"); 25 | } 26 | 27 | char send_line[MAXLINE]; 28 | bzero(send_line, MAXLINE); 29 | char recv_line[MAXLINE]; 30 | 31 | while (fgets(send_line, MAXLINE, stdin) != NULL) { 32 | 33 | int nbytes = sizeof(send_line); 34 | if (write(sockfd, send_line, nbytes) != nbytes) 35 | error(1, errno, "write error"); 36 | 37 | if (read(sockfd, recv_line, MAXLINE) == 0) 38 | error(1, errno, "server terminated prematurely"); 39 | 40 | fputs(recv_line, stdout); 41 | } 42 | 43 | exit(0); 44 | } -------------------------------------------------------------------------------- /chap-7/unixstreamserver.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by shengym on 2019-07-14. 3 | // 4 | 5 | #include "lib/common.h" 6 | 7 | 8 | int main(int argc, char **argv) { 9 | if (argc != 2) { 10 | error(1, 0, "usage: unixstreamserver "); 11 | } 12 | 13 | int listenfd, connfd; 14 | socklen_t clilen; 15 | struct sockaddr_un cliaddr, servaddr; 16 | 17 | listenfd = socket(AF_LOCAL, SOCK_STREAM, 0); 18 | if (listenfd < 0) { 19 | error(1, errno, "socket create failed"); 20 | } 21 | 22 | char *local_path = argv[1]; 23 | unlink(local_path); 24 | bzero(&servaddr, sizeof(servaddr)); 25 | servaddr.sun_family = AF_LOCAL; 26 | strcpy(servaddr.sun_path, local_path); 27 | 28 | if (bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0) { 29 | error(1, errno, "bind failed"); 30 | } 31 | 32 | if (listen(listenfd, LISTENQ) < 0) { 33 | error(1, errno, "listen failed"); 34 | } 35 | 36 | clilen = sizeof(cliaddr); 37 | if ((connfd = accept(listenfd, (struct sockaddr *) &cliaddr, &clilen)) < 0) { 38 | if (errno == EINTR) 39 | error(1, errno, "accept failed"); 40 | else 41 | error(1, errno, "accept failed"); 42 | } 43 | 44 | char buf[BUFFER_SIZE]; 45 | 46 | while (1) { 47 | bzero(buf, sizeof(buf)); 48 | if (read(connfd, buf, BUFFER_SIZE) == 0) { 49 | printf("client quit"); 50 | break; 51 | } 52 | printf("Receive: %s", buf); 53 | 54 | char send_line[MAXLINE]; 55 | bzero(send_line, MAXLINE); 56 | sprintf(send_line, "Hi, %s", buf); 57 | 58 | int nbytes = sizeof(send_line); 59 | 60 | if (write(connfd, send_line, nbytes) != nbytes) 61 | error(1, errno, "write error"); 62 | } 63 | 64 | close(listenfd); 65 | close(connfd); 66 | 67 | exit(0); 68 | 69 | } 70 | -------------------------------------------------------------------------------- /clean.sh: -------------------------------------------------------------------------------- 1 | rm -rf CMakeFiles/ 2 | rm -rf bin/ 3 | rm CMakeCache.txt 4 | rm cmake_install.cmake 5 | rm Makefile -------------------------------------------------------------------------------- /config.h.cmake: -------------------------------------------------------------------------------- 1 | /* Define to 1 if you have the `epoll_create1' function. */ 2 | #cmakedefine EPOLL_ENABLE 1 3 | -------------------------------------------------------------------------------- /lib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | if (EPOLL_EXISTS) 2 | set(yolanda_lib 3 | log.c 4 | sock_ntop.c 5 | read.c 6 | tcp_server.c 7 | tcp_client.c 8 | event_loop.c 9 | channel.c 10 | acceptor.c 11 | channel_map.c 12 | poll_dispatcher.c 13 | thread_pool.c 14 | event_loop_thread.c 15 | utils.c 16 | epoll_dispatcher.c 17 | buffer.c 18 | tcp_connection.c 19 | http_server.c 20 | http_request.c 21 | http_response.c 22 | ) 23 | else () 24 | set(yolanda_lib 25 | log.c 26 | sock_ntop.c 27 | read.c 28 | tcp_server.c 29 | tcp_client.c 30 | event_loop.c 31 | channel.c 32 | acceptor.c 33 | channel_map.c 34 | poll_dispatcher.c 35 | thread_pool.c 36 | event_loop_thread.c 37 | utils.c 38 | buffer.c 39 | tcp_connection.c 40 | http_server.c 41 | http_request.c 42 | http_response.c 43 | ) 44 | endif () 45 | 46 | 47 | add_library(yolanda ${yolanda_lib}) 48 | target_link_libraries(yolanda pthread) 49 | 50 | install(TARGETS yolanda DESTINATION lib) 51 | 52 | #file(GLOB HEADERS "*.h") 53 | #install(FILES ${HEADERS} DESTINATION include/) 54 | 55 | -------------------------------------------------------------------------------- /lib/acceptor.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "acceptor.h" 3 | 4 | struct acceptor *acceptor_init(int port) { 5 | struct acceptor *acceptor1 = malloc(sizeof(struct acceptor)); 6 | acceptor1->listen_port = port; 7 | acceptor1->listen_fd = socket(AF_INET, SOCK_STREAM, 0); 8 | 9 | make_nonblocking(acceptor1->listen_fd); 10 | 11 | struct sockaddr_in server_addr; 12 | bzero(&server_addr, sizeof(server_addr)); 13 | server_addr.sin_family = AF_INET; 14 | server_addr.sin_addr.s_addr = htonl(INADDR_ANY); 15 | server_addr.sin_port = htons(port); 16 | 17 | int on = 1; 18 | setsockopt(acceptor1->listen_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); 19 | 20 | int rt1 = bind(acceptor1->listen_fd, (struct sockaddr *) &server_addr, sizeof(server_addr)); 21 | if (rt1 < 0) { 22 | error(1, errno, "bind failed "); 23 | } 24 | 25 | int rt2 = listen(acceptor1->listen_fd, LISTENQ); 26 | if (rt2 < 0) { 27 | error(1, errno, "listen failed "); 28 | } 29 | 30 | // signal(SIGPIPE, SIG_IGN); 31 | 32 | return acceptor1; 33 | } -------------------------------------------------------------------------------- /lib/acceptor.h: -------------------------------------------------------------------------------- 1 | #ifndef ACCEPTOR_H 2 | #define ACCEPTOR_H 3 | 4 | #include "common.h" 5 | 6 | struct acceptor{ 7 | int listen_port; 8 | int listen_fd; 9 | } ; 10 | 11 | struct acceptor *acceptor_init(int port); 12 | 13 | 14 | #endif -------------------------------------------------------------------------------- /lib/buffer.c: -------------------------------------------------------------------------------- 1 | #include "buffer.h" 2 | #include "common.h" 3 | 4 | const char *CRLF = "\r\n"; 5 | 6 | struct buffer *buffer_new() { 7 | struct buffer *buffer1 = malloc(sizeof(struct buffer)); 8 | if (!buffer1) 9 | return NULL; 10 | 11 | buffer1->data = malloc(INIT_BUFFER_SIZE); 12 | buffer1->total_size = INIT_BUFFER_SIZE; 13 | buffer1->readIndex = 0; 14 | buffer1->writeIndex = 0; 15 | return buffer1; 16 | } 17 | 18 | void buffer_free(struct buffer *buffer1) { 19 | free(buffer1->data); 20 | free(buffer1); 21 | } 22 | 23 | int buffer_writeable_size(struct buffer *buffer) { 24 | return buffer->total_size - buffer->writeIndex; 25 | } 26 | 27 | int buffer_readable_size(struct buffer *buffer) { 28 | return buffer->writeIndex - buffer->readIndex; 29 | } 30 | 31 | int buffer_front_spare_size(struct buffer *buffer) { 32 | return buffer->readIndex; 33 | } 34 | 35 | void make_room(struct buffer *buffer, int size) { 36 | if (buffer_writeable_size(buffer) >= size) { 37 | return; 38 | } 39 | //如果front_spare和writeable的大小加起来可以容纳数据,则把可读数据往前面拷贝 40 | if (buffer_front_spare_size(buffer) + buffer_writeable_size(buffer) >= size) { 41 | int readable = buffer_readable_size(buffer); 42 | int i; 43 | for (i = 0; i < readable; i++) { 44 | memcpy(buffer->data + i, buffer->data + buffer->readIndex + i, 1); 45 | } 46 | buffer->readIndex = 0; 47 | buffer->writeIndex = readable; 48 | } else { 49 | //扩大缓冲区 50 | void *tmp = realloc(buffer->data, buffer->total_size + size); 51 | if (tmp == NULL) { 52 | return; 53 | } 54 | buffer->data = tmp; 55 | buffer->total_size += size; 56 | } 57 | } 58 | 59 | int buffer_append(struct buffer *buffer, void *data, int size) { 60 | if (data != NULL) { 61 | make_room(buffer, size); 62 | //拷贝数据到可写空间中 63 | memcpy(buffer->data + buffer->writeIndex, data, size); 64 | buffer->writeIndex += size; 65 | } 66 | } 67 | 68 | int buffer_append_char(struct buffer *buffer, char data) { 69 | make_room(buffer, 1); 70 | //拷贝数据到可写空间中 71 | buffer->data[buffer->writeIndex++] = data; 72 | } 73 | 74 | int buffer_append_string(struct buffer *buffer, char *data) { 75 | if (data != NULL) { 76 | int size = strlen(data); 77 | buffer_append(buffer, data, size); 78 | } 79 | } 80 | 81 | 82 | int buffer_socket_read(struct buffer *buffer, int fd) { 83 | char additional_buffer[INIT_BUFFER_SIZE]; 84 | struct iovec vec[2]; 85 | int max_writable = buffer_writeable_size(buffer); 86 | vec[0].iov_base = buffer->data + buffer->writeIndex; 87 | vec[0].iov_len = max_writable; 88 | vec[1].iov_base = additional_buffer; 89 | vec[1].iov_len = sizeof(additional_buffer); 90 | int result = readv(fd, vec, 2); 91 | if (result < 0) { 92 | return -1; 93 | } else if (result <= max_writable) { 94 | buffer->writeIndex += result; 95 | } else { 96 | buffer->writeIndex = buffer->total_size; 97 | buffer_append(buffer, additional_buffer, result - max_writable); 98 | } 99 | return result; 100 | } 101 | 102 | char buffer_read_char(struct buffer *buffer) { 103 | char c = buffer->data[buffer->readIndex]; 104 | buffer->readIndex++; 105 | return c; 106 | } 107 | 108 | char *buffer_find_CRLF(struct buffer *buffer) { 109 | char *crlf = memmem(buffer->data + buffer->readIndex, buffer_readable_size(buffer), CRLF, 2); 110 | return crlf; 111 | } -------------------------------------------------------------------------------- /lib/buffer.h: -------------------------------------------------------------------------------- 1 | #ifndef BUFFER_H 2 | #define BUFFER_H 3 | 4 | #define INIT_BUFFER_SIZE 65536 5 | //数据缓冲区 6 | struct buffer { 7 | char *data; //实际缓冲 8 | int readIndex; //缓冲读取位置 9 | int writeIndex; //缓冲写入位置 10 | int total_size; //总大小 11 | }; 12 | 13 | 14 | struct buffer *buffer_new(); 15 | 16 | void buffer_free(struct buffer *buffer); 17 | 18 | int buffer_writeable_size(struct buffer *buffer); 19 | 20 | int buffer_readable_size(struct buffer *buffer); 21 | 22 | int buffer_front_spare_size(struct buffer *buffer); 23 | 24 | //往buffer里写数据 25 | int buffer_append(struct buffer *buffer, void *data, int size); 26 | 27 | //往buffer里写数据 28 | int buffer_append_char(struct buffer *buffer, char data); 29 | 30 | //往buffer里写数据 31 | int buffer_append_string(struct buffer*buffer, char * data); 32 | 33 | //读socket数据,往buffer里写 34 | int buffer_socket_read(struct buffer *buffer, int fd); 35 | 36 | //读buffer数据 37 | char buffer_read_char(struct buffer *buffer); 38 | 39 | //查询buffer数据 40 | char * buffer_find_CRLF(struct buffer * buffer); 41 | 42 | #endif -------------------------------------------------------------------------------- /lib/channel.c: -------------------------------------------------------------------------------- 1 | #include "channel.h" 2 | 3 | 4 | struct channel * 5 | channel_new(int fd, int events, event_read_callback eventReadCallback, event_write_callback eventWriteCallback, 6 | void *data) { 7 | struct channel *chan = malloc(sizeof(struct channel)); 8 | chan->fd = fd; 9 | chan->events = events; 10 | chan->eventReadCallback = eventReadCallback; 11 | chan->eventWriteCallback = eventWriteCallback; 12 | chan->data = data; 13 | return chan; 14 | } 15 | 16 | int channel_write_event_is_enabled(struct channel *channel) { 17 | return channel->events & EVENT_WRITE; 18 | } 19 | 20 | int channel_write_event_enable(struct channel *channel) { 21 | struct event_loop *eventLoop = (struct event_loop *) channel->data; 22 | channel->events = channel->events | EVENT_WRITE; 23 | event_loop_update_channel_event(eventLoop, channel->fd, channel); 24 | } 25 | 26 | int channel_write_event_disable(struct channel *channel) { 27 | struct event_loop *eventLoop = (struct event_loop *) channel->data; 28 | channel->events = channel->events & ~EVENT_WRITE; 29 | event_loop_update_channel_event(eventLoop, channel->fd, channel); 30 | } -------------------------------------------------------------------------------- /lib/channel.h: -------------------------------------------------------------------------------- 1 | #ifndef CHANNEL_H 2 | #define CHANNEL_H 3 | 4 | #include "common.h" 5 | #include "event_loop.h" 6 | #include "buffer.h" 7 | 8 | #define EVENT_TIMEOUT 0x01 9 | /** Wait for a socket or FD to become readable */ 10 | #define EVENT_READ 0x02 11 | /** Wait for a socket or FD to become writeable */ 12 | #define EVENT_WRITE 0x04 13 | /** Wait for a POSIX signal to be raised*/ 14 | #define EVENT_SIGNAL 0x08 15 | 16 | 17 | typedef int (*event_read_callback)(void *data); 18 | 19 | typedef int (*event_write_callback)(void *data); 20 | 21 | struct channel { 22 | int fd; 23 | int events; //表示event类型 24 | 25 | event_read_callback eventReadCallback; 26 | event_write_callback eventWriteCallback; 27 | void *data; //callback data, 可能是event_loop,也可能是tcp_server或者tcp_connection 28 | }; 29 | 30 | 31 | struct channel * 32 | channel_new(int fd, int events, event_read_callback eventReadCallback, event_write_callback eventWriteCallback, 33 | void *data); 34 | 35 | int channel_write_event_is_enabled(struct channel *channel); 36 | 37 | int channel_write_event_enable(struct channel *channel); 38 | 39 | int channel_write_event_disable(struct channel *channel); 40 | 41 | 42 | #endif -------------------------------------------------------------------------------- /lib/channel_map.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "channel_map.h" 3 | 4 | 5 | int map_make_space(struct channel_map *map, int slot, int msize) { 6 | if (map->nentries <= slot) { 7 | int nentries = map->nentries ? map->nentries : 32; 8 | void **tmp; 9 | 10 | while (nentries <= slot) 11 | nentries <<= 1; 12 | 13 | tmp = (void **) realloc(map->entries, nentries * msize); 14 | if (tmp == NULL) 15 | return (-1); 16 | 17 | memset(&tmp[map->nentries], 0, 18 | (nentries - map->nentries) * msize); 19 | 20 | map->nentries = nentries; 21 | map->entries = tmp; 22 | } 23 | 24 | return (0); 25 | } 26 | 27 | void map_init(struct channel_map *map) { 28 | map->nentries = 0; 29 | map->entries = NULL; 30 | } 31 | 32 | void map_clear(struct channel_map *map) { 33 | if (map->entries != NULL) { 34 | int i; 35 | for (i = 0; i < map->nentries; ++i) { 36 | if (map->entries[i] != NULL) 37 | free(map->entries[i]); 38 | } 39 | free(map->entries); 40 | map->entries = NULL; 41 | } 42 | map->nentries = 0; 43 | } 44 | 45 | 46 | -------------------------------------------------------------------------------- /lib/channel_map.h: -------------------------------------------------------------------------------- 1 | #ifndef CHANNEL_MAP_H 2 | #define CHANNEL_MAP_H 3 | 4 | 5 | #include "channel.h" 6 | 7 | /** 8 | * channel映射表, key为对应的socket描述字 9 | */ 10 | struct channel_map { 11 | void **entries; 12 | 13 | /* The number of entries available in entries */ 14 | int nentries; 15 | }; 16 | 17 | 18 | int map_make_space(struct channel_map *map, int slot, int msize); 19 | 20 | void map_init(struct channel_map *map); 21 | 22 | void map_clear(struct channel_map *map); 23 | 24 | #endif -------------------------------------------------------------------------------- /lib/common.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by shengym on 2019-07-07. 3 | // 4 | 5 | #ifndef YOLANDA_COMMON_H 6 | #define YOLANDA_COMMON_H 7 | 8 | #include "config.h" 9 | 10 | #include "log.h" 11 | #include "tcp_server.h" 12 | #include "inetaddress.h" 13 | #include "channel_map.h" 14 | 15 | #include /* basic system data types */ 16 | #include /* basic socket definitions */ 17 | #include /* timeval{} for select() */ 18 | #include /* timespec{} for pselect() */ 19 | #include /* sockaddr_in{} and other Internet defns */ 20 | #include /* inet(3) functions */ 21 | #include 22 | #include /* for nonblocking */ 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include /* for S_xxx file mode constants */ 29 | #include /* for iovec{} and readv/writev */ 30 | #include 31 | #include 32 | #include /* for Unix domain sockets */ 33 | 34 | #include /* for convenience */ 35 | #include 36 | #include /* for convenience */ 37 | #include /* for convenience */ 38 | #include 39 | #include 40 | 41 | #ifdef EPOLL_ENABLE 42 | #include 43 | #endif 44 | 45 | 46 | void err_dump(const char *, ...); 47 | 48 | void err_msg(const char *, ...); 49 | 50 | void err_quit(const char *, ...); 51 | 52 | void err_ret(const char *, ...); 53 | 54 | void err_sys(const char *, ...); 55 | 56 | void error(int status, int err, char *fmt, ...); 57 | 58 | char *sock_ntop(const struct sockaddr_in *sin, socklen_t salen); 59 | 60 | size_t readn(int fd, void *vptr, size_t n); 61 | 62 | size_t read_message(int fd, char *buffer, size_t length); 63 | 64 | size_t readline(int fd, char *buffer, size_t length); 65 | 66 | int tcp_server(int port); 67 | 68 | int tcp_server_listen(int port); 69 | 70 | int tcp_nonblocking_server_listen(int port); 71 | 72 | void make_nonblocking(int fd); 73 | 74 | int tcp_client(char *address, int port); 75 | 76 | #define SERV_PORT 43211 77 | #define MAXLINE 4096 78 | #define UNIXSTR_PATH "/var/lib/unixstream.sock" 79 | #define LISTENQ 1024 80 | #define BUFFER_SIZE 4096 81 | 82 | #endif //YOLANDA_COMMON_H 83 | -------------------------------------------------------------------------------- /lib/epoll_dispatcher.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "event_dispatcher.h" 3 | #include "event_loop.h" 4 | #include "log.h" 5 | 6 | #define MAXEVENTS 128 7 | 8 | typedef struct { 9 | int event_count; 10 | int nfds; 11 | int realloc_copy; 12 | int efd; 13 | struct epoll_event *events; 14 | } epoll_dispatcher_data; 15 | 16 | 17 | static void *epoll_init(struct event_loop *); 18 | 19 | static int epoll_add(struct event_loop *, struct channel *channel1); 20 | 21 | static int epoll_del(struct event_loop *, struct channel *channel1); 22 | 23 | static int epoll_update(struct event_loop *, struct channel *channel1); 24 | 25 | static int epoll_dispatch(struct event_loop *, struct timeval *); 26 | 27 | static void epoll_clear(struct event_loop *); 28 | 29 | const struct event_dispatcher epoll_dispatcher = { 30 | "epoll", 31 | epoll_init, 32 | epoll_add, 33 | epoll_del, 34 | epoll_update, 35 | epoll_dispatch, 36 | epoll_clear, 37 | }; 38 | 39 | void *epoll_init(struct event_loop *eventLoop) { 40 | epoll_dispatcher_data *epollDispatcherData = malloc(sizeof(epoll_dispatcher_data)); 41 | 42 | epollDispatcherData->event_count = 0; 43 | epollDispatcherData->nfds = 0; 44 | epollDispatcherData->realloc_copy = 0; 45 | epollDispatcherData->efd = 0; 46 | 47 | epollDispatcherData->efd = epoll_create1(0); 48 | if (epollDispatcherData->efd == -1) { 49 | error(1, errno, "epoll create failed"); 50 | } 51 | 52 | epollDispatcherData->events = calloc(MAXEVENTS, sizeof(struct epoll_event)); 53 | 54 | return epollDispatcherData; 55 | } 56 | 57 | 58 | int epoll_add(struct event_loop *eventLoop, struct channel *channel1) { 59 | epoll_dispatcher_data *pollDispatcherData = (epoll_dispatcher_data *) eventLoop->event_dispatcher_data; 60 | 61 | int fd = channel1->fd; 62 | int events = 0; 63 | if (channel1->events & EVENT_READ) { 64 | events = events | EPOLLIN; 65 | } 66 | if (channel1->events & EVENT_WRITE) { 67 | events = events | EPOLLOUT; 68 | } 69 | 70 | struct epoll_event event; 71 | event.data.fd = fd; 72 | event.events = events; 73 | // event.events = events | EPOLLET; 74 | if (epoll_ctl(pollDispatcherData->efd, EPOLL_CTL_ADD, fd, &event) == -1) { 75 | error(1, errno, "epoll_ctl add fd failed"); 76 | } 77 | 78 | return 0; 79 | } 80 | 81 | int epoll_del(struct event_loop *eventLoop, struct channel *channel1) { 82 | epoll_dispatcher_data *pollDispatcherData = (epoll_dispatcher_data *) eventLoop->event_dispatcher_data; 83 | 84 | int fd = channel1->fd; 85 | 86 | int events = 0; 87 | if (channel1->events & EVENT_READ) { 88 | events = events | EPOLLIN; 89 | } 90 | 91 | if (channel1->events & EVENT_WRITE) { 92 | events = events | EPOLLOUT; 93 | } 94 | 95 | struct epoll_event event; 96 | event.data.fd = fd; 97 | event.events = events; 98 | // event.events = events | EPOLLET; 99 | if (epoll_ctl(pollDispatcherData->efd, EPOLL_CTL_DEL, fd, &event) == -1) { 100 | error(1, errno, "epoll_ctl delete fd failed"); 101 | } 102 | 103 | return 0; 104 | } 105 | 106 | int epoll_update(struct event_loop *eventLoop, struct channel *channel1) { 107 | epoll_dispatcher_data *pollDispatcherData = (epoll_dispatcher_data *) eventLoop->event_dispatcher_data; 108 | 109 | int fd = channel1->fd; 110 | 111 | int events = 0; 112 | if (channel1->events & EVENT_READ) { 113 | events = events | EPOLLIN; 114 | } 115 | 116 | if (channel1->events & EVENT_WRITE) { 117 | events = events | EPOLLOUT; 118 | } 119 | 120 | struct epoll_event event; 121 | event.data.fd = fd; 122 | event.events = events; 123 | // event.events = events | EPOLLET; 124 | if (epoll_ctl(pollDispatcherData->efd, EPOLL_CTL_MOD, fd, &event) == -1) { 125 | error(1, errno, "epoll_ctl modify fd failed"); 126 | } 127 | 128 | return 0; 129 | } 130 | 131 | int epoll_dispatch(struct event_loop *eventLoop, struct timeval *timeval) { 132 | epoll_dispatcher_data *epollDispatcherData = (epoll_dispatcher_data *) eventLoop->event_dispatcher_data; 133 | int i, n; 134 | 135 | n = epoll_wait(epollDispatcherData->efd, epollDispatcherData->events, MAXEVENTS, -1); 136 | yolanda_msgx("epoll_wait wakeup, %s", eventLoop->thread_name); 137 | for (i = 0; i < n; i++) { 138 | if ((epollDispatcherData->events[i].events & EPOLLERR) || (epollDispatcherData->events[i].events & EPOLLHUP)) { 139 | fprintf(stderr, "epoll error\n"); 140 | close(epollDispatcherData->events[i].data.fd); 141 | continue; 142 | } 143 | 144 | if (epollDispatcherData->events[i].events & EPOLLIN) { 145 | yolanda_msgx("get message channel fd==%d for read, %s", epollDispatcherData->events[i].data.fd, eventLoop->thread_name); 146 | channel_event_activate(eventLoop, epollDispatcherData->events[i].data.fd, EVENT_READ); 147 | } 148 | 149 | if (epollDispatcherData->events[i].events & EPOLLOUT) { 150 | yolanda_msgx("get message channel fd==%d for write, %s", epollDispatcherData->events[i].data.fd,eventLoop->thread_name); 151 | channel_event_activate(eventLoop, epollDispatcherData->events[i].data.fd, EVENT_WRITE); 152 | } 153 | } 154 | 155 | return 0; 156 | } 157 | 158 | void epoll_clear(struct event_loop *eventLoop) { 159 | epoll_dispatcher_data *epollDispatcherData = (epoll_dispatcher_data *) eventLoop->event_dispatcher_data; 160 | 161 | free(epollDispatcherData->events); 162 | close(epollDispatcherData->efd); 163 | free(epollDispatcherData); 164 | eventLoop->event_dispatcher_data = NULL; 165 | 166 | return; 167 | } -------------------------------------------------------------------------------- /lib/event_dispatcher.h: -------------------------------------------------------------------------------- 1 | #ifndef EVENT_DISPATCHER_H 2 | #define EVENT_DISPATCHER_H 3 | 4 | #include "channel.h" 5 | 6 | /** 抽象的event_dispatcher结构体,对应的实现如select,poll,epoll等I/O复用. */ 7 | struct event_dispatcher { 8 | /** 对应实现 */ 9 | const char *name; 10 | 11 | /** 初始化函数 */ 12 | void *(*init)(struct event_loop * eventLoop); 13 | 14 | /** 通知dispatcher新增一个channel事件*/ 15 | int (*add)(struct event_loop * eventLoop, struct channel * channel); 16 | 17 | /** 通知dispatcher删除一个channel事件*/ 18 | int (*del)(struct event_loop * eventLoop, struct channel * channel); 19 | 20 | /** 通知dispatcher更新channel对应的事件*/ 21 | int (*update)(struct event_loop * eventLoop, struct channel * channel); 22 | 23 | /** 实现事件分发,然后调用event_loop的event_activate方法执行callback*/ 24 | int (*dispatch)(struct event_loop * eventLoop, struct timeval *); 25 | 26 | /** 清除数据 */ 27 | void (*clear)(struct event_loop * eventLoop); 28 | }; 29 | 30 | #endif -------------------------------------------------------------------------------- /lib/event_loop.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "event_loop.h" 3 | #include "common.h" 4 | #include "log.h" 5 | #include "event_dispatcher.h" 6 | #include "channel.h" 7 | #include "utils.h" 8 | 9 | // in the i/o thread 10 | int event_loop_handle_pending_channel(struct event_loop *eventLoop) { 11 | //get the lock 12 | pthread_mutex_lock(&eventLoop->mutex); 13 | eventLoop->is_handle_pending = 1; 14 | 15 | struct channel_element *channelElement = eventLoop->pending_head; 16 | while (channelElement != NULL) { 17 | //save into event_map 18 | struct channel *channel = channelElement->channel; 19 | int fd = channel->fd; 20 | if (channelElement->type == 1) { 21 | event_loop_handle_pending_add(eventLoop, fd, channel); 22 | } else if (channelElement->type == 2) { 23 | event_loop_handle_pending_remove(eventLoop, fd, channel); 24 | } else if (channelElement->type == 3) { 25 | event_loop_handle_pending_update(eventLoop, fd, channel); 26 | } 27 | channelElement = channelElement->next; 28 | } 29 | 30 | eventLoop->pending_head = eventLoop->pending_tail = NULL; 31 | eventLoop->is_handle_pending = 0; 32 | 33 | //release the lock 34 | pthread_mutex_unlock(&eventLoop->mutex); 35 | 36 | return 0; 37 | } 38 | 39 | void event_loop_channel_buffer_nolock(struct event_loop *eventLoop, int fd, struct channel *channel1, int type) { 40 | //add channel into the pending list 41 | struct channel_element *channelElement = malloc(sizeof(struct channel_element)); 42 | channelElement->channel = channel1; 43 | channelElement->type = type; 44 | channelElement->next = NULL; 45 | //第一个元素 46 | if (eventLoop->pending_head == NULL) { 47 | eventLoop->pending_head = eventLoop->pending_tail = channelElement; 48 | } else { 49 | eventLoop->pending_tail->next = channelElement; 50 | eventLoop->pending_tail = channelElement; 51 | } 52 | } 53 | 54 | int event_loop_do_channel_event(struct event_loop *eventLoop, int fd, struct channel *channel1, int type) { 55 | //get the lock 56 | pthread_mutex_lock(&eventLoop->mutex); 57 | assert(eventLoop->is_handle_pending == 0); 58 | event_loop_channel_buffer_nolock(eventLoop, fd, channel1, type); 59 | //release the lock 60 | pthread_mutex_unlock(&eventLoop->mutex); 61 | if (!isInSameThread(eventLoop)) { 62 | event_loop_wakeup(eventLoop); 63 | } else { 64 | event_loop_handle_pending_channel(eventLoop); 65 | } 66 | 67 | return 0; 68 | 69 | } 70 | 71 | int event_loop_add_channel_event(struct event_loop *eventLoop, int fd, struct channel *channel1) { 72 | return event_loop_do_channel_event(eventLoop, fd, channel1, 1); 73 | } 74 | 75 | int event_loop_remove_channel_event(struct event_loop *eventLoop, int fd, struct channel *channel1) { 76 | return event_loop_do_channel_event(eventLoop, fd, channel1, 2); 77 | } 78 | 79 | int event_loop_update_channel_event(struct event_loop *eventLoop, int fd, struct channel *channel1) { 80 | return event_loop_do_channel_event(eventLoop, fd, channel1, 3); 81 | } 82 | 83 | // in the i/o thread 84 | int event_loop_handle_pending_add(struct event_loop *eventLoop, int fd, struct channel *channel) { 85 | yolanda_msgx("add channel fd == %d, %s", fd, eventLoop->thread_name); 86 | struct channel_map *map = eventLoop->channelMap; 87 | 88 | if (fd < 0) 89 | return 0; 90 | 91 | if (fd >= map->nentries) { 92 | if (map_make_space(map, fd, sizeof(struct channel *)) == -1) 93 | return (-1); 94 | } 95 | 96 | //第一次创建,增加 97 | if ((map)->entries[fd] == NULL) { 98 | map->entries[fd] = channel; 99 | //add channel 100 | struct event_dispatcher *eventDispatcher = eventLoop->eventDispatcher; 101 | eventDispatcher->add(eventLoop, channel); 102 | return 1; 103 | } 104 | 105 | return 0; 106 | } 107 | 108 | // in the i/o thread 109 | int event_loop_handle_pending_remove(struct event_loop *eventLoop, int fd, struct channel *channel1) { 110 | struct channel_map *map = eventLoop->channelMap; 111 | assert(fd == channel1->fd); 112 | 113 | if (fd < 0) 114 | return 0; 115 | 116 | if (fd >= map->nentries) 117 | return (-1); 118 | 119 | struct channel *channel2 = map->entries[fd]; 120 | 121 | //update dispatcher(multi-thread)here 122 | struct event_dispatcher *eventDispatcher = eventLoop->eventDispatcher; 123 | 124 | int retval = 0; 125 | if (eventDispatcher->del(eventLoop, channel2) == -1) { 126 | retval = -1; 127 | } else { 128 | retval = 1; 129 | } 130 | 131 | map->entries[fd] = NULL; 132 | return retval; 133 | } 134 | 135 | // in the i/o thread 136 | int event_loop_handle_pending_update(struct event_loop *eventLoop, int fd, struct channel *channel) { 137 | yolanda_msgx("update channel fd == %d, %s", fd, eventLoop->thread_name); 138 | struct channel_map *map = eventLoop->channelMap; 139 | 140 | if (fd < 0) 141 | return 0; 142 | 143 | if ((map)->entries[fd] == NULL) { 144 | return (-1); 145 | } 146 | 147 | //update channel 148 | struct event_dispatcher *eventDispatcher = eventLoop->eventDispatcher; 149 | eventDispatcher->update(eventLoop, channel); 150 | } 151 | 152 | int channel_event_activate(struct event_loop *eventLoop, int fd, int revents) { 153 | struct channel_map *map = eventLoop->channelMap; 154 | yolanda_msgx("activate channel fd == %d, revents=%d, %s", fd, revents, eventLoop->thread_name); 155 | 156 | if (fd < 0) 157 | return 0; 158 | 159 | if (fd >= map->nentries)return (-1); 160 | 161 | struct channel *channel = map->entries[fd]; 162 | assert(fd == channel->fd); 163 | 164 | if (revents & (EVENT_READ)) { 165 | if (channel->eventReadCallback) channel->eventReadCallback(channel->data); 166 | } 167 | if (revents & (EVENT_WRITE)) { 168 | if (channel->eventWriteCallback) channel->eventWriteCallback(channel->data); 169 | } 170 | 171 | return 0; 172 | 173 | } 174 | 175 | void event_loop_wakeup(struct event_loop *eventLoop) { 176 | char one = 'a'; 177 | ssize_t n = write(eventLoop->socketPair[0], &one, sizeof one); 178 | if (n != sizeof one) { 179 | LOG_ERR("wakeup event loop thread failed"); 180 | } 181 | } 182 | 183 | int handleWakeup(void *data) { 184 | struct event_loop *eventLoop = (struct event_loop *) data; 185 | char one; 186 | ssize_t n = read(eventLoop->socketPair[1], &one, sizeof one); 187 | if (n != sizeof one) { 188 | LOG_ERR("handleWakeup failed"); 189 | } 190 | yolanda_msgx("wakeup, %s", eventLoop->thread_name); 191 | } 192 | 193 | struct event_loop *event_loop_init() { 194 | return event_loop_init_with_name(NULL); 195 | } 196 | 197 | struct event_loop *event_loop_init_with_name(char *thread_name) { 198 | struct event_loop *eventLoop = malloc(sizeof(struct event_loop)); 199 | pthread_mutex_init(&eventLoop->mutex, NULL); 200 | pthread_cond_init(&eventLoop->cond, NULL); 201 | 202 | if (thread_name != NULL) { 203 | eventLoop->thread_name = thread_name; 204 | } else { 205 | eventLoop->thread_name = "main thread"; 206 | } 207 | 208 | eventLoop->quit = 0; 209 | eventLoop->channelMap = malloc(sizeof(struct channel_map)); 210 | map_init(eventLoop->channelMap); 211 | 212 | #ifdef EPOLL_ENABLE 213 | yolanda_msgx("set epoll as dispatcher, %s", eventLoop->thread_name); 214 | eventLoop->eventDispatcher = &epoll_dispatcher; 215 | #else 216 | yolanda_msgx("set poll as dispatcher, %s", eventLoop->thread_name); 217 | eventLoop->eventDispatcher = &poll_dispatcher; 218 | #endif 219 | eventLoop->event_dispatcher_data = eventLoop->eventDispatcher->init(eventLoop); 220 | 221 | //add the socketfd to event 222 | eventLoop->owner_thread_id = pthread_self(); 223 | if (socketpair(AF_UNIX, SOCK_STREAM, 0, eventLoop->socketPair) < 0) { 224 | LOG_ERR("socketpair set fialed"); 225 | } 226 | eventLoop->is_handle_pending = 0; 227 | eventLoop->pending_head = NULL; 228 | eventLoop->pending_tail = NULL; 229 | 230 | struct channel *channel = channel_new(eventLoop->socketPair[1], EVENT_READ, handleWakeup, NULL, eventLoop); 231 | event_loop_add_channel_event(eventLoop, eventLoop->socketPair[1], channel); 232 | 233 | return eventLoop; 234 | } 235 | 236 | /** 237 | * 238 | * 1.参数验证 239 | * 2.调用dispatcher来进行事件分发,分发完回调事件处理函数 240 | */ 241 | int event_loop_run(struct event_loop *eventLoop) { 242 | assert(eventLoop != NULL); 243 | 244 | struct event_dispatcher *dispatcher = eventLoop->eventDispatcher; 245 | 246 | if (eventLoop->owner_thread_id != pthread_self()) { 247 | exit(1); 248 | } 249 | 250 | yolanda_msgx("event loop run, %s", eventLoop->thread_name); 251 | struct timeval timeval; 252 | timeval.tv_sec = 1; 253 | 254 | while (!eventLoop->quit) { 255 | //block here to wait I/O event, and get active channels 256 | dispatcher->dispatch(eventLoop, &timeval); 257 | 258 | //handle the pending channel 259 | event_loop_handle_pending_channel(eventLoop); 260 | } 261 | 262 | yolanda_msgx("event loop end, %s", eventLoop->thread_name); 263 | return 0; 264 | } 265 | 266 | 267 | -------------------------------------------------------------------------------- /lib/event_loop.h: -------------------------------------------------------------------------------- 1 | #ifndef EVENT_LOOP_H 2 | #define EVENT_LOOP_H 3 | 4 | #include 5 | #include "channel.h" 6 | #include "event_dispatcher.h" 7 | #include "common.h" 8 | 9 | extern const struct event_dispatcher poll_dispatcher; 10 | extern const struct event_dispatcher epoll_dispatcher; 11 | 12 | struct channel_element { 13 | int type; //1: add 2: delete 14 | struct channel *channel; 15 | struct channel_element *next; 16 | }; 17 | 18 | struct event_loop { 19 | int quit; 20 | const struct event_dispatcher *eventDispatcher; 21 | 22 | /** 对应的event_dispatcher的数据. */ 23 | void *event_dispatcher_data; 24 | struct channel_map *channelMap; 25 | 26 | int is_handle_pending; 27 | struct channel_element *pending_head; 28 | struct channel_element *pending_tail; 29 | 30 | pthread_t owner_thread_id; 31 | pthread_mutex_t mutex; 32 | pthread_cond_t cond; 33 | int socketPair[2]; 34 | char *thread_name; 35 | }; 36 | 37 | struct event_loop *event_loop_init(); 38 | 39 | struct event_loop *event_loop_init_with_name(char * thread_name); 40 | 41 | int event_loop_run(struct event_loop *eventLoop); 42 | 43 | void event_loop_wakeup(struct event_loop *eventLoop); 44 | 45 | int event_loop_add_channel_event(struct event_loop *eventLoop, int fd, struct channel *channel1); 46 | 47 | int event_loop_remove_channel_event(struct event_loop *eventLoop, int fd, struct channel *channel1); 48 | 49 | int event_loop_update_channel_event(struct event_loop *eventLoop, int fd, struct channel *channel1); 50 | 51 | int event_loop_handle_pending_add(struct event_loop *eventLoop, int fd, struct channel *channel); 52 | 53 | int event_loop_handle_pending_remove(struct event_loop *eventLoop, int fd, struct channel *channel); 54 | 55 | int event_loop_handle_pending_update(struct event_loop *eventLoop, int fd, struct channel *channel); 56 | 57 | // dispather派发完事件之后,调用该方法通知event_loop执行对应事件的相关callback方法 58 | // res: EVENT_READ | EVENT_READ等 59 | int channel_event_activate(struct event_loop *eventLoop, int fd, int res); 60 | 61 | #endif -------------------------------------------------------------------------------- /lib/event_loop_thread.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "event_loop_thread.h" 3 | #include "event_loop.h" 4 | 5 | void *event_loop_thread_run(void *arg) { 6 | struct event_loop_thread *eventLoopThread = (struct event_loop_thread *) arg; 7 | 8 | pthread_mutex_lock(&eventLoopThread->mutex); 9 | 10 | // 初始化化event loop,之后通知主线程 11 | eventLoopThread->eventLoop = event_loop_init_with_name(eventLoopThread->thread_name); 12 | yolanda_msgx("event loop thread init and signal, %s", eventLoopThread->thread_name); 13 | pthread_cond_signal(&eventLoopThread->cond); 14 | 15 | pthread_mutex_unlock(&eventLoopThread->mutex); 16 | 17 | //子线程event loop run 18 | event_loop_run(eventLoopThread->eventLoop); 19 | } 20 | 21 | //初始化已经分配内存的event_loop_thread 22 | int event_loop_thread_init(struct event_loop_thread *eventLoopThread, int i) { 23 | pthread_mutex_init(&eventLoopThread->mutex, NULL); 24 | pthread_cond_init(&eventLoopThread->cond, NULL); 25 | eventLoopThread->eventLoop = NULL; 26 | eventLoopThread->thread_count = 0; 27 | eventLoopThread->thread_tid = 0; 28 | 29 | char *buf = malloc(16); 30 | sprintf(buf, "Thread-%d\0", i + 1); 31 | eventLoopThread->thread_name = buf; 32 | 33 | return 0; 34 | } 35 | 36 | 37 | //由主线程调用,初始化一个子线程,并且让子线程开始运行event_loop 38 | struct event_loop *event_loop_thread_start(struct event_loop_thread *eventLoopThread) { 39 | pthread_create(&eventLoopThread->thread_tid, NULL, &event_loop_thread_run, eventLoopThread); 40 | 41 | assert(pthread_mutex_lock(&eventLoopThread->mutex) == 0); 42 | 43 | while (eventLoopThread->eventLoop == NULL) { 44 | assert(pthread_cond_wait(&eventLoopThread->cond, &eventLoopThread->mutex) == 0); 45 | } 46 | assert(pthread_mutex_unlock(&eventLoopThread->mutex) == 0); 47 | 48 | yolanda_msgx("event loop thread started, %s", eventLoopThread->thread_name); 49 | return eventLoopThread->eventLoop; 50 | } -------------------------------------------------------------------------------- /lib/event_loop_thread.h: -------------------------------------------------------------------------------- 1 | #ifndef EVENT_LOOP_THREAD_H 2 | #define EVENT_LOOP_THREAD_H 3 | 4 | #include 5 | 6 | struct event_loop_thread { 7 | struct event_loop *eventLoop; 8 | pthread_t thread_tid; /* thread ID */ 9 | pthread_mutex_t mutex; 10 | pthread_cond_t cond; 11 | char * thread_name; 12 | long thread_count; /* # connections handled */ 13 | }; 14 | 15 | //初始化已经分配内存的event_loop_thread 16 | int event_loop_thread_init(struct event_loop_thread *, int); 17 | 18 | //由主线程调用,初始化一个子线程,并且让子线程开始运行event_loop 19 | struct event_loop *event_loop_thread_start(struct event_loop_thread *); 20 | 21 | #endif -------------------------------------------------------------------------------- /lib/http_request.c: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | #include "http_request.h" 3 | 4 | #define INIT_REQUEST_HEADER_SIZE 128 5 | 6 | const char *HTTP10 = "HTTP/1.0"; 7 | const char *HTTP11 = "HTTP/1.1"; 8 | const char *KEEP_ALIVE = "Keep-Alive"; 9 | const char *CLOSE = "close"; 10 | 11 | //初始化一个request对象 12 | struct http_request *http_request_new() { 13 | struct http_request *httpRequest = malloc(sizeof(struct http_request)); 14 | httpRequest->method = NULL; 15 | httpRequest->current_state = REQUEST_STATUS; 16 | httpRequest->version = NULL; 17 | httpRequest->url = NULL; 18 | httpRequest->request_headers = malloc(sizeof(struct http_request) * INIT_REQUEST_HEADER_SIZE); 19 | httpRequest->request_headers_number = 0; 20 | return httpRequest; 21 | } 22 | 23 | //清除一个request对象 24 | void http_request_clear(struct http_request *httpRequest) { 25 | if (httpRequest->request_headers != NULL) { 26 | for (int i = 0; i < httpRequest->request_headers_number; i++) { 27 | free(httpRequest->request_headers[i].key); 28 | free(httpRequest->request_headers[i].value); 29 | } 30 | free(httpRequest->request_headers); 31 | } 32 | free(httpRequest); 33 | } 34 | 35 | //重置一个request对象 36 | void http_request_reset(struct http_request *httpRequest) { 37 | httpRequest->method = NULL; 38 | httpRequest->current_state = REQUEST_STATUS; 39 | httpRequest->version = NULL; 40 | httpRequest->url = NULL; 41 | httpRequest->request_headers_number = 0; 42 | } 43 | 44 | //给request增加header 45 | void http_request_add_header(struct http_request *httpRequest, char *key, char *value) { 46 | httpRequest->request_headers[httpRequest->request_headers_number].key = key; 47 | httpRequest->request_headers[httpRequest->request_headers_number].value = value; 48 | httpRequest->request_headers_number++; 49 | } 50 | 51 | //根据key值获取header熟悉 52 | char *http_request_get_header(struct http_request *httpRequest, char *key) { 53 | if (httpRequest->request_headers != NULL) { 54 | for (int i = 0; i < httpRequest->request_headers_number; i++) { 55 | if (strncmp(httpRequest->request_headers[i].key, key, strlen(key)) == 0) { 56 | return httpRequest->request_headers[i].value; 57 | } 58 | } 59 | } 60 | return NULL; 61 | } 62 | 63 | //获得request解析的当前状态 64 | enum http_request_state http_request_current_state(struct http_request *httpRequest) { 65 | return httpRequest->current_state; 66 | } 67 | 68 | //根据request请求判断是否需要关闭服务器-->客户端单向连接 69 | int http_request_close_connection(struct http_request *httpRequest) { 70 | char *connection = http_request_get_header(httpRequest, "Connection"); 71 | 72 | if (connection != NULL && strncmp(connection, CLOSE, strlen(CLOSE)) == 0) { 73 | return 1; 74 | } 75 | 76 | if (httpRequest->version != NULL && 77 | strncmp(httpRequest->version, HTTP10, strlen(HTTP10)) == 0 && 78 | strncmp(connection, KEEP_ALIVE, strlen(KEEP_ALIVE)) == 1) { 79 | return 1; 80 | } 81 | return 0; 82 | } 83 | -------------------------------------------------------------------------------- /lib/http_request.h: -------------------------------------------------------------------------------- 1 | #ifndef HTTP_REQUEST_H 2 | #define HTTP_REQUEST_H 3 | 4 | struct request_header { 5 | char *key; 6 | char *value; 7 | }; 8 | 9 | enum http_request_state { 10 | REQUEST_STATUS, //等待解析状态行 11 | REQUEST_HEADERS, //等待解析headers 12 | REQUEST_BODY, //等待解析请求body 13 | REQUEST_DONE //解析完成 14 | }; 15 | 16 | struct http_request { 17 | char *version; 18 | char *method; 19 | char *url; 20 | enum http_request_state current_state; 21 | struct request_header *request_headers; 22 | int request_headers_number; 23 | }; 24 | 25 | //初始化一个request对象 26 | struct http_request *http_request_new(); 27 | 28 | //清除一个request对象 29 | void http_request_clear(struct http_request *httpRequest); 30 | 31 | //重置一个request对象 32 | void http_request_reset(struct http_request *httpRequest); 33 | 34 | //给request增加header 35 | void http_request_add_header(struct http_request *httpRequest, char * key, char * value); 36 | 37 | //根据key值获取header熟悉 38 | char *http_request_get_header(struct http_request *httpRequest, char *key); 39 | 40 | //获得request解析的当前状态 41 | enum http_request_state http_request_current_state(struct http_request *httpRequest); 42 | 43 | //根据request请求判断是否需要关闭服务器-->客户端单向连接 44 | int http_request_close_connection(struct http_request *httpRequest); 45 | 46 | #endif -------------------------------------------------------------------------------- /lib/http_response.c: -------------------------------------------------------------------------------- 1 | #include "http_response.h" 2 | #include "common.h" 3 | 4 | #define INIT_RESPONSE_HEADER_SIZE 128 5 | 6 | struct http_response *http_response_new() { 7 | struct http_response *httpResponse = malloc(sizeof(struct http_response)); 8 | httpResponse->body = NULL; 9 | httpResponse->statusCode = Unknown; 10 | httpResponse->statusMessage = NULL; 11 | httpResponse->response_headers = malloc(sizeof(struct response_header) * INIT_RESPONSE_HEADER_SIZE); 12 | httpResponse->response_headers_number = 0; 13 | httpResponse->keep_connected = 0; 14 | return httpResponse; 15 | } 16 | 17 | void http_response_encode_buffer(struct http_response *httpResponse, struct buffer *output) { 18 | char buf[32]; 19 | snprintf(buf, sizeof buf, "HTTP/1.1 %d ", httpResponse->statusCode); 20 | buffer_append_string(output, buf); 21 | buffer_append_string(output, httpResponse->statusMessage); 22 | buffer_append_string(output, "\r\n"); 23 | 24 | if (httpResponse->keep_connected) { 25 | buffer_append_string(output, "Connection: close\r\n"); 26 | } else { 27 | snprintf(buf, sizeof buf, "Content-Length: %zd\r\n", strlen(httpResponse->body)); 28 | buffer_append_string(output, buf); 29 | buffer_append_string(output, "Connection: Keep-Alive\r\n"); 30 | } 31 | 32 | if (httpResponse->response_headers != NULL && httpResponse->response_headers_number > 0) { 33 | for (int i = 0; i < httpResponse->response_headers_number; i++) { 34 | buffer_append_string(output, httpResponse->response_headers[i].key); 35 | buffer_append_string(output, ": "); 36 | buffer_append_string(output, httpResponse->response_headers[i].value); 37 | buffer_append_string(output, "\r\n"); 38 | } 39 | } 40 | 41 | buffer_append_string(output, "\r\n"); 42 | buffer_append_string(output, httpResponse->body); 43 | } -------------------------------------------------------------------------------- /lib/http_response.h: -------------------------------------------------------------------------------- 1 | #include "buffer.h" 2 | 3 | #ifndef HTTP_RESPONSE_H 4 | #define HTTP_RESPONSE_H 5 | 6 | struct response_header { 7 | char *key; 8 | char *value; 9 | }; 10 | 11 | enum HttpStatusCode { 12 | Unknown, 13 | OK = 200, 14 | MovedPermanently = 301, 15 | BadRequest = 400, 16 | NotFound = 404, 17 | }; 18 | 19 | struct http_response { 20 | enum HttpStatusCode statusCode; 21 | char *statusMessage; 22 | char *contentType; 23 | char *body; 24 | struct response_header *response_headers; 25 | int response_headers_number; 26 | int keep_connected; 27 | }; 28 | 29 | struct http_response *http_response_new(); 30 | 31 | void http_response_encode_buffer(struct http_response *httpResponse, struct buffer *buffer); 32 | 33 | #endif -------------------------------------------------------------------------------- /lib/http_server.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "http_server.h" 3 | 4 | 5 | //连接建立之后的callback 6 | int http_onConnectionCompleted(struct tcp_connection *tcpConnection) { 7 | yolanda_msgx("connection completed"); 8 | struct http_request *httpRequest = http_request_new(); 9 | tcpConnection->request = httpRequest; 10 | return 0; 11 | } 12 | 13 | int process_status_line(char *start, char *end, struct http_request *httpRequest) { 14 | int size = end - start; 15 | //method 16 | char *space = memmem(start, end - start, " ", 1); 17 | assert(space != NULL); 18 | int method_size = space - start; 19 | httpRequest->method = malloc(method_size + 1); 20 | strncpy(httpRequest->method, start, space - start); 21 | httpRequest->method[method_size + 1] = '\0'; 22 | 23 | //url 24 | start = space + 1; 25 | space = memmem(start, end - start, " ", 1); 26 | assert(space != NULL); 27 | int url_size = space - start; 28 | httpRequest->url = malloc(url_size + 1); 29 | strncpy(httpRequest->url, start, space - start); 30 | httpRequest->url[url_size + 1] = '\0'; 31 | 32 | //version 33 | start = space + 1; 34 | httpRequest->version = malloc(end - start + 1); 35 | strncpy(httpRequest->version, start, end - start); 36 | httpRequest->version[end - start + 1] = '\0'; 37 | assert(space != NULL); 38 | return size; 39 | } 40 | 41 | int parse_http_request(struct buffer *input, struct http_request *httpRequest) { 42 | int ok = 1; 43 | while (httpRequest->current_state != REQUEST_DONE) { 44 | if (httpRequest->current_state == REQUEST_STATUS) { 45 | char *crlf = buffer_find_CRLF(input); 46 | if (crlf) { 47 | int request_line_size = process_status_line(input->data + input->readIndex, crlf, httpRequest); 48 | if (request_line_size) { 49 | input->readIndex += request_line_size; // request line size 50 | input->readIndex += 2; //CRLF size 51 | httpRequest->current_state = REQUEST_HEADERS; 52 | } 53 | } 54 | } else if (httpRequest->current_state == REQUEST_HEADERS) { 55 | char *crlf = buffer_find_CRLF(input); 56 | if (crlf) { 57 | /** 58 | * -------:------- 59 | */ 60 | char *start = input->data + input->readIndex; 61 | int request_line_size = crlf - start; 62 | char *colon = memmem(start, request_line_size, ": ", 2); 63 | if (colon != NULL) { 64 | char *key = malloc(colon - start + 1); 65 | strncpy(key, start, colon - start); 66 | key[colon - start] = '\0'; 67 | char *value = malloc(crlf - colon - 2 + 1); 68 | strncpy(value, colon + 2, crlf - colon - 2); 69 | value[crlf - colon - 2] = '\0'; 70 | 71 | http_request_add_header(httpRequest, key, value); 72 | 73 | input->readIndex += request_line_size; //request line size 74 | input->readIndex += 2; //CRLF size 75 | } else { 76 | //读到这里说明:没找到,就说明这个是最后一行 77 | input->readIndex += 2; //CRLF size 78 | httpRequest->current_state = REQUEST_DONE; 79 | } 80 | } 81 | } 82 | } 83 | return ok; 84 | } 85 | 86 | 87 | // buffer是框架构建好的,并且已经收到部分数据的情况下 88 | // 注意这里可能没有收到全部数据,所以要处理数据不够的情形 89 | int http_onMessage(struct buffer *input, struct tcp_connection *tcpConnection) { 90 | yolanda_msgx("get message from tcp connection %s", tcpConnection->name); 91 | 92 | struct http_request *httpRequest = (struct http_request *) tcpConnection->request; 93 | struct http_server *httpServer = (struct http_server *) tcpConnection->data; 94 | 95 | if (parse_http_request(input, httpRequest) == 0) { 96 | char *error_response = "HTTP/1.1 400 Bad Request\r\n\r\n"; 97 | tcp_connection_send_data(tcpConnection, error_response, sizeof(error_response)); 98 | tcp_connection_shutdown(tcpConnection); 99 | } 100 | 101 | //处理完了所有的request数据,接下来进行编码和发送 102 | if (http_request_current_state(httpRequest) == REQUEST_DONE) { 103 | struct http_response *httpResponse = http_response_new(); 104 | 105 | //httpServer暴露的requestCallback回调 106 | if (httpServer->requestCallback != NULL) { 107 | httpServer->requestCallback(httpRequest, httpResponse); 108 | } 109 | struct buffer *buffer = buffer_new(); 110 | http_response_encode_buffer(httpResponse, buffer); 111 | tcp_connection_send_buffer(tcpConnection, buffer); 112 | 113 | if (http_request_close_connection(httpRequest)) { 114 | tcp_connection_shutdown(tcpConnection); 115 | } 116 | http_request_reset(httpRequest); 117 | } 118 | } 119 | 120 | //数据通过buffer写完之后的callback 121 | int http_onWriteCompleted(struct tcp_connection *tcpConnection) { 122 | yolanda_msgx("write completed"); 123 | return 0; 124 | } 125 | 126 | //连接关闭之后的callback 127 | int http_onConnectionClosed(struct tcp_connection *tcpConnection) { 128 | yolanda_msgx("connection closed"); 129 | if (tcpConnection->request != NULL) { 130 | http_request_clear(tcpConnection->request); 131 | tcpConnection->request = NULL; 132 | } 133 | return 0; 134 | } 135 | 136 | 137 | struct http_server *http_server_new(struct event_loop *eventLoop, int port, 138 | request_callback requestCallback, 139 | int threadNum) { 140 | struct http_server *httpServer = malloc(sizeof(struct http_server)); 141 | httpServer->requestCallback = requestCallback; 142 | //初始化acceptor 143 | struct acceptor *acceptor = acceptor_init(SERV_PORT); 144 | 145 | httpServer->tcpServer = tcp_server_init(eventLoop, acceptor, http_onConnectionCompleted, http_onMessage, 146 | http_onWriteCompleted, 147 | http_onConnectionClosed, threadNum); 148 | 149 | // for callback 150 | httpServer->tcpServer->data = httpServer; 151 | 152 | return httpServer; 153 | } 154 | 155 | 156 | void http_server_start(struct http_server *httpServer) { 157 | tcp_server_start(httpServer->tcpServer); 158 | } 159 | -------------------------------------------------------------------------------- /lib/http_server.h: -------------------------------------------------------------------------------- 1 | #ifndef HTTP_SERVER_H 2 | #define HTTP_SERVER_H 3 | 4 | #include "common.h" 5 | #include "tcp_server.h" 6 | #include "http_request.h" 7 | #include "http_response.h" 8 | 9 | typedef int (*request_callback)(struct http_request *httpRequest, struct http_response *httpResponse); 10 | 11 | struct http_server { 12 | struct TCPserver *tcpServer; 13 | request_callback requestCallback; 14 | }; 15 | 16 | struct http_server *http_server_new(struct event_loop *eventLoop, int port, 17 | request_callback requestCallback, 18 | int threadNum); 19 | 20 | 21 | void http_server_start(struct http_server *httpServer); 22 | 23 | int parse_http_request(struct buffer *input, struct http_request *httpRequest); 24 | 25 | #endif -------------------------------------------------------------------------------- /lib/inetaddress.h: -------------------------------------------------------------------------------- 1 | #ifndef INET_ADDRESS_H 2 | #define INET_ADDRESS_H 3 | 4 | struct inet_address{ 5 | int port; 6 | }; 7 | 8 | struct inet_address * init_inet_address(int port); 9 | 10 | #endif -------------------------------------------------------------------------------- /lib/log.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by shengym on 2019-07-07. 3 | // 4 | 5 | #include "common.h" 6 | #include /* ANSI C header file */ 7 | #include /* for syslog() */ 8 | 9 | 10 | # define MAXLINE 4096 11 | 12 | 13 | /* error - print a diagnostic and optionally exit */ 14 | void error(int status, int err, char *fmt, ...) { 15 | va_list ap; 16 | 17 | va_start(ap, fmt); 18 | vfprintf(stderr, fmt, ap); 19 | va_end(ap); 20 | if (err) 21 | fprintf(stderr, ": %s (%d)\n", strerror(err), err); 22 | if (status) 23 | exit(status); 24 | } 25 | 26 | 27 | static void 28 | err_doit(int errnoflag, int level, const char *fmt, va_list ap) { 29 | int errno_save, n; 30 | char buf[MAXLINE + 1]; 31 | 32 | errno_save = errno; /* value caller might want printed */ 33 | 34 | vsnprintf(buf, MAXLINE, fmt, ap); /* safe */ 35 | 36 | n = strlen(buf); 37 | if (errnoflag) 38 | snprintf(buf + n, MAXLINE - n, ": %s", strerror(errno_save)); 39 | strcat(buf, "\n"); 40 | 41 | 42 | fflush(stdout); /* in case stdout and stderr are the same */ 43 | fputs(buf, stderr); 44 | fflush(stderr); 45 | 46 | return; 47 | } 48 | 49 | //void 50 | //err_quit(const char *fmt, ...) { 51 | // va_list ap; 52 | // 53 | // va_start(ap, fmt); 54 | // err_doit(0, LOG_ERR, fmt, ap); 55 | // va_end(ap); 56 | // exit(1); 57 | //} 58 | 59 | void yolanda_log(int severity, const char *msg) { 60 | const char *severity_str; 61 | switch (severity) { 62 | case LOG_DEBUG_TYPE: 63 | severity_str = "debug"; 64 | break; 65 | case LOG_MSG_TYPE: 66 | severity_str = "msg"; 67 | break; 68 | case LOG_WARN_TYPE: 69 | severity_str = "warn"; 70 | break; 71 | case LOG_ERR_TYPE: 72 | severity_str = "err"; 73 | break; 74 | default: 75 | severity_str = "???"; 76 | break; 77 | } 78 | (void) fprintf(stdout, "[%s] %s\n", severity_str, msg); 79 | 80 | } 81 | 82 | void yolanda_logx(int severity, const char *errstr, const char *fmt, va_list ap) 83 | { 84 | char buf[1024]; 85 | size_t len; 86 | 87 | if (fmt != NULL) 88 | vsnprintf(buf, sizeof(buf), fmt, ap); 89 | else 90 | buf[0] = '\0'; 91 | 92 | if (errstr) { 93 | len = strlen(buf); 94 | if (len < sizeof(buf) - 3) { 95 | snprintf(buf + len, sizeof(buf) - len, ": %s", errstr); 96 | } 97 | } 98 | 99 | yolanda_log(severity, buf); 100 | } 101 | 102 | void yolanda_msgx(const char *fmt, ...) 103 | { 104 | va_list ap; 105 | 106 | va_start(ap, fmt); 107 | yolanda_logx(LOG_MSG_TYPE, NULL, fmt, ap); 108 | va_end(ap); 109 | } 110 | 111 | void yolanda_debugx(const char *fmt, ...) 112 | { 113 | va_list ap; 114 | 115 | va_start(ap, fmt); 116 | yolanda_logx(LOG_DEBUG_TYPE, NULL, fmt, ap); 117 | va_end(ap); 118 | } -------------------------------------------------------------------------------- /lib/log.h: -------------------------------------------------------------------------------- 1 | #ifndef LOG_H 2 | #define LOG_H 3 | 4 | #include "stdarg.h" 5 | 6 | #define LOG_DEBUG_TYPE 0 7 | #define LOG_MSG_TYPE 1 8 | #define LOG_WARN_TYPE 2 9 | #define LOG_ERR_TYPE 3 10 | 11 | void yolanda_log(int severity, const char *msg); 12 | void yolanda_logx(int severity, const char *errstr, const char *fmt, va_list ap); 13 | void yolanda_msgx(const char *fmt, ...); 14 | void yolanda_debugx(const char *fmt, ...); 15 | 16 | 17 | #define LOG_MSG(msg) yolanda_log(LOG_MSG_TYPE, msg) 18 | #define LOG_ERR(msg) yolanda_log(LOG_ERR_TYPE, msg) 19 | 20 | #endif -------------------------------------------------------------------------------- /lib/poll_dispatcher.c: -------------------------------------------------------------------------------- 1 | #include "event_dispatcher.h" 2 | #include "event_loop.h" 3 | #include "log.h" 4 | 5 | #define INIT_POLL_SIZE 1024 6 | 7 | struct pollidx { 8 | int idxplus1; 9 | }; 10 | 11 | struct poll_dispatcher_data { 12 | int event_count; 13 | int nfds; 14 | int realloc_copy; 15 | struct pollfd *event_set; 16 | struct pollfd *event_set_copy; 17 | }; 18 | 19 | static void *poll_init(struct event_loop *); 20 | 21 | static int poll_add(struct event_loop *, struct channel *channel1); 22 | 23 | static int poll_del(struct event_loop *, struct channel *channel1); 24 | 25 | static int poll_update(struct event_loop *, struct channel *channel1); 26 | 27 | static int poll_dispatch(struct event_loop *, struct timeval *); 28 | 29 | static void poll_clear(struct event_loop *); 30 | 31 | const struct event_dispatcher poll_dispatcher = { 32 | "poll", 33 | poll_init, 34 | poll_add, 35 | poll_del, 36 | poll_update, 37 | poll_dispatch, 38 | poll_clear, 39 | }; 40 | 41 | void *poll_init(struct event_loop *eventLoop) { 42 | struct poll_dispatcher_data *pollDispatcherData = malloc(sizeof(struct poll_dispatcher_data)); 43 | 44 | //初始化pollfd数组,这个数组的第一个元素是listen_fd,其余的用来记录将要连接的connect_fd 45 | pollDispatcherData->event_set = malloc(sizeof(struct pollfd) * INIT_POLL_SIZE); 46 | // 用-1表示这个数组位置还没有被占用 47 | int i; 48 | for (i = 0; i < INIT_POLL_SIZE; i++) 49 | pollDispatcherData->event_set[i].fd = -1; 50 | pollDispatcherData->event_count = 0; 51 | pollDispatcherData->nfds = 0; 52 | pollDispatcherData->realloc_copy = 0; 53 | 54 | return pollDispatcherData; 55 | } 56 | 57 | 58 | int poll_add(struct event_loop *eventLoop, struct channel *channel1) { 59 | 60 | struct poll_dispatcher_data *pollDispatcherData = (struct poll_dispatcher_data *) eventLoop->event_dispatcher_data; 61 | 62 | int fd = channel1->fd; 63 | 64 | int events = 0; 65 | if (channel1->events & EVENT_READ) { 66 | events = events | POLLRDNORM; 67 | } 68 | 69 | if (channel1->events & EVENT_WRITE) { 70 | events = events | POLLWRNORM; 71 | } 72 | 73 | //找到一个可以记录该连接套接字的位置 74 | int i = 0; 75 | for (i = 0; i < INIT_POLL_SIZE; i++) { 76 | if (pollDispatcherData->event_set[i].fd < 0) { 77 | pollDispatcherData->event_set[i].fd = fd; 78 | pollDispatcherData->event_set[i].events = events; 79 | break; 80 | } 81 | } 82 | 83 | yolanda_msgx("poll added channel fd==%d, %s", fd, eventLoop->thread_name); 84 | if (i >= INIT_POLL_SIZE) { 85 | LOG_ERR("too many clients, just abort it"); 86 | } 87 | 88 | return 0; 89 | } 90 | 91 | int poll_del(struct event_loop *eventLoop, struct channel *channel1) { 92 | struct poll_dispatcher_data *pollDispatcherData = (struct poll_dispatcher_data *) eventLoop->event_dispatcher_data; 93 | int fd = channel1->fd; 94 | 95 | //找到fd对应的记录 96 | int i = 0; 97 | for (i = 0; i < INIT_POLL_SIZE; i++) { 98 | if (pollDispatcherData->event_set[i].fd == fd) { 99 | pollDispatcherData->event_set[i].fd = -1; 100 | break; 101 | } 102 | } 103 | 104 | yolanda_msgx("poll delete channel fd==%d, %s", fd, eventLoop->thread_name); 105 | if (i >= INIT_POLL_SIZE) { 106 | LOG_ERR("can not find fd, poll delete error"); 107 | } 108 | 109 | return 0; 110 | } 111 | 112 | int poll_update(struct event_loop *eventLoop, struct channel *channel1) { 113 | struct poll_dispatcher_data *pollDispatcherData = (struct poll_dispatcher_data *) eventLoop->event_dispatcher_data; 114 | 115 | int fd = channel1->fd; 116 | 117 | int events = 0; 118 | if (channel1->events & EVENT_READ) { 119 | events = events | POLLRDNORM; 120 | } 121 | 122 | if (channel1->events & EVENT_WRITE) { 123 | events = events | POLLWRNORM; 124 | } 125 | 126 | //找到fd对应的记录 127 | int i = 0; 128 | for (i = 0; i < INIT_POLL_SIZE; i++) { 129 | if (pollDispatcherData->event_set[i].fd == fd) { 130 | pollDispatcherData->event_set[i].events = events; 131 | break; 132 | } 133 | } 134 | 135 | yolanda_msgx("poll updated channel fd==%d, %s", fd, eventLoop->thread_name); 136 | if (i >= INIT_POLL_SIZE) { 137 | LOG_ERR("can not find fd, poll updated error"); 138 | } 139 | 140 | return 0; 141 | } 142 | 143 | int poll_dispatch(struct event_loop *eventLoop, struct timeval *timeval) { 144 | struct poll_dispatcher_data *pollDispatcherData = 145 | (struct poll_dispatcher_data *) eventLoop->event_dispatcher_data; 146 | 147 | 148 | int ready_number = 0; 149 | int timewait = timeval->tv_sec * 1000; 150 | if ((ready_number = poll(pollDispatcherData->event_set, INIT_POLL_SIZE, timewait)) < 0) { 151 | error(1, errno, "poll failed "); 152 | } 153 | 154 | if (ready_number <= 0) { 155 | return 0; 156 | } 157 | 158 | int i; 159 | for (i = 0; i <= INIT_POLL_SIZE; i++) { 160 | int socket_fd; 161 | struct pollfd pollfd = pollDispatcherData->event_set[i]; 162 | if ((socket_fd = pollfd.fd) < 0) 163 | continue; 164 | 165 | //有事件发生 166 | if (pollfd.revents > 0) { 167 | yolanda_msgx("get message channel i==%d, fd==%d, %s", i, socket_fd, eventLoop->thread_name); 168 | 169 | if (pollfd.revents & POLLRDNORM) { 170 | channel_event_activate(eventLoop, socket_fd, EVENT_READ); 171 | } 172 | 173 | if (pollfd.revents & POLLWRNORM) { 174 | channel_event_activate(eventLoop, socket_fd, EVENT_WRITE); 175 | } 176 | 177 | if (--ready_number <= 0) 178 | break; 179 | } 180 | 181 | // if (pollfd.revents & (POLLRDNORM | POLLERR)) { 182 | // if ((n = read(socket_fd, buf, MAXLINE)) < 0) { 183 | // if (errno == ECONNRESET) { 184 | // close(socket_fd); 185 | // pollfd.fd = -1; 186 | // } else 187 | // error(1, errno, "read error"); 188 | // } else if (n == 0) { 189 | // close(socket_fd); 190 | // pollfd.fd = -1; 191 | // } else { 192 | // if (write(socket_fd, buf, n) < 0) { 193 | // error(1, errno, "write error"); 194 | // } 195 | // } 196 | 197 | } 198 | 199 | return 0; 200 | } 201 | 202 | void poll_clear(struct event_loop *eventLoop) { 203 | struct poll_dispatcher_data *pollDispatcherData = 204 | (struct poll_dispatcher_data *) eventLoop->event_dispatcher_data; 205 | 206 | free(pollDispatcherData->event_set); 207 | pollDispatcherData->event_set = NULL; 208 | free(pollDispatcherData); 209 | eventLoop->event_dispatcher_data = NULL; 210 | 211 | return; 212 | } 213 | -------------------------------------------------------------------------------- /lib/read.c: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | 3 | size_t readn(int fd, void *buffer, size_t size) { 4 | char *buffer_pointer = buffer; 5 | int length = size; 6 | 7 | while (length > 0) { 8 | int result = read(fd, buffer_pointer, length); 9 | 10 | if (result < 0) { 11 | if (errno == EINTR) 12 | continue; /* 考虑非阻塞的情况,这里需要再次调用read */ 13 | else 14 | return (-1); 15 | } else if (result == 0) 16 | break; /* EOF(End of File)表示套接字关闭 */ 17 | 18 | length -= result; 19 | buffer_pointer += result; 20 | } 21 | return (size - length); /* 返回的是实际读取的字节数*/ 22 | } 23 | 24 | 25 | size_t readline_2(int fd, char *buffer, size_t length) { 26 | char *buf_first = buffer; 27 | 28 | char c; 29 | while (length > 0 && recv(fd, &c, 1, 0) == 1) { 30 | *buffer++ = c; 31 | length--; 32 | if (c == '\n') { 33 | *buffer = '\0'; 34 | return buffer - buf_first; 35 | } 36 | } 37 | 38 | return -1; 39 | 40 | } 41 | 42 | /* readline - read a newline terminated record */ 43 | /* 123456789\n */ 44 | size_t readline(int fd, char *buffer, size_t length) { 45 | char *buf_first = buffer; 46 | static char *buffer_pointer; 47 | int nleft = 0; 48 | static char read_buffer[512]; 49 | char c; 50 | 51 | while (--length > 0) { 52 | // nread == 0 53 | if (nleft <= 0) { 54 | int nread = recv(fd, read_buffer, sizeof(read_buffer), 0); 55 | if (nread < 0) { 56 | if (errno == EINTR) { 57 | length++; 58 | continue; 59 | } 60 | return -1; 61 | } 62 | if (nread == 0) 63 | return 0; 64 | buffer_pointer = read_buffer; 65 | nleft = nread; 66 | } 67 | c = *buffer_pointer++; 68 | *buffer++ = c; 69 | nleft--; 70 | if (c == '\n') { 71 | *buffer = '\0'; 72 | return buffer - buf_first; 73 | } 74 | } 75 | return -1; 76 | } 77 | 78 | size_t read_message(int fd, char *buffer, size_t length) { 79 | u_int32_t msg_length; 80 | u_int32_t msg_type; 81 | int rc; 82 | 83 | /* Retrieve the length of the record */ 84 | 85 | rc = readn(fd, (char *) &msg_length, sizeof(u_int32_t)); 86 | if (rc != sizeof(u_int32_t)) 87 | return rc < 0 ? -1 : 0; 88 | msg_length = ntohl(msg_length); 89 | 90 | rc = readn(fd, (char *) &msg_type, sizeof(msg_type)); 91 | if (rc != sizeof(u_int32_t)) 92 | return rc < 0 ? -1 : 0; 93 | 94 | /* 判断buffer是否可以容纳下数据 */ 95 | if (msg_length > length) { 96 | return -1; 97 | } 98 | 99 | /* Retrieve the record itself */ 100 | rc = readn(fd, buffer, msg_length); 101 | if (rc != msg_length) 102 | return rc < 0 ? -1 : 0; 103 | return rc; 104 | } 105 | 106 | 107 | int read_line(int fd, char *buf, int size) { 108 | int i = 0; 109 | char c = '\0'; 110 | int n; 111 | 112 | while ((i < size - 1) && (c != '\n')) { 113 | n = recv(fd, &c, 1, 0); 114 | if (n > 0) { 115 | if (c == '\r') { 116 | n = recv(fd, &c, 1, MSG_PEEK); 117 | if ((n > 0) && (c == '\n')) 118 | recv(fd, &c, 1, 0); 119 | else 120 | c = '\n'; 121 | } 122 | buf[i] = c; 123 | i++; 124 | } else 125 | c = '\n'; 126 | } 127 | buf[i] = '\0'; 128 | 129 | return (i); 130 | } 131 | -------------------------------------------------------------------------------- /lib/sock_ntop.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by shengym on 2019-07-07. 3 | // 4 | 5 | #include "common.h" 6 | 7 | char * 8 | sock_ntop(const struct sockaddr_in *sin, socklen_t salen) { 9 | char portstr[8]; 10 | static char str[128]; /* Unix domain is largest */ 11 | 12 | 13 | if (inet_ntop(AF_INET, &sin->sin_addr, str, sizeof(str)) == NULL) 14 | return (NULL); 15 | if (ntohs(sin->sin_port) != 0) { 16 | snprintf(portstr, sizeof(portstr), ":%d", ntohs(sin->sin_port)); 17 | strcat(str, portstr); 18 | } 19 | return (str); 20 | } -------------------------------------------------------------------------------- /lib/tcp_client.c: -------------------------------------------------------------------------------- 1 | # include "common.h" 2 | 3 | int tcp_client(char *address, int port) { 4 | int socket_fd; 5 | socket_fd = socket(AF_INET, SOCK_STREAM, 0); 6 | 7 | struct sockaddr_in server_addr; 8 | bzero(&server_addr, sizeof(server_addr)); 9 | server_addr.sin_family = AF_INET; 10 | server_addr.sin_port = htons(port); 11 | inet_pton(AF_INET, address, &server_addr.sin_addr); 12 | 13 | socklen_t server_len = sizeof(server_addr); 14 | int connect_rt = connect(socket_fd, (struct sockaddr *) &server_addr, server_len); 15 | if (connect_rt < 0) { 16 | error(1, errno, "connect failed "); 17 | } 18 | 19 | return socket_fd; 20 | } -------------------------------------------------------------------------------- /lib/tcp_connection.c: -------------------------------------------------------------------------------- 1 | #include "tcp_connection.h" 2 | #include "utils.h" 3 | 4 | 5 | int handle_connection_closed(struct tcp_connection *tcpConnection) { 6 | struct event_loop *eventLoop = tcpConnection->eventLoop; 7 | struct channel *channel = tcpConnection->channel; 8 | event_loop_remove_channel_event(eventLoop, channel->fd, channel); 9 | if (tcpConnection->connectionClosedCallBack != NULL) { 10 | tcpConnection->connectionClosedCallBack(tcpConnection); 11 | } 12 | } 13 | 14 | int handle_read(void *data) { 15 | struct tcp_connection *tcpConnection = (struct tcp_connection *) data; 16 | struct buffer *input_buffer = tcpConnection->input_buffer; 17 | struct channel *channel = tcpConnection->channel; 18 | 19 | if (buffer_socket_read(input_buffer, channel->fd) > 0) { 20 | //应用程序真正读取Buffer里的数据 21 | if (tcpConnection->messageCallBack != NULL) { 22 | tcpConnection->messageCallBack(input_buffer, tcpConnection); 23 | } 24 | } else { 25 | handle_connection_closed(tcpConnection); 26 | } 27 | } 28 | 29 | //发送缓冲区可以往外写 30 | //把channel对应的output_buffer不断往外发送 31 | int handle_write(void *data) { 32 | struct tcp_connection *tcpConnection = (struct tcp_connection *) data; 33 | struct event_loop *eventLoop = tcpConnection->eventLoop; 34 | assertInSameThread(eventLoop); 35 | 36 | struct buffer *output_buffer = tcpConnection->output_buffer; 37 | struct channel *channel = tcpConnection->channel; 38 | 39 | ssize_t nwrited = write(channel->fd, output_buffer->data + output_buffer->readIndex, 40 | buffer_readable_size(output_buffer)); 41 | if (nwrited > 0) { 42 | //已读nwrited字节 43 | output_buffer->readIndex += nwrited; 44 | //如果数据完全发送出去,就不需要继续了 45 | if (buffer_readable_size(output_buffer) == 0) { 46 | channel_write_event_disable(channel); 47 | } 48 | //回调writeCompletedCallBack 49 | if (tcpConnection->writeCompletedCallBack != NULL) { 50 | tcpConnection->writeCompletedCallBack(tcpConnection); 51 | } 52 | } else { 53 | yolanda_msgx("handle_write for tcp connection %s", tcpConnection->name); 54 | } 55 | 56 | } 57 | 58 | struct tcp_connection * 59 | tcp_connection_new(int connected_fd, struct event_loop *eventLoop, 60 | connection_completed_call_back connectionCompletedCallBack, 61 | connection_closed_call_back connectionClosedCallBack, 62 | message_call_back messageCallBack, write_completed_call_back writeCompletedCallBack) { 63 | struct tcp_connection *tcpConnection = malloc(sizeof(struct tcp_connection)); 64 | tcpConnection->writeCompletedCallBack = writeCompletedCallBack; 65 | tcpConnection->messageCallBack = messageCallBack; 66 | tcpConnection->connectionCompletedCallBack = connectionCompletedCallBack; 67 | tcpConnection->connectionClosedCallBack = connectionClosedCallBack; 68 | tcpConnection->eventLoop = eventLoop; 69 | tcpConnection->input_buffer = buffer_new(); 70 | tcpConnection->output_buffer = buffer_new(); 71 | 72 | 73 | char *buf = malloc(16); 74 | sprintf(buf, "connection-%d\0", connected_fd); 75 | tcpConnection->name = buf; 76 | 77 | // add event read for the new connection 78 | struct channel *channel1 = channel_new(connected_fd, EVENT_READ, handle_read, handle_write, tcpConnection); 79 | tcpConnection->channel = channel1; 80 | 81 | //connectionCompletedCallBack callback 82 | if (tcpConnection->connectionCompletedCallBack != NULL) { 83 | tcpConnection->connectionCompletedCallBack(tcpConnection); 84 | } 85 | 86 | event_loop_add_channel_event(tcpConnection->eventLoop, connected_fd, tcpConnection->channel); 87 | return tcpConnection; 88 | } 89 | 90 | //应用层调用入口 91 | int tcp_connection_send_data(struct tcp_connection *tcpConnection, void *data, int size) { 92 | size_t nwrited = 0; 93 | size_t nleft = size; 94 | int fault = 0; 95 | 96 | struct channel *channel = tcpConnection->channel; 97 | struct buffer *output_buffer = tcpConnection->output_buffer; 98 | 99 | //先往套接字尝试发送数据 100 | if (!channel_write_event_is_enabled(channel) && buffer_readable_size(output_buffer) == 0) { 101 | nwrited = write(channel->fd, data, size); 102 | if (nwrited >= 0) { 103 | nleft = nleft - nwrited; 104 | } else { 105 | nwrited = 0; 106 | if (errno != EWOULDBLOCK) { 107 | if (errno == EPIPE || errno == ECONNRESET) { 108 | fault = 1; 109 | } 110 | } 111 | } 112 | } 113 | 114 | if (!fault && nleft > 0) { 115 | //拷贝到Buffer中,Buffer的数据由框架接管 116 | buffer_append(output_buffer, data + nwrited, nleft); 117 | if (!channel_write_event_is_enabled(channel)) { 118 | channel_write_event_enable(channel); 119 | } 120 | } 121 | 122 | return nwrited; 123 | } 124 | 125 | int tcp_connection_send_buffer(struct tcp_connection *tcpConnection, struct buffer *buffer) { 126 | int size = buffer_readable_size(buffer); 127 | int result = tcp_connection_send_data(tcpConnection, buffer->data + buffer->readIndex, size); 128 | buffer->readIndex += size; 129 | return result; 130 | } 131 | 132 | void tcp_connection_shutdown(struct tcp_connection *tcpConnection) { 133 | if (shutdown(tcpConnection->channel->fd, SHUT_WR) < 0) { 134 | yolanda_msgx("tcp_connection_shutdown failed, socket == %d", tcpConnection->channel->fd); 135 | } 136 | } -------------------------------------------------------------------------------- /lib/tcp_connection.h: -------------------------------------------------------------------------------- 1 | #ifndef TCP_CONNECTION 2 | #define TCP_CONNECTION 3 | 4 | #include "event_loop.h" 5 | #include "channel.h" 6 | #include "buffer.h" 7 | #include "tcp_server.h" 8 | 9 | struct tcp_connection { 10 | struct event_loop *eventLoop; 11 | struct channel *channel; 12 | char *name; 13 | struct buffer *input_buffer; //接收缓冲区 14 | struct buffer *output_buffer; //发送缓冲区 15 | 16 | connection_completed_call_back connectionCompletedCallBack; 17 | message_call_back messageCallBack; 18 | write_completed_call_back writeCompletedCallBack; 19 | connection_closed_call_back connectionClosedCallBack; 20 | 21 | void * data; //for callback use: http_server 22 | void * request; // for callback use 23 | void * response; // for callback use 24 | }; 25 | 26 | struct tcp_connection * 27 | tcp_connection_new(int fd, struct event_loop *eventLoop, connection_completed_call_back connectionCompletedCallBack, 28 | connection_closed_call_back connectionClosedCallBack, 29 | message_call_back messageCallBack, write_completed_call_back writeCompletedCallBack); 30 | 31 | //应用层调用入口 32 | int tcp_connection_send_data(struct tcp_connection *tcpConnection, void *data, int size); 33 | 34 | //应用层调用入口 35 | int tcp_connection_send_buffer(struct tcp_connection *tcpConnection, struct buffer * buffer); 36 | 37 | void tcp_connection_shutdown(struct tcp_connection * tcpConnection); 38 | //int tcp_connection_append_buffer(struct tcp_connection *tcpConnection); 39 | #endif -------------------------------------------------------------------------------- /lib/tcp_server.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "common.h" 3 | #include "tcp_server.h" 4 | #include "thread_pool.h" 5 | #include "utils.h" 6 | #include "tcp_connection.h" 7 | 8 | int tcp_server(int port) { 9 | int listenfd; 10 | listenfd = socket(AF_INET, SOCK_STREAM, 0); 11 | 12 | struct sockaddr_in server_addr; 13 | bzero(&server_addr, sizeof(server_addr)); 14 | server_addr.sin_family = AF_INET; 15 | server_addr.sin_addr.s_addr = htonl(INADDR_ANY); 16 | server_addr.sin_port = htons(port); 17 | 18 | int on = 1; 19 | setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); 20 | 21 | int rt1 = bind(listenfd, (struct sockaddr *) &server_addr, sizeof(server_addr)); 22 | if (rt1 < 0) { 23 | error(1, errno, "bind failed "); 24 | } 25 | 26 | int rt2 = listen(listenfd, LISTENQ); 27 | if (rt2 < 0) { 28 | error(1, errno, "listen failed "); 29 | } 30 | 31 | signal(SIGPIPE, SIG_IGN); 32 | 33 | int connfd; 34 | struct sockaddr_in client_addr; 35 | socklen_t client_len = sizeof(client_addr); 36 | 37 | if ((connfd = accept(listenfd, (struct sockaddr *) &client_addr, &client_len)) < 0) { 38 | error(1, errno, "bind failed "); 39 | } 40 | 41 | return connfd; 42 | } 43 | 44 | 45 | int tcp_server_listen(int port) { 46 | int listenfd; 47 | listenfd = socket(AF_INET, SOCK_STREAM, 0); 48 | 49 | struct sockaddr_in server_addr; 50 | bzero(&server_addr, sizeof(server_addr)); 51 | server_addr.sin_family = AF_INET; 52 | server_addr.sin_addr.s_addr = htonl(INADDR_ANY); 53 | server_addr.sin_port = htons(port); 54 | 55 | int on = 1; 56 | setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); 57 | 58 | int rt1 = bind(listenfd, (struct sockaddr *) &server_addr, sizeof(server_addr)); 59 | if (rt1 < 0) { 60 | error(1, errno, "bind failed "); 61 | } 62 | 63 | int rt2 = listen(listenfd, LISTENQ); 64 | if (rt2 < 0) { 65 | error(1, errno, "listen failed "); 66 | } 67 | 68 | signal(SIGPIPE, SIG_IGN); 69 | 70 | return listenfd; 71 | } 72 | 73 | 74 | int tcp_nonblocking_server_listen(int port) { 75 | int listenfd; 76 | listenfd = socket(AF_INET, SOCK_STREAM, 0); 77 | 78 | make_nonblocking(listenfd); 79 | 80 | struct sockaddr_in server_addr; 81 | bzero(&server_addr, sizeof(server_addr)); 82 | server_addr.sin_family = AF_INET; 83 | server_addr.sin_addr.s_addr = htonl(INADDR_ANY); 84 | server_addr.sin_port = htons(port); 85 | 86 | int on = 1; 87 | setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); 88 | 89 | int rt1 = bind(listenfd, (struct sockaddr *) &server_addr, sizeof(server_addr)); 90 | if (rt1 < 0) { 91 | error(1, errno, "bind failed "); 92 | } 93 | 94 | int rt2 = listen(listenfd, LISTENQ); 95 | if (rt2 < 0) { 96 | error(1, errno, "listen failed "); 97 | } 98 | 99 | signal(SIGPIPE, SIG_IGN); 100 | 101 | return listenfd; 102 | } 103 | 104 | void make_nonblocking(int fd) { 105 | fcntl(fd, F_SETFL, O_NONBLOCK); 106 | } 107 | 108 | 109 | struct TCPserver * 110 | tcp_server_init(struct event_loop *eventLoop, struct acceptor *acceptor, 111 | connection_completed_call_back connectionCompletedCallBack, 112 | message_call_back messageCallBack, 113 | write_completed_call_back writeCompletedCallBack, 114 | connection_closed_call_back connectionClosedCallBack, 115 | int threadNum) { 116 | struct TCPserver *tcpServer = malloc(sizeof(struct TCPserver)); 117 | tcpServer->eventLoop = eventLoop; 118 | tcpServer->acceptor = acceptor; 119 | tcpServer->connectionCompletedCallBack = connectionCompletedCallBack; 120 | tcpServer->messageCallBack = messageCallBack; 121 | tcpServer->writeCompletedCallBack = writeCompletedCallBack; 122 | tcpServer->connectionClosedCallBack = connectionClosedCallBack; 123 | tcpServer->threadNum = threadNum; 124 | tcpServer->threadPool = thread_pool_new(eventLoop, threadNum); 125 | tcpServer->data = NULL; 126 | 127 | return tcpServer; 128 | } 129 | 130 | 131 | int handle_connection_established(void *data) { 132 | struct TCPserver *tcpServer = (struct TCPserver *) data; 133 | struct acceptor *acceptor = tcpServer->acceptor; 134 | int listenfd = acceptor->listen_fd; 135 | 136 | struct sockaddr_in client_addr; 137 | socklen_t client_len = sizeof(client_addr); 138 | int connected_fd = accept(listenfd, (struct sockaddr *) &client_addr, &client_len); 139 | make_nonblocking(connected_fd); 140 | 141 | yolanda_msgx("new connection established, socket == %d", connected_fd); 142 | 143 | // choose event loop from the thread pool 144 | struct event_loop *eventLoop = thread_pool_get_loop(tcpServer->threadPool); 145 | 146 | // create a new tcp connection 147 | struct tcp_connection *tcpConnection = tcp_connection_new(connected_fd, eventLoop, 148 | tcpServer->connectionCompletedCallBack, 149 | tcpServer->connectionClosedCallBack, 150 | tcpServer->messageCallBack, 151 | tcpServer->writeCompletedCallBack); 152 | //for callback use 153 | if (tcpServer->data != NULL) { 154 | tcpConnection->data = tcpServer->data; 155 | } 156 | return 0; 157 | } 158 | 159 | 160 | //开启监听 161 | void tcp_server_start(struct TCPserver *tcpServer) { 162 | struct acceptor *acceptor = tcpServer->acceptor; 163 | struct event_loop *eventLoop = tcpServer->eventLoop; 164 | 165 | //开启多个线程 166 | thread_pool_start(tcpServer->threadPool); 167 | 168 | //acceptor主线程, 同时把tcpServer作为参数传给channel对象 169 | struct channel *channel = channel_new(acceptor->listen_fd, EVENT_READ, handle_connection_established, NULL, 170 | tcpServer); 171 | event_loop_add_channel_event(eventLoop, channel->fd, channel); 172 | return; 173 | } 174 | 175 | //设置callback数据 176 | void tcp_server_set_data(struct TCPserver *tcpServer, void *data) { 177 | if (data != NULL) { 178 | tcpServer->data = data; 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /lib/tcp_server.h: -------------------------------------------------------------------------------- 1 | #ifndef TCP_SERVER_H 2 | #define TCP_SERVER_H 3 | 4 | typedef int (*connection_completed_call_back)(struct tcp_connection *tcpConnection); 5 | 6 | typedef int (*message_call_back)(struct buffer *buffer, struct tcp_connection *tcpConnection); 7 | 8 | typedef int (*write_completed_call_back)(struct tcp_connection *tcpConnection); 9 | 10 | typedef int (*connection_closed_call_back)(struct tcp_connection *tcpConnection); 11 | 12 | #include "acceptor.h" 13 | #include "event_loop.h" 14 | #include "thread_pool.h" 15 | #include "buffer.h" 16 | #include "tcp_connection.h" 17 | 18 | struct TCPserver { 19 | int port; 20 | struct event_loop *eventLoop; 21 | struct acceptor *acceptor; 22 | connection_completed_call_back connectionCompletedCallBack; 23 | message_call_back messageCallBack; 24 | write_completed_call_back writeCompletedCallBack; 25 | connection_closed_call_back connectionClosedCallBack; 26 | int threadNum; 27 | struct thread_pool *threadPool; 28 | void * data; //for callback use: http_server 29 | }; 30 | 31 | 32 | //准备监听套接字 33 | struct TCPserver * 34 | tcp_server_init(struct event_loop *eventLoop, struct acceptor *acceptor, 35 | connection_completed_call_back connectionCallBack, 36 | message_call_back messageCallBack, 37 | write_completed_call_back writeCompletedCallBack, 38 | connection_closed_call_back connectionClosedCallBack, 39 | int threadNum); 40 | 41 | //开启监听 42 | void tcp_server_start(struct TCPserver *tcpServer); 43 | 44 | //设置callback数据 45 | void tcp_server_set_data(struct TCPserver *tcpServer, void * data); 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /lib/thread_pool.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "utils.h" 3 | #include "thread_pool.h" 4 | 5 | struct thread_pool *thread_pool_new(struct event_loop *mainLoop, int threadNumber) { 6 | 7 | struct thread_pool *threadPool = malloc(sizeof(struct thread_pool)); 8 | threadPool->mainLoop = mainLoop; 9 | threadPool->position = 0; 10 | threadPool->thread_number = threadNumber; 11 | threadPool->started = 0; 12 | threadPool->eventLoopThreads = NULL; 13 | return threadPool; 14 | } 15 | 16 | //一定是main thread发起 17 | void thread_pool_start(struct thread_pool *threadPool) { 18 | assert(!threadPool->started); 19 | assertInSameThread(threadPool->mainLoop); 20 | 21 | threadPool->started = 1; 22 | void *tmp; 23 | 24 | if (threadPool->thread_number <= 0) { 25 | return; 26 | } 27 | 28 | threadPool->eventLoopThreads = malloc(threadPool->thread_number * sizeof(struct event_loop_thread)); 29 | for (int i = 0; i < threadPool->thread_number; ++i) { 30 | event_loop_thread_init(&threadPool->eventLoopThreads[i], i); 31 | event_loop_thread_start(&threadPool->eventLoopThreads[i]); 32 | } 33 | } 34 | 35 | //一定是main thread中选择 36 | struct event_loop *thread_pool_get_loop(struct thread_pool *threadPool) { 37 | assert(threadPool->started); 38 | assertInSameThread(threadPool->mainLoop); 39 | 40 | //优先选择当前主线程 41 | struct event_loop *selected = threadPool->mainLoop; 42 | 43 | //从线程池中按照顺序挑选出一个线程 44 | if (threadPool->thread_number > 0) { 45 | selected = threadPool->eventLoopThreads[threadPool->position].eventLoop; 46 | if (++threadPool->position >= threadPool->thread_number) { 47 | threadPool->position = 0; 48 | } 49 | } 50 | 51 | return selected; 52 | } 53 | -------------------------------------------------------------------------------- /lib/thread_pool.h: -------------------------------------------------------------------------------- 1 | #ifndef THREAD_POOL_H 2 | #define THREAD_POOL_H 3 | 4 | #include "event_loop.h" 5 | #include "event_loop_thread.h" 6 | 7 | struct thread_pool { 8 | //创建thread_pool的主线程 9 | struct event_loop *mainLoop; 10 | //是否已经启动 11 | int started; 12 | //线程数目 13 | int thread_number; 14 | //数组指针,指向创建的event_loop_thread数组 15 | struct event_loop_thread *eventLoopThreads; 16 | 17 | //表示在数组里的位置,用来决定选择哪个event_loop_thread服务 18 | int position; 19 | 20 | }; 21 | 22 | struct thread_pool *thread_pool_new(struct event_loop *mainLoop, int threadNumber); 23 | 24 | void thread_pool_start(struct thread_pool *); 25 | 26 | struct event_loop *thread_pool_get_loop(struct thread_pool *); 27 | 28 | #endif -------------------------------------------------------------------------------- /lib/utils.c: -------------------------------------------------------------------------------- 1 | #include "utils.h" 2 | #include "log.h" 3 | 4 | 5 | void assertInSameThread(struct event_loop *eventLoop) { 6 | if (eventLoop->owner_thread_id != pthread_self()) { 7 | LOG_ERR("not in the same thread"); 8 | exit(-1); 9 | } 10 | } 11 | 12 | //1: same thread: 0: not the same thread 13 | int isInSameThread(struct event_loop *eventLoop){ 14 | return eventLoop->owner_thread_id == pthread_self(); 15 | } -------------------------------------------------------------------------------- /lib/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef UTILS_H 2 | #define UTILS_H 3 | 4 | #include "event_loop.h" 5 | 6 | void assertInSameThread(struct event_loop *eventLoop); 7 | 8 | //1: same thread: 0: not the same thread 9 | int isInSameThread(struct event_loop *eventLoop); 10 | #endif -------------------------------------------------------------------------------- /mid-homework/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(telnet-client telnet-client.c) 2 | target_link_libraries(telnet-client yolanda) 3 | 4 | add_executable(telnet-server telnet-server.c) 5 | target_link_libraries(telnet-server yolanda) 6 | -------------------------------------------------------------------------------- /mid-homework/telnet-client.c: -------------------------------------------------------------------------------- 1 | #include "lib/common.h" 2 | 3 | #define MAXLINE 1024 4 | 5 | 6 | int main(int argc, char **argv) { 7 | if (argc != 3) { 8 | error(1, 0, "usage: tcp_client "); 9 | } 10 | int port = atoi(argv[2]); 11 | int socket_fd = tcp_client(argv[1], port); 12 | 13 | char recv_line[MAXLINE], send_line[MAXLINE]; 14 | int n; 15 | 16 | fd_set readmask; 17 | fd_set allreads; 18 | FD_ZERO(&allreads); 19 | FD_SET(0, &allreads); 20 | FD_SET(socket_fd, &allreads); 21 | 22 | for (;;) { 23 | readmask = allreads; 24 | int rc = select(socket_fd + 1, &readmask, NULL, NULL, NULL); 25 | 26 | if (rc <= 0) { 27 | error(1, errno, "select failed"); 28 | } 29 | 30 | if (FD_ISSET(socket_fd, &readmask)) { 31 | n = read(socket_fd, recv_line, MAXLINE); 32 | if (n < 0) { 33 | error(1, errno, "read error"); 34 | } else if (n == 0) { 35 | printf("server closed \n"); 36 | break; 37 | } 38 | recv_line[n] = 0; 39 | fputs(recv_line, stdout); 40 | fputs("\n", stdout); 41 | } 42 | 43 | if (FD_ISSET(STDIN_FILENO, &readmask)) { 44 | if (fgets(send_line, MAXLINE, stdin) != NULL) { 45 | int i = strlen(send_line); 46 | if (send_line[i - 1] == '\n') { 47 | send_line[i - 1] = 0; 48 | } 49 | 50 | if (strncmp(send_line, "quit", strlen(send_line)) == 0) { 51 | if (shutdown(socket_fd, 1)) { 52 | error(1, errno, "shutdown failed"); 53 | } 54 | } 55 | 56 | size_t rt = write(socket_fd, send_line, strlen(send_line)); 57 | if (rt < 0) { 58 | error(1, errno, "write failed "); 59 | } 60 | } 61 | } 62 | } 63 | 64 | exit(0); 65 | } 66 | 67 | 68 | -------------------------------------------------------------------------------- /mid-homework/telnet-server.c: -------------------------------------------------------------------------------- 1 | #include "lib/common.h" 2 | 3 | static int count; 4 | 5 | static void sig_int(int signo) { 6 | printf("\nreceived %d datagrams\n", count); 7 | exit(0); 8 | } 9 | 10 | char *run_cmd(char *cmd) { 11 | char *data = malloc(16384); 12 | bzero(data, sizeof(data)); 13 | FILE *fdp; 14 | const int max_buffer = 256; 15 | char buffer[max_buffer]; 16 | fdp = popen(cmd, "r"); 17 | char *data_index = data; 18 | if (fdp) { 19 | while (!feof(fdp)) { 20 | if (fgets(buffer, max_buffer, fdp) != NULL) { 21 | int len = strlen(buffer); 22 | memcpy(data_index, buffer, len); 23 | data_index += len; 24 | } 25 | } 26 | pclose(fdp); 27 | } 28 | return data; 29 | } 30 | 31 | int main(int argc, char **argv) { 32 | int listenfd; 33 | listenfd = socket(AF_INET, SOCK_STREAM, 0); 34 | 35 | struct sockaddr_in server_addr; 36 | bzero(&server_addr, sizeof(server_addr)); 37 | server_addr.sin_family = AF_INET; 38 | server_addr.sin_addr.s_addr = htonl(INADDR_ANY); 39 | server_addr.sin_port = htons(SERV_PORT); 40 | 41 | int on = 1; 42 | setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); 43 | 44 | int rt1 = bind(listenfd, (struct sockaddr *) &server_addr, sizeof(server_addr)); 45 | if (rt1 < 0) { 46 | error(1, errno, "bind failed "); 47 | } 48 | 49 | int rt2 = listen(listenfd, LISTENQ); 50 | if (rt2 < 0) { 51 | error(1, errno, "listen failed "); 52 | } 53 | 54 | signal(SIGPIPE, SIG_IGN); 55 | 56 | int connfd; 57 | struct sockaddr_in client_addr; 58 | socklen_t client_len = sizeof(client_addr); 59 | 60 | 61 | char buf[256]; 62 | count = 0; 63 | 64 | while (1) { 65 | if ((connfd = accept(listenfd, (struct sockaddr *) &client_addr, &client_len)) < 0) { 66 | error(1, errno, "bind failed "); 67 | } 68 | 69 | while (1) { 70 | bzero(buf, sizeof(buf)); 71 | int n = read(connfd, buf, sizeof(buf)); 72 | if (n < 0) { 73 | error(1, errno, "error read message"); 74 | } else if (n == 0) { 75 | printf("client closed \n"); 76 | close(connfd); 77 | break; 78 | } 79 | count++; 80 | buf[n] = 0; 81 | if (strncmp(buf, "ls", n) == 0) { 82 | char *result = run_cmd("ls"); 83 | if (send(connfd, result, strlen(result), 0) < 0){ 84 | return 1; 85 | } 86 | free(result); 87 | } else if (strncmp(buf, "pwd", n) == 0) { 88 | char buf[256]; 89 | char *result = getcwd(buf, 256); 90 | if (send(connfd, result, strlen(result), 0) < 0) 91 | return 1; 92 | } else if (strncmp(buf, "cd ", 3) == 0) { 93 | char target[256]; 94 | bzero(target, sizeof(target)); 95 | memcpy(target, buf + 3, strlen(buf) - 3); 96 | if (chdir(target) == -1) { 97 | printf("change dir failed, %s\n", target); 98 | } 99 | } else { 100 | char *error = "error: unknown input type"; 101 | if (send(connfd, error, strlen(error), 0) < 0) 102 | return 1; 103 | } 104 | } 105 | } 106 | exit(0); 107 | 108 | } 109 | 110 | 111 | 112 | --------------------------------------------------------------------------------