Created
March 17, 2014 14:47
-
-
Save cadl/9600632 to your computer and use it in GitHub Desktop.
simple_server2
This file contains hidden or 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
#define MAX_EVENTS 512 | |
#define LOCK_NAME ".server.lock" | |
#include <unistd.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <errno.h> | |
#include <signal.h> | |
#include <assert.h> | |
#include <sys/types.h> | |
#include <sys/wait.h> | |
#include <sys/file.h> | |
#include <sys/socket.h> | |
#include <sys/epoll.h> | |
#include <netinet/in.h> | |
struct worker_proc { | |
pid_t pid; | |
struct worker_proc *next; | |
}root; | |
void sig_handler(int sig) { | |
struct worker_proc* wp = &root; | |
if (sig == SIGINT) { | |
while (wp) { | |
kill(wp->pid, SIGINT); | |
wp = wp->next; | |
} | |
} | |
} | |
static inline int acquire_lock(char *file_name) { | |
int lockfd; | |
if ((lockfd = open(file_name, O_CREAT|O_RDWR, 0666)) < 0) { | |
return -1; | |
} | |
if (flock(lockfd, LOCK_NB|LOCK_EX) < 0) { | |
close(lockfd); | |
return -1; | |
} | |
return lockfd; | |
} | |
static inline void release_lock(int lockfd) { | |
flock(lockfd, LOCK_UN); | |
close(lockfd); | |
} | |
static int setnonblock(int fd) { | |
int flags, s; | |
flags = fcntl(fd, F_GETFL, 0); | |
if (flags == -1) { | |
perror("fcntl get flag"); | |
return -1; | |
} | |
flags |= O_NONBLOCK; | |
s = fcntl(fd, F_SETFL, flags); | |
if (s == -1) { | |
perror("fcntl set flags"); | |
return -1; | |
} | |
return 0; | |
} | |
void worker_proc_read(int fd) { | |
int nread; | |
char read_buf[512]; | |
while ((nread = read(fd, read_buf, 512)) > 0) { | |
read_buf[nread] = '\0'; | |
} | |
if (nread == -1 && errno != EAGAIN) { | |
perror("read error"); | |
} | |
} | |
void worker_proc_write(int fd) { | |
int nwrite, data_size, n; | |
char write_buf[256] = "HTTP/1.1 200 OK\r\nContent-Length: 11\r\n\r\nHello World"; | |
data_size = strlen(write_buf); | |
n = data_size; | |
while (n > 0) { | |
nwrite = write(fd, write_buf+data_size-n, n); | |
if (nwrite < n) { | |
if (nwrite == -1 && errno != EAGAIN) { | |
perror("write errpr"); | |
return; | |
} | |
break; | |
} | |
n -= nwrite; | |
} | |
close(fd); | |
} | |
void worker_proc_loop(int listen_fd) { | |
struct epoll_event ev, events[MAX_EVENTS]; | |
int epollfd, nfds, connfd; | |
int lockfd, fd; | |
struct sockaddr_in client_addr; | |
socklen_t length = sizeof(client_addr); | |
epollfd = epoll_create(10); | |
if (epollfd == -1) { | |
perror("epoll_create"); | |
exit(EXIT_FAILURE); | |
} | |
for (;;) { | |
lockfd = acquire_lock(LOCK_NAME); | |
if (lockfd != -1) { | |
ev.events = EPOLLIN | EPOLLET; | |
ev.data.fd = listen_fd; | |
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, listen_fd, &ev) == -1) { | |
perror("epoll_ctl: listen_sock"); | |
exit(EXIT_FAILURE); | |
} | |
} | |
nfds = epoll_wait(epollfd, events, MAX_EVENTS, 100); | |
if (nfds == -1) { | |
perror("epoll_wait"); | |
exit(EXIT_FAILURE); | |
} | |
printf("lock %d %d %d\n", lockfd, getpid(), nfds); | |
for (int i=0; i<nfds; i++) { | |
fd = events[i].data.fd; | |
if (fd == listen_fd) { | |
while ((connfd = accept(listen_fd, | |
(struct sockaddr *)&client_addr, | |
&length)) > 0) { | |
if (setnonblock(connfd) == -1) { | |
perror("nonblock"); | |
exit(EXIT_FAILURE); | |
} | |
ev.events = EPOLLIN| EPOLLET; | |
ev.data.fd = connfd; | |
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, connfd, &ev) == -1) { | |
perror("epoll_ctl: conn_sock"); | |
exit(EXIT_FAILURE); | |
} | |
} | |
if (connfd == -1) { | |
if (errno != EAGAIN && errno != ECONNABORTED | |
&& errno != EPROTO && errno != EINTR) { | |
perror("accept"); | |
} | |
} | |
} | |
else | |
{ | |
if (events[i].events & EPOLLIN) { | |
worker_proc_read(fd); | |
ev.data.fd = fd; | |
ev.events = events[i].events | EPOLLOUT; | |
if (epoll_ctl(epollfd, EPOLL_CTL_MOD, fd, &ev) == -1) { | |
perror("epoll_ctl: mode"); | |
exit(EXIT_FAILURE); | |
} | |
} | |
if (events[i].events & EPOLLOUT) { | |
worker_proc_write(fd); | |
} | |
} | |
} | |
if (lockfd != -1) { | |
ev.data.fd = listen_fd; | |
ev.events = EPOLLIN; | |
epoll_ctl(epollfd, EPOLL_CTL_DEL, listen_fd, &ev); | |
release_lock(lockfd); | |
} | |
} | |
} | |
struct worker_proc* worker_proc_new(int listen_fd){ | |
pid_t pid; | |
struct worker_proc *wp, *tmp; | |
wp = &root; | |
pid = fork(); | |
assert(pid >= 0); | |
if (pid > 0) { | |
while (wp->next) { | |
wp = wp->next; | |
} | |
tmp = (struct worker_proc *)malloc(sizeof(struct worker_proc)); | |
tmp->pid = pid; | |
tmp->next = NULL; | |
wp->next = tmp; | |
return wp; | |
} | |
else { | |
worker_proc_loop(listen_fd); | |
return NULL; | |
} | |
} | |
int main() { | |
int server_fd, wait_status; | |
struct sockaddr_in server_addr; | |
memset(&server_addr, 0, sizeof(server_addr)); | |
server_addr.sin_family = AF_INET; | |
server_addr.sin_addr.s_addr = htons(INADDR_ANY); | |
server_addr.sin_port = htons(8888); | |
server_fd = socket(AF_INET, SOCK_STREAM, 0); | |
if (server_fd < 0) { | |
perror("socket"); | |
exit(EXIT_FAILURE); | |
} | |
if (setnonblock(server_fd) == -1) { | |
perror("nonblock"); | |
exit(EXIT_FAILURE); | |
} | |
if (bind(server_fd, (struct sockaddr *)&server_addr, | |
sizeof(server_addr)) < 0) { | |
perror("bind"); | |
exit(EXIT_FAILURE); | |
} | |
if (listen(server_fd, 5) < 0) { | |
perror("listen"); | |
exit(EXIT_FAILURE); | |
} | |
for (int i=0; i<4; i++) { | |
worker_proc_new(server_fd); | |
} | |
close(server_fd); | |
for (int i=0; i<4; i++) { | |
wait(&wait_status); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment