Skip to content

Instantly share code, notes, and snippets.

@jorben
Created December 2, 2015 01:37
Show Gist options
  • Save jorben/d5526c5cdd5a58964d78 to your computer and use it in GitHub Desktop.
Save jorben/d5526c5cdd5a58964d78 to your computer and use it in GitHub Desktop.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <time.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <sys/resource.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#define MAXEPOLLSIZE 60000
#define MAXLINE 1024
int handle(int fd);
int setnonblocking(int fd);
char* getbody(char* buf, size_t sz);
char* gethead(char* buf, size_t sz, int bodylen);
char* getgmt(char* buf, size_t sz);
int main(int argc, char** argv)
{
int serv_port = 53101;
char* serv_host = "0.0.0.0";
signal(SIGPIPE, SIG_IGN);
if(3 == argc)
{
serv_host = argv[1];
serv_port = atoi(argv[2]);
}
else if(1 != argc)
{
printf("Usage:%s Ip Port\n", argv[0]);
return 0;
}
int fd_sock, fd_conn, kdpfd, nfds, n, curfds, accept_count = 0;
int listenq = 60000;
struct sockaddr_in serv_addr, cli_addr;
socklen_t socklen = sizeof(struct sockaddr_in);
struct epoll_event ev;
struct epoll_event ev_poll[MAXEPOLLSIZE];
struct rlimit rt;
char buf[MAXLINE];
rt.rlim_max = rt.rlim_cur = MAXEPOLLSIZE;
if(-1 == setrlimit(RLIMIT_NOFILE, &rt))
{
perror("setrlimit error");
return -1;
}
bzero(&serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = inet_addr(serv_host);
serv_addr.sin_port = htons(serv_port);
fd_sock = socket(AF_INET, SOCK_STREAM, 0);
if(0 > fd_sock)
{
perror("socket error");
return -1;
}
int opt = 1;
if(0 > setsockopt(fd_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)))
{
perror("setsockopt SO_REUSEADDR error");
return -1;
}
if(0 > setnonblocking(fd_sock))
{
perror("setnonblocking error");
}
if(0 > bind(fd_sock, (struct sockaddr *) &serv_addr, sizeof(struct sockaddr)))
{
perror("bind error");
return -1;
}
if(0 > listen(fd_sock, listenq))
{
perror("listen error");
return -1;
}
kdpfd = epoll_create(MAXEPOLLSIZE);
ev.events = EPOLLIN | EPOLLET;
ev.data.fd = fd_sock;
if(0 > epoll_ctl(kdpfd, EPOLL_CTL_ADD, fd_sock, &ev))
{
printf("epoll set insertion error: fd=%d\n", fd_sock);
return -1;
}
curfds = 1;
printf("epollserver startup, listen on %s:%d, max connection is %d, backlog is %d\n", serv_host, serv_port, MAXEPOLLSIZE, listenq);
for( ; ; )
{
nfds = epoll_wait(kdpfd, ev_poll, curfds, -1);
if (0 > nfds )
{
if (EINTR != errno || EAGAIN != errno)
{
printf("kdpfd:%d curfds:%d nfds:%d\n", kdpfd, curfds, nfds);
perror("epoll_wait error");
}
continue;
}
for(n = 0; n < nfds; n++)
{
if (fd_sock == ev_poll[n].data.fd)
{
fd_conn = accept(fd_sock, (struct sockaddr *) &cli_addr, &socklen);
if(0 > fd_conn)
{
perror("accept error");
continue;
}
sprintf(buf, "accept from %s:%d\n", inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port) );
// printf("%d:%s", ++accept_count, buf);
if(curfds >= MAXEPOLLSIZE)
{
printf("too many connection, more than %d\n", MAXEPOLLSIZE);
close(fd_conn);
continue;
}
if(0 > setnonblocking(fd_conn))
{
perror("setnonblocking error");
}
ev.events = EPOLLIN | EPOLLET;
ev.data.fd = fd_conn;
if (0 > epoll_ctl(kdpfd, EPOLL_CTL_ADD, fd_conn, &ev))
{
printf("add socket '%d' to epoll failed: %s\n", fd_conn, strerror(errno));
return -1;
}
curfds++;
continue;
}
// printf("\n===========================================\nstatus: some data coming...\n");
// handle(ev_poll[n].data.fd);
if(0 > handle(ev_poll[n].data.fd))
{
epoll_ctl(kdpfd, EPOLL_CTL_DEL, ev_poll[n].data.fd, &ev);
close(fd_conn);
curfds--;
}
}
}
close(fd_sock);
return 0;
}
int handle(int fd)
{
int n_read;
char buf[MAXLINE];
n_read = read(fd, buf, MAXLINE);
if(0 > n_read)
{
if(104 == errno)
{
return -1;
}
// perror("read error");
printf("read error: %d, %s\n", errno, strerror(errno));
return -1;
}
else if(0 == n_read || 0 == strncmp("exit", buf, 4))
{
printf("client close the connetion\n");
return -1;
}
// printf("client say: %s\n+++++++++++++++++++++++++++++++++++++++++\n", buf);
int b_body, bodylen = 0;
int b_head = 1;
if(0 == strncmp("GET /", buf, 5) || 0 == strncmp("POST /", buf, 6))
{
b_body = 1;
bodylen = strlen(getbody(buf, sizeof(buf)));
}
if(b_head)
{
// printf("server: just do send head\n");
gethead(buf, sizeof(buf), bodylen);
write(fd, buf, strlen(buf));
}
if(b_body)
{
// printf("server:just do send body\n");
getbody(buf, sizeof(buf));
usleep(10*1000); // 10ms
write(fd, buf, strlen(buf));
}
// printf("============================================\n");
return 0;
}
char* gethead(char* buf, size_t sz, int bodylen)
{
if(!buf) return NULL;
char ch_gtm[128];
memset(ch_gtm, '\0', sizeof(ch_gtm));
getgmt(ch_gtm, sizeof(ch_gtm));
snprintf(buf, sz, "HTTP/1.0 200 OK\r\n" \
"Server:YWS/0.0.1\r\n" \
"Content-Length:%d\r\n" \
"Date:%s\r\n" \
"Keep-Alive:timeout=8\r\n" \
"Connection:keep-alive\r\n" \
"Content-Type:text/html\r\n" \
"\r\n",
bodylen,
ch_gtm
);
return buf;
}
char* getbody(char* buf, size_t sz)
{
if(!buf)
return NULL;
snprintf(buf, sz, "<!DOCTYPE html>\r\n" \
"<html>\r\n" \
"<body>\r\n" \
"\t<h1><center>Hello World!</center></h1>\r\n" \
"</body>\r\n" \
"</html>"
);
return buf;
}
char* getgmt(char* buf, size_t sz)
{
if(!buf) return NULL;
time_t now = time(NULL);
strftime(buf, sz, "%a, %d %b %Y %H:%M:%S GMT", gmtime(&now));
return buf;
}
int setnonblocking(int fd)
{
if(0 > fcntl(fd, F_SETFL, fcntl(fd, F_GETFD, 0) | O_NONBLOCK))
{
return -1;
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment