forked from yedf2/handy
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
yedf
committed
Mar 12, 2016
1 parent
3d1a94d
commit ad59000
Showing
7 changed files
with
411 additions
and
2 deletions.
There are no files selected for viewing
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
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
#pragma once | ||
#include "string.h" | ||
#include <string.h> | ||
#include <string> | ||
#include <vector> | ||
|
||
|
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
SOURCES = $(shell ls *.cc) | ||
|
||
PROGRAMS = $(SOURCES:.cc=) | ||
|
||
default: | ||
@echo make \<program\> [ program can be \"$(PROGRAMS)\" ] | ||
|
||
clean: | ||
-rm -f $(PROGRAMS) | ||
-rm -f *.o | ||
|
||
.cc.o: | ||
$(CXX) $(CXXFLAGS) -c $< -o $@ | ||
|
||
.c.o: | ||
$(CC) $(CFLAGS) -c $< -o $@ | ||
|
||
.cc: | ||
$(CXX) -o $@ $< $(CXXFLAGS) $(LDFLAGS) | ||
|
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
#include <sys/socket.h> | ||
#include <sys/epoll.h> | ||
#include <netinet/in.h> | ||
#include <arpa/inet.h> | ||
#include <fcntl.h> | ||
#include <unistd.h> | ||
#include <stdio.h> | ||
#include <errno.h> | ||
#include <string.h> | ||
#include <stdlib.h> | ||
#include <map> | ||
#include <string> | ||
using namespace std; | ||
#define exit_if(r, ...) if(r) {printf(__VA_ARGS__); printf("error no: %d error msg %s\n", errno, strerror(errno)); exit(1);} | ||
|
||
void setNonBlock(int fd) { | ||
int flags = fcntl(fd, F_GETFL, 0); | ||
exit_if(flags<0, "fcntl failed"); | ||
int r = fcntl(fd, F_SETFL, flags | O_NONBLOCK); | ||
exit_if(r<0, "fcntl failed"); | ||
} | ||
|
||
void updateEvents(int efd, int fd, int events, int op) { | ||
struct epoll_event ev; | ||
memset(&ev, 0, sizeof(ev)); | ||
ev.events = events | EPOLLET; | ||
ev.data.fd = fd; | ||
printf("%s fd %d events read %d write %d\n", | ||
op==EPOLL_CTL_MOD?"mod":"add", fd, ev.events & EPOLLIN, ev.events & EPOLLOUT); | ||
int r = epoll_ctl(efd, op, fd, &ev); | ||
exit_if(r, "epoll_ctl failed"); | ||
} | ||
|
||
void handleAccept(int efd, int fd) { | ||
struct sockaddr_in raddr; | ||
socklen_t rsz = sizeof(raddr); | ||
int cfd = accept(fd,(struct sockaddr *)&raddr,&rsz); | ||
exit_if(cfd<0, "accept failed"); | ||
sockaddr_in peer, local; | ||
socklen_t alen = sizeof(peer); | ||
int r = getpeername(cfd, (sockaddr*)&peer, &alen); | ||
exit_if(r<0, "getpeername failed"); | ||
printf("accept a connection from %s\n", inet_ntoa(raddr.sin_addr)); | ||
setNonBlock(cfd); | ||
updateEvents(efd, cfd, EPOLLIN|EPOLLOUT, EPOLL_CTL_ADD); | ||
} | ||
struct Con { | ||
string readed; | ||
size_t written; | ||
Con(): written(0) {} | ||
}; | ||
map<int, Con> cons; | ||
|
||
string httpRes; | ||
void sendRes(int fd) { | ||
Con& con = cons[fd]; | ||
if (!con.readed.length()) | ||
return; | ||
size_t left = httpRes.length() - con.written; | ||
int wd = 0; | ||
while((wd=::write(fd, httpRes.data()+con.written, left))>0) { | ||
con.written += wd; | ||
left -= wd; | ||
printf("write %d bytes left: %lu\n", wd, left); | ||
}; | ||
if (left == 0) { | ||
close(fd); | ||
cons.erase(fd); | ||
return; | ||
} | ||
if (wd < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) | ||
return; | ||
exit_if(wd<=0, "write error"); | ||
} | ||
|
||
void handleRead(int efd, int fd) { | ||
char buf[4096]; | ||
int n = 0; | ||
while ((n=::read(fd, buf, sizeof buf)) > 0) { | ||
printf("read %d bytes\n", n); | ||
string& readed = cons[fd].readed; | ||
readed.append(buf, n); | ||
if (readed.length()>4) { | ||
if (readed.substr(readed.length()-2, 2) == "\n\n" || readed.substr(readed.length()-4, 4) == "\r\n\r\n") { | ||
sendRes(fd); | ||
} | ||
} | ||
} | ||
if (n<0 && (errno == EAGAIN || errno == EWOULDBLOCK)) | ||
return; | ||
exit_if(n<0, "read error"); //实际应用中,n<0应当检查各类错误,如EINTR | ||
printf("fd %d closed\n", fd); | ||
close(fd); | ||
} | ||
|
||
void handleWrite(int efd, int fd) { | ||
sendRes(fd); | ||
} | ||
|
||
void loop_once(int efd, int lfd, int waitms) { | ||
const int kMaxEvents = 20; | ||
struct epoll_event activeEvs[100]; | ||
int n = epoll_wait(efd, activeEvs, kMaxEvents, waitms); | ||
printf("epoll_wait return %d\n", n); | ||
for (int i = 0; i < n; i ++) { | ||
int fd = activeEvs[i].data.fd; | ||
int events = activeEvs[i].events; | ||
if (events & (EPOLLIN | EPOLLERR)) { | ||
if (fd == lfd) { | ||
handleAccept(efd, fd); | ||
} else { | ||
handleRead(efd, fd); | ||
} | ||
} else if (events & EPOLLOUT) { | ||
printf("handling epollout\n"); | ||
handleWrite(efd, fd); | ||
} else { | ||
exit_if(1, "unknown event"); | ||
} | ||
} | ||
} | ||
|
||
int main() { | ||
httpRes = "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\nContent-Length: 1048576\r\n\r\n123456"; | ||
for(int i=0;i<1048570;i++) { | ||
httpRes+='\0'; | ||
} | ||
short port = 80; | ||
int epollfd = epoll_create(1); | ||
exit_if(epollfd < 0, "epoll_create failed"); | ||
int listenfd = socket(AF_INET, SOCK_STREAM, 0); | ||
exit_if(listenfd < 0, "socket failed"); | ||
struct sockaddr_in addr; | ||
memset(&addr, 0, sizeof addr); | ||
addr.sin_family = AF_INET; | ||
addr.sin_port = htons(port); | ||
addr.sin_addr.s_addr = INADDR_ANY; | ||
int r = ::bind(listenfd,(struct sockaddr *)&addr, sizeof(struct sockaddr)); | ||
exit_if(r, "bind to 0.0.0.0:%d failed %d %s", port, errno, strerror(errno)); | ||
r = listen(listenfd, 20); | ||
exit_if(r, "listen failed %d %s", errno, strerror(errno)); | ||
printf("fd %d listening at %d\n", listenfd, port); | ||
setNonBlock(listenfd); | ||
updateEvents(epollfd, listenfd, EPOLLIN, EPOLL_CTL_ADD); | ||
for (;;) { //实际应用应当注册信号处理函数,退出时清理资源 | ||
loop_once(epollfd, listenfd, 10000); | ||
} | ||
return 0; | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
#include <sys/socket.h> | ||
#include <sys/epoll.h> | ||
#include <netinet/in.h> | ||
#include <arpa/inet.h> | ||
#include <fcntl.h> | ||
#include <unistd.h> | ||
#include <stdio.h> | ||
#include <errno.h> | ||
#include <string.h> | ||
#include <stdlib.h> | ||
|
||
#define exit_if(r, ...) if(r) {printf(__VA_ARGS__); printf("error no: %d error msg %s\n", errno, strerror(errno)); exit(1);} | ||
|
||
void setNonBlock(int fd) { | ||
int flags = fcntl(fd, F_GETFL, 0); | ||
exit_if(flags<0, "fcntl failed"); | ||
int r = fcntl(fd, F_SETFL, flags | O_NONBLOCK); | ||
exit_if(r<0, "fcntl failed"); | ||
} | ||
|
||
void updateEvents(int efd, int fd, int events, int op) { | ||
struct epoll_event ev; | ||
memset(&ev, 0, sizeof(ev)); | ||
ev.events = events; | ||
ev.data.fd = fd; | ||
printf("%s fd %d events read %d write %d\n", | ||
op==EPOLL_CTL_MOD?"mod":"add", fd, ev.events & EPOLLIN, ev.events & EPOLLOUT); | ||
int r = epoll_ctl(efd, op, fd, &ev); | ||
exit_if(r, "epoll_ctl failed"); | ||
} | ||
|
||
void handleAccept(int efd, int fd) { | ||
struct sockaddr_in raddr; | ||
socklen_t rsz = sizeof(raddr); | ||
int cfd = accept(fd,(struct sockaddr *)&raddr,&rsz); | ||
exit_if(cfd<0, "accept failed"); | ||
sockaddr_in peer, local; | ||
socklen_t alen = sizeof(peer); | ||
int r = getpeername(cfd, (sockaddr*)&peer, &alen); | ||
exit_if(r<0, "getpeername failed"); | ||
printf("accept a connection from %s\n", inet_ntoa(raddr.sin_addr)); | ||
setNonBlock(cfd); | ||
updateEvents(efd, cfd, EPOLLIN|EPOLLOUT, EPOLL_CTL_ADD); | ||
} | ||
|
||
void handleRead(int efd, int fd) { | ||
char buf[4096]; | ||
int n = 0; | ||
while ((n=::read(fd, buf, sizeof buf)) > 0) { | ||
printf("read %d bytes\n", n); | ||
int r = ::write(fd, buf, n); //写出读取的数据 | ||
//实际应用中,写出数据可能会返回EAGAIN,此时应当监听可写事件,当可写时再把数据写出 | ||
exit_if(r<=0, "write error"); | ||
} | ||
if (n<0 && (errno == EAGAIN || errno == EWOULDBLOCK)) | ||
return; | ||
exit_if(n<0, "read error"); //实际应用中,n<0应当检查各类错误,如EINTR | ||
printf("fd %d closed\n", fd); | ||
close(fd); | ||
} | ||
|
||
void handleWrite(int efd, int fd) { | ||
//实际应用应当实现可写时写出数据,无数据可写才关闭可写事件 | ||
updateEvents(efd, fd, EPOLLIN, EPOLL_CTL_MOD); | ||
} | ||
|
||
void loop_once(int efd, int lfd, int waitms) { | ||
const int kMaxEvents = 20; | ||
struct epoll_event activeEvs[100]; | ||
int n = epoll_wait(efd, activeEvs, kMaxEvents, waitms); | ||
printf("epoll_wait return %d\n", n); | ||
for (int i = 0; i < n; i ++) { | ||
int fd = activeEvs[i].data.fd; | ||
int events = activeEvs[i].events; | ||
if (events & (EPOLLIN | EPOLLERR)) { | ||
if (fd == lfd) { | ||
handleAccept(efd, fd); | ||
} else { | ||
handleRead(efd, fd); | ||
} | ||
} else if (events & EPOLLOUT) { | ||
handleWrite(efd, fd); | ||
} else { | ||
exit_if(1, "unknown event"); | ||
} | ||
} | ||
} | ||
|
||
int main() { | ||
short port = 99; | ||
int epollfd = epoll_create(1); | ||
exit_if(epollfd < 0, "epoll_create failed"); | ||
int listenfd = socket(AF_INET, SOCK_STREAM, 0); | ||
exit_if(listenfd < 0, "socket failed"); | ||
struct sockaddr_in addr; | ||
memset(&addr, 0, sizeof addr); | ||
addr.sin_family = AF_INET; | ||
addr.sin_port = htons(port); | ||
addr.sin_addr.s_addr = INADDR_ANY; | ||
int r = ::bind(listenfd,(struct sockaddr *)&addr, sizeof(struct sockaddr)); | ||
exit_if(r, "bind to 0.0.0.0:%d failed %d %s", port, errno, strerror(errno)); | ||
r = listen(listenfd, 20); | ||
exit_if(r, "listen failed %d %s", errno, strerror(errno)); | ||
printf("fd %d listening at %d\n", listenfd, port); | ||
setNonBlock(listenfd); | ||
updateEvents(epollfd, listenfd, EPOLLIN, EPOLL_CTL_ADD); | ||
for (;;) { //实际应用应当注册信号处理函数,退出时清理资源 | ||
loop_once(epollfd, listenfd, 10000); | ||
} | ||
return 0; | ||
} |
Oops, something went wrong.