├── Client.o ├── Server.o ├── chatroom_client ├── chatroom_server ├── ServerMain.cpp ├── ClientMain.cpp ├── model.md ├── README.md ├── Server.h ├── makefile ├── Client.h ├── Common.h ├── Client.cpp ├── Server.cpp └── Client.s /Client.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xunshuidezhu/chatroom/HEAD/Client.o -------------------------------------------------------------------------------- /Server.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xunshuidezhu/chatroom/HEAD/Server.o -------------------------------------------------------------------------------- /chatroom_client: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xunshuidezhu/chatroom/HEAD/chatroom_client -------------------------------------------------------------------------------- /chatroom_server: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xunshuidezhu/chatroom/HEAD/chatroom_server -------------------------------------------------------------------------------- /ServerMain.cpp: -------------------------------------------------------------------------------- 1 | #include "Server.h" 2 | 3 | //start the server 4 | int main(int argc, char *argv[]){ 5 | Server server; 6 | server.start(); 7 | return 0; 8 | } -------------------------------------------------------------------------------- /ClientMain.cpp: -------------------------------------------------------------------------------- 1 | #include "Client.h" 2 | 3 | //start the client 4 | int main(int argc, char *argv[]) 5 | { 6 | Client client; 7 | client.Start(); 8 | return 0; 9 | } -------------------------------------------------------------------------------- /model.md: -------------------------------------------------------------------------------- 1 | ## 模型分析 2 | ### 使用 select 或者 poll 等待数据,并且可以等待多个套接字中的任何一个变为可读。这一过程会被阻塞,当某一个套接字可读时返回,之后再使用 recvfrom 把数据从内核复制到进程中。 3 | 4 | ### 它可以让单个进程具有处理多个 I/O 事件的能力。又被称为 Event Driven I/O,即事件驱动 I/O。 5 | 6 | ### 如果一个 Web 服务器没有 I/O 复用,那么每一个 Socket 连接都需要创建一个线程去处理。如果同时有几万个连接,那么就需要创建相同数量的线程。相比于多进程和多线程技术,I/O 复用不需要进程线程创建和切换的开销,系统开销更小。 7 | 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # chatroom 2 | ## the chatroom with the epoll 3 | 4 | 5 | ### 服务器采用 多线程,i/o复用实现并发,基于epoll开发的即时聊天服务器,客户端采用管道进行进程间通信,分别负责消息的read/write 6 | 7 | ### **环境** :ubuntu16.04 + gcc + vscode + gdb 8 | 9 | ### **说明** :此聊天室具备客户端和服务端,服务端接受新的客户端链接,并将每个客户端发来的信息发给所有客户端。客户端接受服务端发来的消息,并且可以将信息发送给服务端 10 | 11 | ### **how to start** : make Server.o make Clinet.o make all 12 | 13 | ### **改进** :后续会增加更多功能,增加线程池提高并发量,提高健壮性,使用reactor模型 14 | 15 | -------------------------------------------------------------------------------- /Server.h: -------------------------------------------------------------------------------- 1 | #ifndef CHATROOM_SERVER_H 2 | #define CHATROOM_SERVER_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "Common.h" 10 | 11 | using namespace std; 12 | class Server{ 13 | public: 14 | Server(); 15 | void init(); 16 | void close(); 17 | void start(); 18 | private: 19 | int sendBroadcastMessage(int clientfd); 20 | sockaddr_in serverAddr; 21 | int listener; 22 | int epfd; 23 | list clients_list; 24 | }; 25 | #endif //CHATROOM_SERVER_H -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | CC = g++ 2 | CFLAGS = -std=c++11 3 | 4 | all: ClientMain.cpp ServerMain.cpp Server.o Client.o 5 | $(CC) $(CFLAGS) ServerMain.cpp Server.o -o chatroom_server 6 | $(CC) $(CFLAGS) ClientMain.cpp Client.o -o chatroom_client 7 | Server.o: Server.cpp Server.h Common.h 8 | $(CC) $(CFLAGS) -c Server.cpp 9 | 10 | Client.o: Client.cpp Client.h Common.h 11 | $(CC) $(CFLAGS) -c Client.cpp 12 | Client.i: 13 | g++ Client.cpp -E -o Client.i 14 | Client.S: 15 | g++ Client.cpp -S -o Client.s 16 | Clean: 17 | rm -f *.o chatroom_client chatroom_server 18 | -------------------------------------------------------------------------------- /Client.h: -------------------------------------------------------------------------------- 1 | #ifndef CHATROOM_CLIENT_H 2 | #define CHATROOM_CLIENT_H 3 | 4 | #include 5 | #include "Common.h" 6 | #include 7 | using namespace std; 8 | 9 | //client class... 10 | class Client 11 | { 12 | public: 13 | //constructor 14 | Client(); 15 | //connect the server 16 | void Connect(); 17 | //close the client 18 | void Close(); 19 | //start the client 20 | void Start(); 21 | private: 22 | //the server socket 23 | int sock; 24 | //the process id 25 | pid_t pid; 26 | //the epoll_create return 27 | int epfd; 28 | //create pipe, fd[0] the father read, fd[1] the child write 29 | int pipe_fd[2]; 30 | //if the client work 31 | bool isClientWork; 32 | //chat message buffer 33 | char message[BUF_SZIE]; 34 | //server ip + port 35 | sockaddr_in serverAddr; 36 | 37 | }; 38 | 39 | 40 | #endif //CHATROOM_CLINET_H -------------------------------------------------------------------------------- /Common.h: -------------------------------------------------------------------------------- 1 | #ifndef CHARTROOM_COMMON_H 2 | #define CHARTROOM_COMMON_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | using namespace std; 19 | 20 | //default ip 21 | #define SERVER_IP "127.0.0.1" 22 | //default port 23 | #define SERVER_PORT 8080 24 | //epoll max handle 25 | #define EPOLL_SIZE 5000 26 | //buffer size 65536 27 | #define BUF_SZIE 0xFFFF 28 | //the welcome information 29 | #define SERVER_WELCOME "Welcome to the chatroom, the client id is#%d" 30 | //the user rec the chat message 31 | #define SERVER_MESSAGE "ClinetID %d say >> %s" 32 | //exit the chatroom 33 | #define EXIT "EXIT" 34 | //the caution message 35 | #define CAUTION "You are the only one in the chatroom" 36 | //add fd to the epollfd 37 | //enable_et:true ET/false LT 38 | static void addfd(int epollfd, int fd, bool enable_et) 39 | { 40 | epoll_event ev; 41 | 42 | ev.data.fd = fd; 43 | ev.events = EPOLLIN; 44 | if (enable_et) 45 | ev.events = EPOLLIN | EPOLLET; 46 | epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev); 47 | 48 | fcntl(fd, F_SETFL, fcntl(fd, F_GETFD, 0) | O_NONBLOCK); 49 | cout << "fd added to epoll " << endl; 50 | } 51 | #endif -------------------------------------------------------------------------------- /Client.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "Client.h" 4 | 5 | using namespace std; 6 | 7 | Client::Client() 8 | { 9 | serverAddr.sin_family = PF_INET; 10 | serverAddr.sin_port = htons(SERVER_PORT); 11 | serverAddr.sin_addr.s_addr = inet_addr(SERVER_IP); 12 | 13 | //init the socket 14 | sock = 0; 15 | //init the pid 16 | pid = 0; 17 | //the client stat 18 | isClientWork = true; 19 | //epoll fd 20 | epfd = 0; 21 | } 22 | //connect 23 | void Client::Connect() 24 | { 25 | cout << "Connect server: " << SERVER_IP << " : " << SERVER_PORT << endl; 26 | //create the socket 27 | sock = socket(PF_INET, SOCK_STREAM, 0); 28 | if (sock < 0) { 29 | perror("sock error"); 30 | exit(-1); 31 | } 32 | //connect the server 33 | if (connect(sock, (sockaddr*)&serverAddr, sizeof(serverAddr)) < 0) { 34 | perror("connect error"); 35 | exit(-1); 36 | } 37 | //create the pipe, the pipe[0] used to the father read, the pipe[1] used to the child write 38 | if (pipe(pipe_fd) < 0) { 39 | perror("pipe error"); 40 | exit(-1); 41 | } 42 | //create the epoll 43 | epfd = epoll_create(EPOLL_SIZE); 44 | if (epfd < 0) { 45 | perror("epfd error"); 46 | exit(-1); 47 | } 48 | //add the sock and the pipe_fd[0](the read) to the epfd 49 | addfd(epfd, sock, true); 50 | addfd(epfd, pipe_fd[0], true); 51 | } 52 | void Client::Close() 53 | { 54 | if (pid) { 55 | //close the father pipe(read) 56 | close(pipe_fd[0]); 57 | //close the socket 58 | close(sock); 59 | } else { 60 | //close the child pipe(write) 61 | close(pipe_fd[1]); 62 | } 63 | } 64 | void Client::Start() 65 | { 66 | //epoll events queue 67 | static epoll_event events[2]; 68 | //conect the server 69 | Connect(); 70 | //create the child process 71 | pid = fork(); 72 | if (pid < 0) { 73 | //fork error 74 | perror("fork error"); 75 | close(sock); 76 | exit(-1); 77 | } else if (pid == 0) { 78 | /** 79 | * ----------------- 80 | * the child process 81 | * ----------------- 82 | **/ 83 | //close the read pipe 84 | close(pipe_fd[0]); 85 | cout << "input 'exit' to exit the chatroom" << endl; 86 | //if the client work send message to the server 87 | while (isClientWork) { 88 | bzero(&message, BUF_SZIE); 89 | fgets(message, BUF_SZIE, stdin); 90 | //if client exit 91 | if (strncasecmp(message, EXIT, strlen(EXIT)) == 0) { 92 | isClientWork = 0; 93 | } 94 | //child write the message to the pipe[1] 95 | else { 96 | if (write(pipe_fd[1], message, strlen(message) - 1) < 0) { 97 | perror("fork error"); 98 | exit(-1); 99 | } 100 | } 101 | } 102 | } 103 | /** 104 | -------------- 105 | father process 106 | -------------- 107 | **/ 108 | else { 109 | //father process : read the message from the pipe 110 | //close the pipe[1](child pipe to write) 111 | close(pipe_fd[1]); 112 | while (isClientWork) { 113 | int epoll_events_count = epoll_wait(epfd, events, 2, -1); 114 | //handle the events in the queue 115 | for (int i = 0; i < epoll_events_count; ++i) { 116 | bzero(&message, BUF_SZIE); 117 | //the message from the server 118 | if (events[i].data.fd == sock) { 119 | int ret = recv(sock, message, BUF_SZIE, 0); 120 | if (ret == 0) { 121 | cout << "Server closed connection: " << sock << endl; 122 | close(sock); 123 | isClientWork = 0; 124 | } else { 125 | cout << message << endl; 126 | } 127 | } 128 | //child process write the message, father process send it to the server 129 | else { 130 | //father process read the message from the pipe 131 | int ret = read(events[i].data.fd, message, BUF_SZIE); 132 | if (ret == 0){ 133 | isClientWork = 0; 134 | }else{ 135 | send(sock, message, BUF_SZIE, 0); 136 | } 137 | } 138 | } 139 | } 140 | } 141 | Close(); 142 | } -------------------------------------------------------------------------------- /Server.cpp: -------------------------------------------------------------------------------- 1 | #include "Server.h" 2 | #include 3 | 4 | using namespace std; 5 | 6 | Server::Server() 7 | { 8 | serverAddr.sin_family = PF_INET; 9 | serverAddr.sin_port = htons(SERVER_PORT); 10 | serverAddr.sin_addr.s_addr = inet_addr(SERVER_IP); 11 | //listener 12 | listener = 0; 13 | //epoll fd 14 | epfd = 0; 15 | } 16 | void Server::init() 17 | { 18 | cout << "Init Server ... " << endl; 19 | 20 | listener = socket(PF_INET, SOCK_STREAM, 0); 21 | if (listener < 0) { 22 | perror("listener error"); 23 | exit(-1); 24 | } 25 | if (bind(listener, (sockaddr*)&serverAddr, sizeof(serverAddr)) < 0) { 26 | perror("bind error"); 27 | exit(-1); 28 | } 29 | 30 | int ret = listen(listener, 5); 31 | if (ret < 0) { 32 | perror("listen error"); 33 | exit(-1); 34 | } 35 | 36 | cout << "start to listen: " << SERVER_IP << endl; 37 | 38 | epfd = epoll_create(EPOLL_SIZE); 39 | if (epfd < 0) { 40 | perror("epoll create error"); 41 | exit(-1); 42 | } 43 | addfd(epfd, listener, true); 44 | } 45 | 46 | void Server::close() 47 | { 48 | ::close(epfd); 49 | ::close(listener); 50 | } 51 | 52 | int Server::sendBroadcastMessage(int clientfd) 53 | { 54 | //buf: rec the new mes 55 | //message: save the format message 56 | char buf[BUF_SZIE], message[BUF_SZIE]; 57 | bzero(buf, BUF_SZIE); 58 | bzero(message, BUF_SZIE); 59 | cout << "read form client : clientId--" << clientfd << endl; 60 | int len = recv(clientfd, buf, BUF_SZIE, 0); 61 | //if the client close the connection 62 | if (len == 0) { 63 | ::close(clientfd); 64 | //remove the clientfd from clinets_list 65 | clients_list.remove(clientfd); 66 | 67 | cout << "ClientId :" << clientfd << " closed , there are " << clients_list.size() << "int the chatroom" << endl; 68 | } 69 | //send the message broadcast 70 | else { 71 | //if there are clients in the chatroom 72 | if (clients_list.size() == 1) { 73 | send(clientfd, CAUTION, strlen(CAUTION), 0); 74 | return len; 75 | } 76 | //format send the message 77 | sprintf(message, SERVER_MESSAGE, clientfd, buf); 78 | 79 | list::iterator it; 80 | for (it = clients_list.begin(); it != clients_list.end(); ++it) { 81 | if (*it != clientfd) { 82 | if (send(*it, message, BUF_SZIE, 0) < 0) { 83 | return -1; 84 | } 85 | } 86 | } 87 | } 88 | return len; 89 | } 90 | 91 | void Server::start() 92 | { 93 | //epoll queue 94 | static epoll_event events[EPOLL_SIZE]; 95 | //init the server 96 | init(); 97 | 98 | while (1) { 99 | //the num of the event 100 | int epoll_events_count = epoll_wait(epfd, events, EPOLL_SIZE, -1); 101 | 102 | if (epoll_events_count < 0) { 103 | perror("epoll error"); 104 | break; 105 | } 106 | 107 | cout << "epoll_events_count =\n" 108 | << epoll_events_count << endl; 109 | //handle the event 110 | for (int i = 0; i < epoll_events_count; i++) { 111 | int sockfd = events[i].data.fd; 112 | //new user connect 113 | if (sockfd == listener) { 114 | sockaddr_in client_address; 115 | socklen_t client_addrLength = sizeof(sockaddr_in); 116 | int clientfd = accept(listener, (sockaddr*)&client_address, &client_addrLength); 117 | 118 | cout << "client connection from: " 119 | << inet_ntoa(client_address.sin_addr) << ":" 120 | << ntohs(client_address.sin_port) << ", cientfd = " 121 | << clientfd << endl; 122 | 123 | addfd(epfd, clientfd, true); 124 | 125 | //clients_list save the client 126 | clients_list.push_back(clientfd); 127 | cout << "add new clientfd = " << clientfd << "to epoll " << endl; 128 | cout << "Now there are " << clients_list.size() << "clients in the chatroom" << endl; 129 | //server send the message 130 | cout << "welcome message" << endl; 131 | char message[BUF_SZIE]; 132 | memset(&message, 0, BUF_SZIE); 133 | //clientg -> SERVER_WELCOME -> message,return strlen(message) 134 | sprintf(message, SERVER_WELCOME, clientfd); 135 | int ret = send(clientfd, message, BUF_SZIE, 0); 136 | if (ret < 0) { 137 | perror("send error"); 138 | close(); 139 | exit(-1); 140 | } 141 | 142 | } 143 | //handle the message from client , broadcast the message 144 | else { 145 | int ret = sendBroadcastMessage(sockfd); 146 | if (ret < 0) { 147 | perror(""); 148 | close(); 149 | exit(-1); 150 | } 151 | } 152 | } 153 | } 154 | //close the server 155 | close(); 156 | } -------------------------------------------------------------------------------- /Client.s: -------------------------------------------------------------------------------- 1 | .file "Client.cpp" 2 | .local _ZStL8__ioinit 3 | .comm _ZStL8__ioinit,1,1 4 | .section .rodata 5 | .LC0: 6 | .string "fd added to epoll " 7 | .text 8 | .type _ZL5addfdiib, @function 9 | _ZL5addfdiib: 10 | .LFB1132: 11 | .cfi_startproc 12 | pushq %rbp 13 | .cfi_def_cfa_offset 16 14 | .cfi_offset 6, -16 15 | movq %rsp, %rbp 16 | .cfi_def_cfa_register 6 17 | subq $48, %rsp 18 | movl %edi, -36(%rbp) 19 | movl %esi, -40(%rbp) 20 | movl %edx, %eax 21 | movb %al, -44(%rbp) 22 | movq %fs:40, %rax 23 | movq %rax, -8(%rbp) 24 | xorl %eax, %eax 25 | movl -40(%rbp), %eax 26 | movl %eax, -28(%rbp) 27 | movl $1, -32(%rbp) 28 | cmpb $0, -44(%rbp) 29 | je .L2 30 | movl $-2147483647, -32(%rbp) 31 | .L2: 32 | leaq -32(%rbp), %rcx 33 | movl -40(%rbp), %edx 34 | movl -36(%rbp), %eax 35 | movl $1, %esi 36 | movl %eax, %edi 37 | call epoll_ctl 38 | movl -40(%rbp), %eax 39 | movl $0, %edx 40 | movl $1, %esi 41 | movl %eax, %edi 42 | movl $0, %eax 43 | call fcntl 44 | orb $8, %ah 45 | movl %eax, %edx 46 | movl -40(%rbp), %eax 47 | movl $4, %esi 48 | movl %eax, %edi 49 | movl $0, %eax 50 | call fcntl 51 | movl $.LC0, %esi 52 | movl $_ZSt4cout, %edi 53 | call _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc 54 | movl $_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_, %esi 55 | movq %rax, %rdi 56 | call _ZNSolsEPFRSoS_E 57 | nop 58 | movq -8(%rbp), %rax 59 | xorq %fs:40, %rax 60 | je .L3 61 | call __stack_chk_fail 62 | .L3: 63 | leave 64 | .cfi_def_cfa 7, 8 65 | ret 66 | .cfi_endproc 67 | .LFE1132: 68 | .size _ZL5addfdiib, .-_ZL5addfdiib 69 | .section .rodata 70 | .LC1: 71 | .string "127.0.0.1" 72 | .text 73 | .align 2 74 | .globl _ZN6ClientC2Ev 75 | .type _ZN6ClientC2Ev, @function 76 | _ZN6ClientC2Ev: 77 | .LFB1134: 78 | .cfi_startproc 79 | pushq %rbp 80 | .cfi_def_cfa_offset 16 81 | .cfi_offset 6, -16 82 | movq %rsp, %rbp 83 | .cfi_def_cfa_register 6 84 | subq $16, %rsp 85 | movq %rdi, -8(%rbp) 86 | movq -8(%rbp), %rax 87 | movw $2, 65556(%rax) 88 | movl $8080, %edi 89 | call htons 90 | movl %eax, %edx 91 | movq -8(%rbp), %rax 92 | movw %dx, 65558(%rax) 93 | movl $.LC1, %edi 94 | call inet_addr 95 | movl %eax, %edx 96 | movq -8(%rbp), %rax 97 | movl %edx, 65560(%rax) 98 | movq -8(%rbp), %rax 99 | movl $0, (%rax) 100 | movq -8(%rbp), %rax 101 | movl $0, 4(%rax) 102 | movq -8(%rbp), %rax 103 | movb $1, 20(%rax) 104 | movq -8(%rbp), %rax 105 | movl $0, 8(%rax) 106 | nop 107 | leave 108 | .cfi_def_cfa 7, 8 109 | ret 110 | .cfi_endproc 111 | .LFE1134: 112 | .size _ZN6ClientC2Ev, .-_ZN6ClientC2Ev 113 | .globl _ZN6ClientC1Ev 114 | .set _ZN6ClientC1Ev,_ZN6ClientC2Ev 115 | .section .rodata 116 | .LC2: 117 | .string "Connect server: " 118 | .LC3: 119 | .string " : " 120 | .LC4: 121 | .string "sock error" 122 | .LC5: 123 | .string "connect error" 124 | .LC6: 125 | .string "pipe error" 126 | .LC7: 127 | .string "epfd error" 128 | .text 129 | .align 2 130 | .globl _ZN6Client7ConnectEv 131 | .type _ZN6Client7ConnectEv, @function 132 | _ZN6Client7ConnectEv: 133 | .LFB1136: 134 | .cfi_startproc 135 | pushq %rbp 136 | .cfi_def_cfa_offset 16 137 | .cfi_offset 6, -16 138 | movq %rsp, %rbp 139 | .cfi_def_cfa_register 6 140 | subq $16, %rsp 141 | movq %rdi, -8(%rbp) 142 | movl $.LC2, %esi 143 | movl $_ZSt4cout, %edi 144 | call _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc 145 | movl $.LC1, %esi 146 | movq %rax, %rdi 147 | call _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc 148 | movl $.LC3, %esi 149 | movq %rax, %rdi 150 | call _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc 151 | movl $8080, %esi 152 | movq %rax, %rdi 153 | call _ZNSolsEi 154 | movl $_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_, %esi 155 | movq %rax, %rdi 156 | call _ZNSolsEPFRSoS_E 157 | movl $0, %edx 158 | movl $1, %esi 159 | movl $2, %edi 160 | call socket 161 | movl %eax, %edx 162 | movq -8(%rbp), %rax 163 | movl %edx, (%rax) 164 | movq -8(%rbp), %rax 165 | movl (%rax), %eax 166 | testl %eax, %eax 167 | jns .L6 168 | movl $.LC4, %edi 169 | call perror 170 | movl $-1, %edi 171 | call exit 172 | .L6: 173 | movl $16, %edx 174 | movq -8(%rbp), %rax 175 | leaq 65556(%rax), %rcx 176 | movq -8(%rbp), %rax 177 | movl (%rax), %eax 178 | movq %rcx, %rsi 179 | movl %eax, %edi 180 | call connect 181 | shrl $31, %eax 182 | testb %al, %al 183 | je .L7 184 | movl $.LC5, %edi 185 | call perror 186 | movl $-1, %edi 187 | call exit 188 | .L7: 189 | movq -8(%rbp), %rax 190 | addq $12, %rax 191 | movq %rax, %rdi 192 | call pipe 193 | shrl $31, %eax 194 | testb %al, %al 195 | je .L8 196 | movl $.LC6, %edi 197 | call perror 198 | movl $-1, %edi 199 | call exit 200 | .L8: 201 | movl $5000, %edi 202 | call epoll_create 203 | movl %eax, %edx 204 | movq -8(%rbp), %rax 205 | movl %edx, 8(%rax) 206 | movq -8(%rbp), %rax 207 | movl 8(%rax), %eax 208 | testl %eax, %eax 209 | jns .L9 210 | movl $.LC7, %edi 211 | call perror 212 | movl $-1, %edi 213 | call exit 214 | .L9: 215 | movq -8(%rbp), %rax 216 | movl (%rax), %ecx 217 | movq -8(%rbp), %rax 218 | movl 8(%rax), %eax 219 | movl $1, %edx 220 | movl %ecx, %esi 221 | movl %eax, %edi 222 | call _ZL5addfdiib 223 | movq -8(%rbp), %rax 224 | movl 12(%rax), %ecx 225 | movq -8(%rbp), %rax 226 | movl 8(%rax), %eax 227 | movl $1, %edx 228 | movl %ecx, %esi 229 | movl %eax, %edi 230 | call _ZL5addfdiib 231 | nop 232 | leave 233 | .cfi_def_cfa 7, 8 234 | ret 235 | .cfi_endproc 236 | .LFE1136: 237 | .size _ZN6Client7ConnectEv, .-_ZN6Client7ConnectEv 238 | .align 2 239 | .globl _ZN6Client5CloseEv 240 | .type _ZN6Client5CloseEv, @function 241 | _ZN6Client5CloseEv: 242 | .LFB1137: 243 | .cfi_startproc 244 | pushq %rbp 245 | .cfi_def_cfa_offset 16 246 | .cfi_offset 6, -16 247 | movq %rsp, %rbp 248 | .cfi_def_cfa_register 6 249 | subq $16, %rsp 250 | movq %rdi, -8(%rbp) 251 | movq -8(%rbp), %rax 252 | movl 4(%rax), %eax 253 | testl %eax, %eax 254 | je .L11 255 | movq -8(%rbp), %rax 256 | movl 12(%rax), %eax 257 | movl %eax, %edi 258 | call close 259 | movq -8(%rbp), %rax 260 | movl (%rax), %eax 261 | movl %eax, %edi 262 | call close 263 | jmp .L13 264 | .L11: 265 | movq -8(%rbp), %rax 266 | movl 16(%rax), %eax 267 | movl %eax, %edi 268 | call close 269 | .L13: 270 | nop 271 | leave 272 | .cfi_def_cfa 7, 8 273 | ret 274 | .cfi_endproc 275 | .LFE1137: 276 | .size _ZN6Client5CloseEv, .-_ZN6Client5CloseEv 277 | .section .rodata 278 | .LC8: 279 | .string "fork error" 280 | .align 8 281 | .LC9: 282 | .string "input 'exit' to exit the chatroom" 283 | .LC10: 284 | .string "EXIT" 285 | .LC11: 286 | .string "Server closed connection: " 287 | .text 288 | .align 2 289 | .globl _ZN6Client5StartEv 290 | .type _ZN6Client5StartEv, @function 291 | _ZN6Client5StartEv: 292 | .LFB1138: 293 | .cfi_startproc 294 | pushq %rbp 295 | .cfi_def_cfa_offset 16 296 | .cfi_offset 6, -16 297 | movq %rsp, %rbp 298 | .cfi_def_cfa_register 6 299 | pushq %rbx 300 | subq $40, %rsp 301 | .cfi_offset 3, -24 302 | movq %rdi, -40(%rbp) 303 | movq -40(%rbp), %rax 304 | movq %rax, %rdi 305 | call _ZN6Client7ConnectEv 306 | call fork 307 | movl %eax, %edx 308 | movq -40(%rbp), %rax 309 | movl %edx, 4(%rax) 310 | movq -40(%rbp), %rax 311 | movl 4(%rax), %eax 312 | testl %eax, %eax 313 | jns .L15 314 | movl $.LC8, %edi 315 | call perror 316 | movq -40(%rbp), %rax 317 | movl (%rax), %eax 318 | movl %eax, %edi 319 | call close 320 | movl $-1, %edi 321 | call exit 322 | .L15: 323 | movq -40(%rbp), %rax 324 | movl 4(%rax), %eax 325 | testl %eax, %eax 326 | jne .L16 327 | movq -40(%rbp), %rax 328 | movl 12(%rax), %eax 329 | movl %eax, %edi 330 | call close 331 | movl $.LC9, %esi 332 | movl $_ZSt4cout, %edi 333 | call _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc 334 | movl $_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_, %esi 335 | movq %rax, %rdi 336 | call _ZNSolsEPFRSoS_E 337 | .L20: 338 | movq -40(%rbp), %rax 339 | movzbl 20(%rax), %eax 340 | testb %al, %al 341 | je .L17 342 | movq -40(%rbp), %rax 343 | addq $21, %rax 344 | movl $65535, %esi 345 | movq %rax, %rdi 346 | call bzero 347 | movq stdin(%rip), %rax 348 | movq -40(%rbp), %rdx 349 | leaq 21(%rdx), %rcx 350 | movq %rax, %rdx 351 | movl $65535, %esi 352 | movq %rcx, %rdi 353 | call fgets 354 | movq -40(%rbp), %rax 355 | addq $21, %rax 356 | movl $4, %edx 357 | movl $.LC10, %esi 358 | movq %rax, %rdi 359 | call strncasecmp 360 | testl %eax, %eax 361 | jne .L18 362 | movq -40(%rbp), %rax 363 | movb $0, 20(%rax) 364 | jmp .L20 365 | .L18: 366 | movq -40(%rbp), %rax 367 | addq $21, %rax 368 | movq %rax, %rdi 369 | call strlen 370 | leaq -1(%rax), %rdx 371 | movq -40(%rbp), %rax 372 | leaq 21(%rax), %rcx 373 | movq -40(%rbp), %rax 374 | movl 16(%rax), %eax 375 | movq %rcx, %rsi 376 | movl %eax, %edi 377 | call write 378 | shrq $63, %rax 379 | testb %al, %al 380 | je .L20 381 | movl $.LC8, %edi 382 | call perror 383 | movl $-1, %edi 384 | call exit 385 | .L16: 386 | movq -40(%rbp), %rax 387 | movl 16(%rax), %eax 388 | movl %eax, %edi 389 | call close 390 | .L28: 391 | movq -40(%rbp), %rax 392 | movzbl 20(%rax), %eax 393 | testb %al, %al 394 | je .L17 395 | movq -40(%rbp), %rax 396 | movl 8(%rax), %eax 397 | movl $-1, %ecx 398 | movl $2, %edx 399 | movl $_ZZN6Client5StartEvE6events, %esi 400 | movl %eax, %edi 401 | call epoll_wait 402 | movl %eax, -28(%rbp) 403 | movl $0, -32(%rbp) 404 | .L27: 405 | movl -32(%rbp), %eax 406 | cmpl -28(%rbp), %eax 407 | jge .L28 408 | movq -40(%rbp), %rax 409 | addq $21, %rax 410 | movl $65535, %esi 411 | movq %rax, %rdi 412 | call bzero 413 | movl -32(%rbp), %eax 414 | movslq %eax, %rdx 415 | movq %rdx, %rax 416 | addq %rax, %rax 417 | addq %rdx, %rax 418 | salq $2, %rax 419 | addq $_ZZN6Client5StartEvE6events+4, %rax 420 | movl (%rax), %edx 421 | movq -40(%rbp), %rax 422 | movl (%rax), %eax 423 | cmpl %eax, %edx 424 | jne .L22 425 | movq -40(%rbp), %rax 426 | leaq 21(%rax), %rsi 427 | movq -40(%rbp), %rax 428 | movl (%rax), %eax 429 | movl $0, %ecx 430 | movl $65535, %edx 431 | movl %eax, %edi 432 | call recv 433 | movl %eax, -24(%rbp) 434 | cmpl $0, -24(%rbp) 435 | jne .L23 436 | movq -40(%rbp), %rax 437 | movl (%rax), %ebx 438 | movl $.LC11, %esi 439 | movl $_ZSt4cout, %edi 440 | call _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc 441 | movl %ebx, %esi 442 | movq %rax, %rdi 443 | call _ZNSolsEi 444 | movl $_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_, %esi 445 | movq %rax, %rdi 446 | call _ZNSolsEPFRSoS_E 447 | movq -40(%rbp), %rax 448 | movl (%rax), %eax 449 | movl %eax, %edi 450 | call close 451 | movq -40(%rbp), %rax 452 | movb $0, 20(%rax) 453 | jmp .L25 454 | .L23: 455 | movq -40(%rbp), %rax 456 | addq $21, %rax 457 | movq %rax, %rsi 458 | movl $_ZSt4cout, %edi 459 | call _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc 460 | movl $_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_, %esi 461 | movq %rax, %rdi 462 | call _ZNSolsEPFRSoS_E 463 | jmp .L25 464 | .L22: 465 | movq -40(%rbp), %rax 466 | leaq 21(%rax), %rcx 467 | movl -32(%rbp), %eax 468 | movslq %eax, %rdx 469 | movq %rdx, %rax 470 | addq %rax, %rax 471 | addq %rdx, %rax 472 | salq $2, %rax 473 | addq $_ZZN6Client5StartEvE6events+4, %rax 474 | movl (%rax), %eax 475 | movl $65535, %edx 476 | movq %rcx, %rsi 477 | movl %eax, %edi 478 | call read 479 | movl %eax, -20(%rbp) 480 | cmpl $0, -20(%rbp) 481 | jne .L26 482 | movq -40(%rbp), %rax 483 | movb $0, 20(%rax) 484 | jmp .L25 485 | .L26: 486 | movq -40(%rbp), %rax 487 | leaq 21(%rax), %rsi 488 | movq -40(%rbp), %rax 489 | movl (%rax), %eax 490 | movl $0, %ecx 491 | movl $65535, %edx 492 | movl %eax, %edi 493 | call send 494 | .L25: 495 | addl $1, -32(%rbp) 496 | jmp .L27 497 | .L17: 498 | movq -40(%rbp), %rax 499 | movq %rax, %rdi 500 | call _ZN6Client5CloseEv 501 | nop 502 | addq $40, %rsp 503 | popq %rbx 504 | popq %rbp 505 | .cfi_def_cfa 7, 8 506 | ret 507 | .cfi_endproc 508 | .LFE1138: 509 | .size _ZN6Client5StartEv, .-_ZN6Client5StartEv 510 | .type _Z41__static_initialization_and_destruction_0ii, @function 511 | _Z41__static_initialization_and_destruction_0ii: 512 | .LFB1147: 513 | .cfi_startproc 514 | pushq %rbp 515 | .cfi_def_cfa_offset 16 516 | .cfi_offset 6, -16 517 | movq %rsp, %rbp 518 | .cfi_def_cfa_register 6 519 | subq $16, %rsp 520 | movl %edi, -4(%rbp) 521 | movl %esi, -8(%rbp) 522 | cmpl $1, -4(%rbp) 523 | jne .L31 524 | cmpl $65535, -8(%rbp) 525 | jne .L31 526 | movl $_ZStL8__ioinit, %edi 527 | call _ZNSt8ios_base4InitC1Ev 528 | movl $__dso_handle, %edx 529 | movl $_ZStL8__ioinit, %esi 530 | movl $_ZNSt8ios_base4InitD1Ev, %edi 531 | call __cxa_atexit 532 | .L31: 533 | nop 534 | leave 535 | .cfi_def_cfa 7, 8 536 | ret 537 | .cfi_endproc 538 | .LFE1147: 539 | .size _Z41__static_initialization_and_destruction_0ii, .-_Z41__static_initialization_and_destruction_0ii 540 | .type _GLOBAL__sub_I__ZN6ClientC2Ev, @function 541 | _GLOBAL__sub_I__ZN6ClientC2Ev: 542 | .LFB1148: 543 | .cfi_startproc 544 | pushq %rbp 545 | .cfi_def_cfa_offset 16 546 | .cfi_offset 6, -16 547 | movq %rsp, %rbp 548 | .cfi_def_cfa_register 6 549 | movl $65535, %esi 550 | movl $1, %edi 551 | call _Z41__static_initialization_and_destruction_0ii 552 | popq %rbp 553 | .cfi_def_cfa 7, 8 554 | ret 555 | .cfi_endproc 556 | .LFE1148: 557 | .size _GLOBAL__sub_I__ZN6ClientC2Ev, .-_GLOBAL__sub_I__ZN6ClientC2Ev 558 | .section .init_array,"aw" 559 | .align 8 560 | .quad _GLOBAL__sub_I__ZN6ClientC2Ev 561 | .local _ZZN6Client5StartEvE6events 562 | .comm _ZZN6Client5StartEvE6events,24,16 563 | .hidden __dso_handle 564 | .ident "GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.11) 5.4.0 20160609" 565 | .section .note.GNU-stack,"",@progbits 566 | --------------------------------------------------------------------------------