yedongfu
A C++11 non-blocking network library
Example
EventBase events dispatcher
tcp connection
tcp server
http server
half sync half async server
#include <handy/handy.h>
using namespace std;
using namespace handy;
int main(int argc, const char* argv[]) {
EventBase base;
//handle ctrl+c
Signal::signal(SIGINT, [&]{ base.exit(); });
TcpServer echo(&base);
int r = echo.bind("", 2099);
exitif(r, "bind failed %d %s", errno, strerror(errno));
echo.onConnRead([](const TcpConnPtr& con) {
con->send(con->getInput());
});
base.loop(); //enter events loop
}
EventBase base;
//call epoll_wait repeatedly, handle I/O events
base.loop();
//exit events loop, can be called from other threads
base.exit();
bool exited();
TcpConnPtr con = TcpConn::createConnection(&base, host, port);
TcpServer echo(&base);
Some tasks must be called from I/O thread, for example writing some data to connection. In order to avoid conflicting read/write, the operation should be performed in a single thread.
void safeCall(const Task& task);
base.safeCall([](con){con->send("OK");});
EventBase will make itself return by setting a wait time form epoll_wait/kevent. It will check and call timeout tasks. The precision rely on epoll_wait/kevent
//interval: 0:once task;>0:repeated task, task will be execute every interval milliseconds
TimerId runAfter(int64_t milli, const Task& task, int64_t interval=0);
//runAt will specify the absolute time
TimerId runAt(int64_t milli, const Task& task, int64_t interval=0)
//cancel Task, Ignore if task is already removed or expired.
bool cancel(TimerId timerid);
TimerId tid = base.runAfter(1000, []{ info("a second passed"); });
base.cancel(tid);
typedef std::shared_ptr<TcpConn> TcpConnPtr;
enum State { Invalid=1, Handshaking, Connected, Closed, Failed, };
TcpConnPtr con = TcpConn::createConnection(base, host, port);
con->onState([=](const TcpConnPtr& con) {
info("onState called state: %d", con->getState());
});
con->onRead([](const TcpConnPtr& con){
info("recv %lu bytes", con->getInput().size());
con->send("ok");
con->getInput().clear();
});
//set reconnect. -1: no reconnect; 0 :reconnect now; other: wait millisecond; default -1
void setReconnectInterval(int milli);
void addIdleCB(int idle, const TcpCallBack& cb);
//close connection if idle for 30 seconds
con->addIdleCB(30, [](const TcpConnPtr& con)) { con->close(); });
you can onRead or onMsg to handle message
//message callback, confict with onRead callback. You should set only one of these
//codec will be released when connection destroyed
void onMsg(CodecBase* codec, const MsgCallBack& cb);
//send message
void sendMsg(Slice msg);
con->onMsg(new LineCodec, [](const TcpConnPtr& con, Slice msg) {
info("recv msg: %.*s", (int)msg.size(), msg.data());
con->sendMsg("hello");
});
template<class T> T& context();
con->context<std::string>() = "user defined data";
TcpServer echo(&base);
int r = echo.bind("", 2099);
exitif(r, "bind failed %d %s", errno, strerror(errno));
echo.onConnRead([](const TcpConnPtr& con) {
con->send(con->getInput()); // echo data read
});
when TcpServer accept a connection, it will call this to create an TcpConn
void onConnCreate(const std::function<TcpConnPtr()>& cb);
chat.onConnCreate([&]{
TcpConnPtr con(new TcpConn);
con->onState([&](const TcpConnPtr& con) {
if (con->getState() == TcpConn::Connected) {
con->context<int>() = 1;
}
}
return con;
});
//example
HttpServer sample(&base);
int r = sample.bind("", 8081);
exitif(r, "bind failed %d %s", errno, strerror(errno));
sample.onGet("/hello", [](const HttpConnPtr& con) {
HttpResponse resp;
resp.body = Slice("hello world");
con.sendResponse(resp);
});
// empty string indicates unfinished handling of request. You may operate on con as you like.
void onMsg(CodecBase* codec, const RetMsgCallBack& cb);
hsha.onMsg(new LineCodec, [](const TcpConnPtr& con, const string& input){
int ms = rand() % 1000;
info("processing a msg");
usleep(ms * 1000);
return util::format("%s used %d ms", input.c_str(), ms);
});
updating.......