#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <iostream>
volatile sig_atomic_t flag = 0;
static void my_handler(int sig) {
flag = 1;
}
ssize_t count_flag = 0;
void HandleEvents(int epoll_fd, epoll_event* events, int max_event, int listen_socket) {
if (events == nullptr || max_event <= 0) {
return;
}
for (int i = 0; i < max_event; ++i) {
char buf[1024 * 10] = {0};
if (events[i].data.fd == listen_socket && (events[i].events & EPOLLIN)) {
sockaddr_in peer;
socklen_t peer_len = sizeof(peer);
int acc_sock = accept(listen_socket, (sockaddr*) &peer, &peer_len);
if (acc_sock < 0) {
std::cout << "Error, accept failed" << std::endl;
continue;
} else {
epoll_event event;
event.data.fd = acc_sock;
event.events = EPOLLIN;
int ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, acc_sock, &event);
std::cout << "INFO, EPOLL_CTL_ADD, EPOLLIN client socket ->" << acc_sock << std::endl;
if (ret < 0) {
std::cout << "Error, epoll ctl failed" << std::endl;
continue;
}
}
continue;
}
if (events[i].events & EPOLLIN) {
ssize_t read_size = read(events[i].data.fd, buf, sizeof(buf) - 1);
if (events[i].data.fd == -1) {
std::cout << "Error, data.fd==-1" << std::endl;
}
std::cout << "read size->" << read_size << std::endl;
if (read_size < 0) {
std::cout << "Error, read failed" << std::endl;
close(events[i].data.fd);
epoll_ctl(epoll_fd, EPOLL_CTL_DEL, events[i].data.fd, NULL);
std::cout << "INFO, EPOLL_CTL_DEL, client socket ->" << events[i].data.fd << std::endl;
continue;
}
if (read_size == 0) {
std::cout << "Error, client disconnect" << std::endl;
close(events[i].data.fd);
epoll_ctl(epoll_fd, EPOLL_CTL_DEL, events[i].data.fd, NULL);
std::cout << "INFO, EPOLL_CTL_DEL, client socket ->" << events[i].data.fd << std::endl;
continue;
}
buf[read_size] = '\0';
std::cout << "Read msg->" << buf << std::endl;
epoll_event event;
event.data.fd = events[i].data.fd;
event.events = EPOLLIN | EPOLLOUT;
int ret = epoll_ctl(epoll_fd, EPOLL_CTL_MOD, events[i].data.fd, &event);
std::cout << "INFO, EPOLL_CTL_ADD, EPOLLOUT client socket ->" << events[i].data.fd << std::endl;
std::cout << "epoll ctl ret->" << ret << std::endl;
}
if (events[i].events & EPOLLOUT) {
std::cout << "Write to " << events[i].data.fd << std::endl;
const char* recv = "HTTP/1.1 200 OK\r\n\r\n<html><h1>hello world</h1><html>";
write(events[i].data.fd, recv, strlen(recv));
close(events[i].data.fd);
epoll_ctl(epoll_fd, EPOLL_CTL_DEL, events[i].data.fd, NULL);
std::cout << "INFO, EPOLL_CTL_DEL, client socket ->" << events[i].data.fd << std::endl;
}
}
}
int ServerStart(const char* ip, const short port) {
int server_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (server_socket < 0) {
std::cout << "Error, server_socket<0" << std::endl;
return -1;
}
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(ip);
addr.sin_port = htons(port);
int bind_result = bind(server_socket, (sockaddr*) &addr, sizeof(addr));
if (bind_result < 0) {
std::cout << "Error, bind_result<0" << std::endl;
return -1;
}
int listen_ret = listen(server_socket, 5);
if (listen_ret < 0) {
std::cout << "Error, listen_result<0" << std::endl;
return -1;
}
return server_socket;
}
int main(int argc, char* argv[]) {
if (argc != 3) {
std::cout << "Usage :./socket_base [ip] [port]" << std::endl;
return -1;
}
int server_socket = ServerStart(argv[1], atoi(argv[2]));
if (server_socket < 0) {
std::cout << "Error, fail to start server" << std::endl;
return -1;
}
std::cout << "Start server successfully" << std::endl;
int epoll_fd = epoll_create(256);
if (epoll_fd < 0) {
std::cout << "Error, fail to create epoll" << std::endl;
return -1;
}
signal(SIGINT, my_handler);
epoll_event event;
event.data.fd = server_socket;
event.events = EPOLLIN;
int ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_socket, &event);
std::cout << "INFO, EPOLL_CTL_ADD, EPOLLIN server socket ->" << server_socket << std::endl;
if (ret < 0) {
std::cout << "Error, epoll ctl failed" << std::endl;
return -1;
}
std::cout << "INFO, epoll ctl success" << std::endl;
while (true) {
epoll_event events[128];
memset(events, 0, sizeof(events) / sizeof(epoll_event));
int size = epoll_wait(epoll_fd, events, sizeof(events) / sizeof(events[0]), -1);
std::cout << "----While true, epoll wait size->" << size << std::endl;
switch (size) {
case -1:
std::cout << "Error, epoll waiting pool size<0\n";
break;
case 0:
std::cout << "Warning, epoll waiting pool size==0\n";
break;
default:
HandleEvents(epoll_fd, events, size, server_socket);
break;
}
if (flag) {
std::cout << "Catch Ctrl+C, exit" << std::endl;
flag = 0;
break;
}
}
close(server_socket);
close(epoll_fd);
return 0;
}