在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
开源软件名称(OpenSource Name):iqiyi/libfiber开源软件地址(OpenSource Url):https://github.com/iqiyi/libfiber开源编程语言(OpenSource Language):C++ 38.9%开源软件介绍(OpenSource Introduction):The high performance coroutine library, supporting Linux/BSD/Mac/WindowsAboutThe libfiber project comes from the coroutine module of the acl project in lib_fiber directory of which. It can be used on OS platfroms including Linux, FreeBSD, MacOS, and Windows, which supports select, poll, epoll, kqueue, iocp, and even Windows GUI messages for different platfrom. With libfiber, you can write network application services having the high performance and large cocurrent more easily than the traditional asynchronus framework with event-driven model. What's more, with the help of libfiber, you can even write network module of the Windows GUI application written by MFC, wtl or other GUI framework on Windows in coroutine way. That's realy amazing. Which IO events are supported ?The libfiber supports many events including select/poll/epoll/kqueue/iocp, and Windows GUI messages.
SAMPLESOne server sample with C API// fiber_server.c
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "fiber/lib_fiber.h"
#include "patch.h" // in the samples path
static size_t __stack_size = 128000;
static const char *__listen_ip = "127.0.0.1";
static int __listen_port = 9001;
static void fiber_client(ACL_FIBER *fb, void *ctx)
{
SOCKET *pfd = (SOCKET *) ctx;
char buf[8192];
while (1) {
#if defined(_WIN32) || defined(_WIN64)
int ret = acl_fiber_recv(*pfd, buf, sizeof(buf), 0);
#else
int ret = recv(*pfd, buf, sizeof(buf), 0);
#endif
if (ret == 0) {
break;
} else if (ret < 0) {
if (acl_fiber_last_error() == FIBER_EINTR) {
continue;
}
break;
}
#if defined(_WIN32) || defined(_WIN64)
if (acl_fiber_send(*pfd, buf, ret, 0) < 0) {
#else
if (send(*pfd, buf, ret, 0) < 0) {
#endif
break;
}
}
socket_close(*pfd);
free(pfd);
}
static void fiber_accept(ACL_FIBER *fb, void *ctx)
{
const char *addr = (const char *) ctx;
SOCKET lfd = socket_listen(__listen_ip, __listen_port);
assert(lfd >= 0);
for (;;) {
SOCKET *pfd, cfd = socket_accept(lfd);
if (cfd == INVALID_SOCKET) {
printf("accept error %s\r\n", acl_fiber_last_serror());
break;
}
pfd = (SOCKET *) malloc(sizeof(SOCKET));
*pfd = cfd;
// create and start one fiber to handle the client socket IO
acl_fiber_create(fiber_client, pfd, __stack_size);
}
socket_close(lfd);
exit (0);
}
// FIBER_EVENT_KERNEL represents the event type on
// Linux(epoll), BSD(kqueue), Mac(kqueue), Windows(iocp)
// FIBER_EVENT_POLL: poll on Linux/BSD/Mac/Windows
// FIBER_EVENT_SELECT: select on Linux/BSD/Mac/Windows
// FIBER_EVENT_WMSG: Win GUI message on Windows
// acl_fiber_create/acl_fiber_schedule_with are in `lib_fiber.h`.
// socket_listen/socket_accept/socket_close are in patch.c of the samples path.
int main(void)
{
int event_mode = FIBER_EVENT_KERNEL;
#if defined(_WIN32) || defined(_WIN64)
socket_init();
#endif
// create one fiber to accept connections
acl_fiber_create(fiber_accept, NULL, __stack_size);
// start the fiber schedule process
acl_fiber_schedule_with(event_mode);
#if defined(_WIN32) || defined(_WIN64)
socket_end();
#endif
return 0;
} One client sample with C API// fiber_client.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "fiber/lib_fiber.h"
#include "patch.h" // in the samples path
static const char *__server_ip = "127.0.0.1";
static int __server_port = 9001;
// socket_init/socket_end/socket_connect/socket_close are in patch.c of the samples path
static void fiber_client(ACL_FIBER *fb, void *ctx)
{
SOCKET cfd = socket_connect(__server_ip, __server_port);
const char *s = "hello world\r\n";
char buf[8192];
int i, ret;
if (cfd == INVALID_SOCKET) {
return;
}
for (i = 0; i < 1024; i++) {
#if defined(_WIN32) || defined(_WIN64)
if (acl_fiber_send(cfd, s, strlen(s), 0) <= 0) {
#else
if (send(cfd, s, strlen(s), 0) <= 0) {
#endif
printf("send error %s\r\n", acl_fiber_last_serror());
break;
}
#if defined(_WIN32) || defined(_WIN64)
ret = acl_fiber_recv(cfd, buf, sizeof(buf), 0);
#else
ret = recv(cfd, buf, sizeof(buf), 0);
#endif
if (ret <= 0) {
break;
}
}
#if defined(_WIN32) || defined(_WIN64)
acl_fiber_close(cfd);
#else
close(cfd);
#endif
}
int main(void)
{
int event_mode = FIBER_EVENT_KERNEL;
size_t stack_size = 128000;
int i;
#if defined(_WIN32) || defined(_WIN64)
socket_init();
#endif
for (i = 0; i < 100; i++) {
acl_fiber_create(fiber_client, NULL, stack_size);
}
acl_fiber_schedule_with(event_mode);
#if defined(_WIN32) || defined(_WIN64)
socket_end();
#endif
return 0;
} Resolve domain address in coroutineThe rfc1035 for DNS has been implement in libfiber, so you can call gethostbyname or getaddrinfo to get the givent domain's IP addresses in coroutine. #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include "fiber/lib_fiber.h"
static void lookup(ACL_FIBER *fiber, void *ctx) {
char *name = (char *) ctx;
struct addrinfo hints, *res0;
int ret;
(void) fiber; // avoid compiler warning
memset(&hints, 0, sizeof(hints));
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG;
ret = getaddrinfo(name, "80", &hints, &res0);
free(name);
if (ret != 0) {
printf("getaddrinfo error %s\r\n", gai_strerror(ret));
} else {
printf("getaddrinfo ok\r\n");
freeaddrinfo(res0);
}
}
int main(void) {
char *name1 = strdup("www.iqiyi.com");
char *name2 = strdup("www.baidu.com");
acl_fiber_create(lookup, name1, 128000);
acl_fiber_create(lookup, name2, 128000);
acl_fiber_schedule();
return 0;
} Create fiber with standard C++ APIYou can create one coroutine with standard C++ API in libfiber: #include <stdio.h>
#include "fiber/libfiber.hpp"
class myfiber : public acl::fiber {
public:
myfiber(void) {}
private:
~myfiber(void) {}
protected:
// @override from acl::fiber
void run(void) {
printf("hello world!\r\n");
delete this;
}
};
int main(void) {
for (int i = 0; i < 10; i++) {
acl::fiber* fb = new myfiber();
fb->start();
}
acl::fiber::schedule();
return 0;
} Create fiber with C++1x APIYou can also create one coroutine with c++11 API in libfiber: #include <stdio.h>
#include "fiber/libfiber.hpp"
#include "fiber/go_fiber.hpp"
static void fiber_routine(int i) {
printf("hi, i=%d, curr fiber=%u\r\n", i, acl::fiber::self());
}
int main(void) {
for (int i = 0; i < 10; i++) {
go[=] {
fiber_routine(i);
};
}
acl::fiber::schedule();
return 0;
} Wait for the result from a thread#include <stdio.h>
#include <unistd.h>
#include "fiber/go_fiber.hpp"
static void fiber_routine(int i) {
go_wait[&] { // running in another thread
i += 100;
usleep(10000);
};
printf("i is %d\r\n", i);
}
int main(void) {
// create ten fibers
for (int i = 0; i < 10; i++) {
go[=] {
fiber_routine(i);
};
}
acl::fiber::schedule();
return 0;
} Http server supporting http url routeOne http server written with libfiber and http module of acl supports http handler route which is in http server. #include <acl-lib/acl_cpp/lib_acl.hpp> // must before http_server.hpp
#include <acl-lib/fiber/http_server.hpp>
static char *var_cfg_debug_msg;
static acl::master_str_tbl var_conf_str_tab[] = {
{ "debug_msg", "test_msg", &var_cfg_debug_msg },
{ 0, 0, 0 }
};
static int var_cfg_io_timeout;
static acl::master_int_tbl var_conf_int_tab[] = {
{ "io_timeout", 120, &var_cfg_io_timeout, 0, 0 },
{ 0, 0 , 0 , 0, 0 }
};
int main(void) {
acl::acl_cpp_init();
acl::http_server server;
// set the configure variables
server.set_cfg_int(var_conf_int_tab)
.set_cfg_str(var_conf_str_tab);
// set http handler route
server.Get("/", [](acl::HttpRequest&, acl::HttpResponse& res) {
acl::string buf("hello world1!\r\n");
res.setContentLength(buf.size());
return res.write(buf.c_str(), buf.size());
}).Post("/ok", [](acl::HttpRequest& req, acl::HttpResponse& res) {
acl::string buf;
req.getBody(buf);
res.setContentLength(buf.size());
return res.write(buf.c_str(), buf.size());
}).Get("/json", [&](acl::HttpRequest&, acl::HttpResponse& res) {
acl::json json;
acl::json_node& root = json.get_root();
root.add_number("code", 200)
.add_text("status", "+ok")
.add_child("data",
json.create_node()
.add_text("name", "value")
.add_bool("success", true)
.add_number("number", 200));
return res.write(json);
});
// start the server in alone mode
server.run_alone("0.0.0.0|8194, 127.0.0.1|8195", "./httpd.cf");
return 0;
} Windows GUI sampleThere is one Windows GUI sample with libfiber in directory. The screen shot is The server coroutine and client coroutine are all running in the same thread as the GUI, so you can operate the GUI object in server and client coroutine without worrying about the memroy collision problem. And you can write network process with sequence way, other than asynchronus callback way which is so horrible. With the libfirber for Windows GUI, the asynchronus API like CAsyncSocket should be discarded. The network APIs are intergrated with the Windows GUI seamlessly because the libfiber using GUI message pump as event driven internal. More SAMPLESYou can get more samples in samples, which use many APIs in acl project library. BUILDINGOn Unix
The simple Makefile shown below:
On WindowsYou can open the fiber_vc2012.sln/ fiber_vc2013.sln/c/fiber_vc2015.sln with vc2012/vc2013/vc2015, and build the libfiber library and the samples included. BenchmarkThe picture below show the IOPS (io echo per-second) benchmark written by libfiber, comparing with the samples writen by libmill, golang and libco. The samples written by libmill and libco are in directory, the sample written by golang is in here, and the sample written by libfiber is in server sample directory. The testing client is in here from the acl project. API supportBase API
IO API
Net API
Channel API
Sync APIACL_FIBER_MUTEX
ACL_FIBER_RWLOCK
ACL_FIBER_EVENT
ACL_FIBER_SEM
About API HookOn Linux/BSD/Mac, many IO and Net APIs are hooked. So you can just use the System standard APIs in your applications with libfiber, the hooked APIs will be replaced with libfiber APIs. In this case, you can
FAQ
|
2023-10-27
2022-08-15
2022-08-17
2022-09-23
2022-08-13
请发表评论