yedf2 / handy Goto Github PK
View Code? Open in Web Editor NEW🔥简洁易用的C++11网络库 / 支持单机千万并发连接 / a simple C++11 network server framework
License: BSD 2-Clause "Simplified" License
🔥简洁易用的C++11网络库 / 支持单机千万并发连接 / a simple C++11 network server framework
License: BSD 2-Clause "Simplified" License
目录代码里面用的是 OS_LINUX 和 OS_MACOSX,我从 StackOverflow 上看到的和这里看到的,分别用 __linux__ 和 __APPLE__ 会不会更好一些呢?
上面问题是我在编译 hany 时,在 handy\poller.cc 和 handy\port_posix.cc 中遇到的。
I noticed that handy supports openssl. But I could not find the example with openssl.
A project should provides the comment in English so that it can be accessed by more developers.
正在学习您的handy库,不明白为什么要用管道来唤醒I/O线程,任务队列不是有条件信号吗,条件等待的时候线程挂起就不占用资源了吧?所以我就是没明白用管道唤醒然后去条件等待的目的
MUDUO作者的测试是高出LIBEVENT有15~20%,请问这为什么?
@yedf2
希望提供一个Windows支持
Hi,
I got the following build error message after changing OPT(OPT ?= -O2 -DNDEBUG) in Makefile.
$ make
g++ -I. -pthread -DOS_LINUX -DLITTLE_ENDIAN=1 -std=c++11 -O2 -DNDEBUG -c ssl/ssl-conn.cc -o ssl/ssl-conn.o
In file included from ./handy/handy-imp.h:2:0,
from ./handy/event_base.h:2,
from ./handy/conn.h:2,
from ./handy/http.h:4,
from ./handy/handy.h:4,
from ssl/ssl-conn.h:2,
from ssl/ssl-conn.cc:1:
ssl/ssl-conn.cc: In lambda function:
./handy/logging.h:30:77: error: expected ‘while’ before ‘}’ token
#define fatalif(b, ...) do { if((b)) { hlog(Logger::LFATAL, __VA_ARGS__); } } while (0)
^
ssl/ssl-conn.cc:29:13: note: in expansion of macro ‘fatalif’
fatalif(!r, "SSL_library_init failed");
^
./handy/logging.h:30:77: error: expected ‘(’ before ‘}’ token
#define fatalif(b, ...) do { if((b)) { hlog(Logger::LFATAL, __VA_ARGS__); } } while (0)
^
.
.
.
客户端拔网线下或kill进程等动作时,代码里没有相应处理逻辑,我在测试时复现了这个问题
在阅读代码的时候看到tcp在send缓冲区满的时候会把发送内容保存到对应的buffer里面去,并设置epoll的write标记等待可写的时候回调再次发送。
为什么对udp没有做这种操作呢?
判断可读可写应该是2个 if 否则会导致读写事件同时出现的时候要2次 epoll_wait才能处理完,另外如果读事件一直出现还会导致写事件一直得不到处理。。简单瞄了一眼。。不知道有没有搞错。。😁😁
struct EventsImp {
EventBase* base_;
PollerBase* poller_;
std::atomic exit_;
int wakeupFds_[2];
......
void EventsImp::init() {
int r = pipe(wakeupFds_);
pipe 一般不是进程间通信用的吗?为什么会用在这里呢?有点奇怪,你也没有开多个进程啊?
Channel* ch = new Channel(base_, wakeupFds_[0], kReadEvent);
通过下面来通知读取的对吧?
void wakeup() {
int r = write(wakeupFds_[1], "", 1);
fatalif(r<=0, "write error wd %d %d %s", r, errno, strerror(errno));
}
不是很了解这套流程啊
在网上搜索网络库的时候,发现了kandf,看readme上没有说支持window,想问下window可以支持下吗
在一个应用程序里面同时启动一个HttpServer和一个TcpServer,不同端口;
是否可行?
如可以,如何实现?
Hi,
I tried to build handy. but I got the error message
"make[1]: *** No rule to make target handy-fw.o', needed by
libhandy.a'. Stop."
Where is handy-fw.cc file ?
valrind to valgrind in README.md
在虚拟机中编译出错,运行环境vm+ubuntu19.10,是因为系统问题吗?
请问你是使用什么ide开发c++,大神?
请问EventBase中有一个EventsImp的unique_ptr成员变量,EventImp中有一个EventBase的指针成员变量这样嵌套的用意是什么?
楼主声明handy是受muduo库启发而写。恰巧不是特别习惯依赖boost的库,因此首选handy,非常欣赏handy的清爽简洁。在与muduo进行比较后有一些小疑问,其中最困惑的是:
为什么没有类似muduo库中 sendinloop 这样的设计?
在eventBase的设计中,有线程池,那很有可能库使用者会使用线程池完成耗时任务(同时将connection传递给工作线程),在任务结束时使用connection发送结果数据。muduo的设计中有 sendinloop 保证关于socket的读写都在同一个loop线程中,不知道为什么handy中没有这样的设计,是有什么特殊考虑吗?
看到设计中有 safeCall,为什么没有 safeSend 这样的设计?😆
mabook:~ vincent$ cat main.cpp
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("", 99);
exitif(r, "bind failed %d %s", errno, strerror(errno));
echo.onConnRead([](const TcpConnPtr& con) {
con->send(con->getInput());
});
base.loop();
//enter events loop
}
mabook:~ vincent$ clang main.cpp -o server -std=c++11
In file included from main.cpp:1:
In file included from /usr/local/include/handy/handy.h:4:
In file included from /usr/local/include/handy/http.h:4:
In file included from /usr/local/include/handy/conn.h:2:
In file included from /usr/local/include/handy/event_base.h:3:
/usr/local/include/handy/poller.h:14:2: error: "platform unsupported"
^
/usr/local/include/handy/poller.h:73:2: error: "platform not supported"
^
2 errors generated.
#include <handy/handy.h>
using namespace std;
using namespace handy;
int main(int argc, const char* argv[]) {
EventBase base; //事件分发器
//注册Ctrl+C的信号处理器 -- 退出事件分发循环
Signal::signal(SIGINT, [&]{ base.exit();});
TcpServer echo(&base); //创建服务器
int r = echo.bind("", 99); //绑定端口
exitif(r, "bind failed %d %s", errno,strerror(errno));
echo.onConnRead([](const TcpConnPtr& con) {
con->send(con->getInput()); //echo 读取的数据
});
base.loop(); //进入事件分发循环
}
clang++ -std=c++11 demo.cpp -omain
In file included from echo.cpp:1:
In file included from /usr/local/include/handy/handy.h:4:
In file included from /usr/local/include/handy/http.h:4:
In file included from /usr/local/include/handy/conn.h:2:
In file included from /usr/local/include/handy/event_base.h:3:
/usr/local/include/handy/poller.h:14:2: error: "platform unsupported"
^
/usr/local/include/handy/poller.h:73:2: error: "platform not supported"
\r\n
额,我仔细计算了下,没有问题。。
单机并发千万,个人觉得"并发"一词用法不当,千万这个我猜对应的应该是多网卡物理机的qps,这个不叫并发。
要真并发千万,你一台物理机瞬间就给你压挂了。
你的千万应该指的是QPS吧,而且是长连接的qps(长链接估计也到不了,网卡队列软中断会消耗大量CPU),短连接qps更不可能到千万。
每个连接都要耗几十K内存,千万qps你内存也早爆了,CPU也抗不住的。
京东这种电商双11规模估计也才千万并发,并发的意思楼主可能误解了。
handy/threads.h文件中:
std::vector<std::thread> threads_;
handy/threads.cc文件中:
ThreadPool::ThreadPool(int threads, int maxWaiting, bool start):
tasks_(maxWaiting), threads_(threads)
{
if (start) {
this->start();
}
}
这里初始化列表对于threads_的初始化是否存在问题??求解答。
使用echo来ping_pong测试,5万个连接,没有任何信息程序就退出了,没有打印异常信息
这是为什么呢??
系统参数都是修改过了的。
ping_pong:连接建立后以8K数据向服务器发数据然后再收,收到服务器数据后再发,中间不停顿这样循环,来测试处理能力
如题所述。
看见了 HSHA ,这个就是 tcp server 的多线程封装吗?
请问为什么称为半同步半异步服务器?
int fd = channel_->fd();
ssize_t rn = recvfrom(fd, buf.makeRoom(kUdpPacketSize), buf.space(), 0, (sockaddr*)&raddr, &rsz);
if (rn < 0) {
error("udp %d recv failed: %d %s", fd, errno, strerror(errno));
return;
}
buf.addSize(rn); //测试到有时recvfrom返回为0,即rn=0,addSize就会把buf内存搞砸
trace("udp %d recv %ld bytes from %s", fd, rn, Ip4Addr(raddr).toString().data());
this->msgcb_(shared_from_this(), buf, raddr);
释放内存错误*** Error in
./udp-cli': double free or corruption (top): 0x0000000000f555e0 ***`
顺带问一下,什么情况下recvfrom返回0? 设定了非阻塞模式?我抓包看一下发送端
template struct SafeQueue: private std::mutex, private noncopyable,在threadpool.h 14 行。 完全不懂?为何不直接添加一个mutex成员呢?
There are some issues of code quality. Like createPoller()
returns a pointer to a poller which locates heap.
And we should fix these issues. If you think there are code quality issues, please comment in this issue. Thanks a lot.
I think we should re write the comment in English because I found that there are some foreigners followed this repo.
And if we write the comments in English, I believe that there are more and more international developers get involved in this.
https://www.oschina.net/p/c11-handy
关于测试性能对比那里,nginx配置
worker_processes=1
location /hello {
echo "hello world!"
}
这里为worker数量为啥配置成1呢,t420 应该是双核吧。master作为io进程基本消耗不了多少cpu,所以cpu打不满。能测试下worker_processes=2情况下的数据么,以及各个测试系统资源情况
想问一下有没有什么已知的项目在使用这个库呢?
非阻塞+ET模式下,在handleAccept中接受连接不应该是用一个循环包围吗?像这样:
void handleAccept(int efd, int fd)
{
struct sockaddr_in raddr;
socklen_t rsz = sizeof(raddr);
while(1)
{
int cfd = accept(fd,(struct sockaddr *)&raddr,&rsz);
//exit_if(cfd<0, "accept failed");
if(cfd == -1)
{
if(errno == EAGAIN || errno == EWOULDBLOCK)
{
/* 接受了所有连接,退出循环 */
fprintf(stdout, "Accept all connect request\n");
break;
}
}
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);
}
}
Buffer对象是线程安全的吗?
A project should provides the comment in English so that it can be accessed by more developers.
您好,handleWrite是epoll触发的被动可写事件处理函数,send是主动写事件的处理函数,请问两者有冲突吗?或者为什么要有两种处理函数?
addSize不做越界检查,可能会存在buffer空间不够的情况越界访问吧。
如果空间超过exp_, 应该做相应的处理。
/tmp/ccrj5xT1.o: In function main::{lambda()#1}::operator()() const': me.cpp:(.text+0xbd): undefined reference to
handy::EventBase::exit()'
/tmp/ccrj5xT1.o: In function main::{lambda(std::shared_ptr<handy::TcpConn> const&)#2}::operator()(std::shared_ptr<handy::TcpConn> const&) const': me.cpp:(.text+0xff): undefined reference to
handy::TcpConn::send(handy::Buffer&)'
/tmp/ccrj5xT1.o: In function main': me.cpp:(.text+0x136): undefined reference to
handy::EventBase::EventBase(int)'
me.cpp:(.text+0x166): undefined reference to handy::Signal::signal(int, std::function<void ()> const&)' me.cpp:(.text+0x1bd): undefined reference to
handy::TcpServer::startServer(handy::EventBases*, std::__cxx11::basic_string<char, std::char_traits, std::allocator > const&, unsigned short, bool)'
me.cpp:(.text+0x1f2): undefined reference to handy::Logger::getLogger()' me.cpp:(.text+0x223): undefined reference to
handy::Logger::getLogger()'
me.cpp:(.text+0x24f): undefined reference to handy::Logger::logv(int, char const*, int, char const*, char const*, ...)' me.cpp:(.text+0x2ab): undefined reference to
handy::EventBase::loop()'
me.cpp:(.text+0x2c9): undefined reference to handy::EventBase::~EventBase()' me.cpp:(.text+0x33d): undefined reference to
handy::EventBase::~EventBase()'
collect2: error: ld returned 1 exit status
Poller的removeChannel(Channnel* channel)中,删除channel为什么只需要将activeEvs_中的对应的channel置为NULL?
if (events & (EPOLLIN | EPOLLERR)) {
if (fd == lfd) {
handleAccept(efd, fd);
} else {
handleRead(efd, fd);
}
} else if (events & EPOLLOUT) {
if (output_log)
printf("handling epollout\n");
handleWrite(efd, fd);
当Socket读和写都返回了EAGAIN,epoll_wait返回时EPOLLIN和EPOLLOUT可能同时有效,由于使用if判断EPOLLIN+else if判断EPOLLOUT,所以只有handleRead分支被执行了,handleWrite分支未得到执行。由于是边沿触发,socket可写事件被触发一次之后不会再被触发。
我正在看你的代码,想知道应该以什么顺序阅读?哪几个文件先看,哪些后看?谢谢了
感谢作者贡献的handy。
handy的日志是采用write(O_APPEND)的方式,非常简洁并且这种方式又可以保证原子,但是如题,handy的日志只是在本线程写,那么当这个线程需要写大量的日志时,即大量调用write(2)的时候,会不会对它的处理来说是一种负担?所以作者有将日志做成异步的考虑吗?
理论上解析成功了就可以拷贝了, 这样 buffer 就可以自己回收了
When a client closes its connection, when the server destroy the TcpConn?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.