Skip to content

Commit

Permalink
add raw-examples
Browse files Browse the repository at this point in the history
  • Loading branch information
yedf committed Mar 12, 2016
1 parent 3d1a94d commit ad59000
Show file tree
Hide file tree
Showing 7 changed files with 411 additions and 2 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ examples/http-echo
examples/log
examples/stat
examples/write-on-empty
raw-examples/epoll
raw-examples/epoll-et
raw-examples/kqueue
handy_test
protobuf/middle
protobuf/test
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ int main(int argc, const char* argv[]) {
###目录结构
* handy--------handy库
* examples----示例
* examples----示例
* raw-examples--原生api使用示例,包括了epoll,epoll ET模式,kqueue示例
* ssl------------openssl相关的代码与示例
* protobuf-----handy使用protobuf的示例
* test-----------handy相关的测试
Expand Down
2 changes: 1 addition & 1 deletion handy/slice.h
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>

Expand Down
20 changes: 20 additions & 0 deletions raw-examples/Makefile
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)

149 changes: 149 additions & 0 deletions raw-examples/epoll-et.cc
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;
}
111 changes: 111 additions & 0 deletions raw-examples/epoll.cc
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;
}
Loading

0 comments on commit ad59000

Please sign in to comment.