#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <sys/epoll.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
int set_none_block(int fd)
{
int flags = fcntl(fd, F_GETFL, 0);
if (flags < 0)
{
perror("get F_GETFL failed");
return -1;
}
int ret = fcntl(fd, F_GETFL, flags | O_NONBLOCK);
if (ret < 0)
{
perror("set F_GETFL failed");
}
return ret;
}
int update_events(int efd, int fd, int events, int op)
{
struct epoll_event ev = {0};
memset(&ev, 0, sizeof(ev));
ev.data.fd = fd;
ev.events = events;
printf("%s fd %d events read %d write %d\n", op == EPOLL_CTL_MOD ? "mod" : "add", fd, ev.events & EPOLLIN, ev.events & EPOLLOUT);
int ret = epoll_ctl(efd, op, fd, &ev);
if (ret < 0)
{
printf("epoll_ctl error:%s\n", strerror(errno));
}
return ret;
}
int handle_accept(int efd, int fd)
{
struct sockaddr_in raddr = {0};
socklen_t raddr_size = sizeof(raddr);
int afd = accept(fd, (struct sockaddr *)&raddr, &raddr_size);
if (afd < 0)
{
printf("accept faild\n");
return -1;
}
struct sockaddr peer, local;
socklen_t peer_size = sizeof(peer);
int ret = getpeername(afd, (struct sockaddr *)&peer, &peer_size);
if (ret < 0)
{
printf("getpeername failed\n");
return -1;
}
printf("accept a connection from %s\n", inet_ntoa(raddr.sin_addr));
set_none_block(afd);
update_events(efd, afd, EPOLLIN | EPOLLOUT | EPOLLET, EPOLL_CTL_ADD);
return 0;
}
int send_data(int fd, char *data, int len)
{
int w = 0;
while ((w = write(fd, data, len)) > 0)
{
data += w;
len -= w;
}
if (w < 0 && (errno == EAGAIN || errno == EWOULDBLOCK))
{
printf("send failed:%s\n", strerror(errno));
return -1;
}
return 0;
}
char testData[] = "HTTP/1.1 200 OK\r\nConnection: Keep-Alive\r\nContent-Type: t ext/html; charset=UTF-8\r\nContent-Length: 1048576\r\n\r\n123456";
int recieve_data(int fd)
{
int n = 0;
char buff[4096] = {0};
printf("handle recieve data ...\n");
n = read(fd, buff, sizeof(buff));
if (n < 0)
{
perror("read");
return errno;
}
if (n == 0)
{
printf("fd %d is closed\n", fd);
return errno;
}
if (n > 0 && n < sizeof(buff))
{
if (strstr(buff, "\r\n\r\n") != NULL)
{
char *p = malloc(2048 * 1024);
if (p)
{
memset(p, 0, 2048 * 1024);
strcpy(p, testData);
int len = strlen(testData);
for (int i = 0; i < 1048570; i++)
p[len++] = 'A';
write(fd, p, len);
free(p);
}
}
else
{
printf("read:%s\n", buff);
write(fd, "ack:", 4);
write(fd, buff, n);
}
}
else if (n >= sizeof(buff))
{
printf("read too much data\n");
}
printf("handle recieve data end\n");
return 0;
}
void loop_once(int efd, int lfd, int timeout)
{
int maxEvts = 20;
struct epoll_event activeEvts[100] = {0};
int n = epoll_wait(efd, activeEvts, maxEvts, timeout);
printf("epoll_wait return %d\n", n);
for (int i = 0; i < n; i++)
{
int fd = activeEvts[i].data.fd;
int ev = activeEvts[i].events;
if (ev & (EPOLLIN | EPOLLERR))
{
if (fd == lfd)
handle_accept(efd, fd);
else
recieve_data(fd);
}
else if (ev & EPOLLOUT)
{
printf("handle epollout\n");
send_data(fd, "fuck the world\n", 15);
}
else
{
printf("unknown event\n");
exit(-1);
}
}
}
void signal_handler(int signal)
{
switch (signal)
{
case SIGPIPE:
break;
case SIGINT:
printf("stop by user\n");
exit(0);
break;
default:
break;
}
}
int main(int argc, char *argv[])
{
signal(SIGINT, signal_handler);
short port = 20000;
int efd = epoll_create(1);
if (efd < 0)
{
printf("create epoll failed\n");
return -1;
}
int listen_fd = socket(AF_INET, SOCK_STREAM, 0);
if (listen_fd < 0)
{
printf("create listen socket failed\n");
return -1;
}
struct sockaddr_in addr = {0};
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = INADDR_ANY;
int ret = bind(listen_fd, (struct sockaddr *)&addr, sizeof(struct sockaddr));
if (ret)
{
printf("bind to 0.0.0.0:%d failed %d, %s", port, errno, strerror(errno));
return -1;
}
ret = listen(listen_fd, 20);
if (ret)
{
printf("listen failed %d, %s", errno, strerror(errno));
return -1;
}
printf("fd %d listen at %d\n", listen_fd, port);
set_none_block(listen_fd);
update_events(efd, listen_fd, EPOLLIN, EPOLL_CTL_ADD);
for (;;)
{
loop_once(efd, listen_fd, 10000);
}
return 0;
}