Created
December 2, 2015 01:37
-
-
Save jorben/d5526c5cdd5a58964d78 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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