libuv简介
libuv是一个基于事件驱动的跨平台的异步I/O库,它主要提供了异步文件操作、网络操作、定时器、子进程等功能。libuv最初是Node.js的一个组件,用于处理非阻塞I/O的事件循环,后来逐渐发展成为一个独立的库。它支持多种平台,包括Linux, macOS, Windows等,通过统一的API接口,应用程序可以在不同的平台上得到相同的行为。libuv还提供了一套线程池工具,可用于处理一些CPU密集型的任务。在Node.js 10版本之后,libuv被集成到Node.js中,成为了Node.js的重要组成部分。
libuv的下载地址和官方教程如下:
下载地址:
GitHub地址:https://github.com/libuv/libuv/releases
官网下载地址:http://libuv.org/dist/
官方教程:
官方文档:http://docs.libuv.org/en/latest/index.html
GitHub示例代码:https://github.com/libuv/libuv/tree/v1.x/docs/code
常见问题及解答:http://docs.libuv.org/en/stable/faq.html
除了官方文档和示例代码外,还有一些社区提供的教程和文章,可以通过互联网搜索来获得更多的学习资源。
本文内容
利用libuv的源码,创建QT工程,编辑工程文件,实现libuv的源码编译和调试。
libuv版本号:v1.44.1
QT版本号:5.9.9
操作系统:win10/Ubuntu。
创建工程
首先创建QT Console 工程,一路下一步,选择MinGW 32bit的kit。
在工程的main.cpp所在文件夹中新建libuv文件夹,将下载好的libuv代码中的libuv-v1.44.1\include\和libuv-v1.44.1\src\两个文件夹复制到此文件夹中。
编辑工程文件
添加依赖文件头文件和源文件路径
在.pro文件中,添加如下代码:
INCLUDEPATH += $$PWD/libuv/include
DEPENDPATH += $$PWD/libuv/include
INCLUDEPATH += $$PWD/libuv/src
DEPENDPATH += $$PWD/libuv/src
公共头文件和源文件添加
在.pro文件中,将SOURCES 和 HEADERS部分修改为:
SOURCES += \
libuv/src/fs-poll.c \
libuv/src/idna.c \
libuv/src/inet.c \
libuv/src/random.c \
libuv/src/strscpy.c \
libuv/src/threadpool.c \
libuv/src/timer.c \
libuv/src/uv-common.c \
libuv/src/uv-data-getter-setters.c \
libuv/src/version.c \
main.cpp
HEADERS += \
libuv/include/uv.h \
libuv/include/uv/aix.h \
libuv/include/uv/bsd.h \
libuv/include/uv/darwin.h \
libuv/include/uv/errno.h \
libuv/include/uv/linux.h \
libuv/include/uv/os390.h \
libuv/include/uv/posix.h \
libuv/include/uv/stdint-msvc2008.h \
libuv/include/uv/sunos.h \
libuv/include/uv/threadpool.h \
libuv/include/uv/tree.h \
libuv/include/uv/version.h \
libuv/src/heap-inl.h \
libuv/src/idna.h \
libuv/src/queue.h \
libuv/src/strscpy.h \
libuv/src/uv-common.h \
WIN系统依赖库、头文件和源文件添加
WIN系统下,添加预定义 DEFINES += _WIN32_WINNT=0x0602。
WIN系统下,libuv需要7个依赖库,分别为:ws2_32、UserEnv、IPHLPAPI、Psapi、advapi32、User32、Gdi32。
WIN系统下,所需的源码主要集中在“libuv\src\win\”中。添加后如下所示。
win32{
DEFINES += _WIN32_WINNT=0x0602
LIBS += -lws2_32
LIBS += -lUserEnv
LIBS += -lIPHLPAPI
LIBS += -lPsapi
LIBS += -ladvapi32
LIBS += -lUser32
LIBS += -lGdi32
SOURCES += \
libuv/src/win/async.c \
libuv/src/win/core.c \
libuv/src/win/detect-wakeup.c \
libuv/src/win/dl.c \
libuv/src/win/error.c \
libuv/src/win/fs-event.c \
libuv/src/win/fs.c \
libuv/src/win/getaddrinfo.c \
libuv/src/win/getnameinfo.c \
libuv/src/win/handle.c \
libuv/src/win/loop-watcher.c \
libuv/src/win/pipe.c \
libuv/src/win/poll.c \
libuv/src/win/process-stdio.c \
libuv/src/win/process.c \
libuv/src/win/signal.c \
libuv/src/win/snprintf.c \
libuv/src/win/stream.c \
libuv/src/win/tcp.c \
libuv/src/win/thread.c \
libuv/src/win/tty.c \
libuv/src/win/udp.c \
libuv/src/win/util.c \
libuv/src/win/winapi.c \
libuv/src/win/winsock.c \
HEADERS += \
libuv/include/uv/win.h \
libuv/src/win/atomicops-inl.h \
libuv/src/win/fs-fd-hash-inl.h \
libuv/src/win/handle-inl.h \
libuv/src/win/internal.h \
libuv/src/win/req-inl.h \
libuv/src/win/stream-inl.h \
libuv/src/win/winapi.h \
libuv/src/win/winsock.h
}
LINUX系统依赖库、头文件和源文件添加
LINUX系统下,添加预定义: DEFINES += _FILE_OFFSET_BITS=64 DEFINES += _LARGEFILE_SOURCE DEFINES += _GNU_SOURCE DEFINES += _POSIX_C_SOURCE=200112。
LINUX系统下,libuv需要pthread依赖库。
LINUX系统下,所需的源码主要集中在“libuv\src\unix\”中,注意并不是此文件夹中所有文件都需要,因为有很多是AIX、MAC、BSD等系统的,常用的Linux系统(如Ubuntu)并不需要。
添加后如下所示。
unix{
LIBS += -lpthread
DEFINES += _FILE_OFFSET_BITS=64
DEFINES += _LARGEFILE_SOURCE
DEFINES += _GNU_SOURCE
DEFINES += _POSIX_C_SOURCE=200112
SOURCES += \
libuv/src/unix/async.c \
libuv/src/unix/core.c \
libuv/src/unix/dl.c \
libuv/src/unix/fs.c \
libuv/src/unix/getaddrinfo.c \
libuv/src/unix/getnameinfo.c \
libuv/src/unix/loop-watcher.c \
libuv/src/unix/loop.c \
libuv/src/unix/pipe.c \
libuv/src/unix/poll.c \
libuv/src/unix/process.c \
libuv/src/unix/random-devurandom.c \
libuv/src/unix/signal.c \
libuv/src/unix/stream.c \
libuv/src/unix/tcp.c \
libuv/src/unix/thread.c \
libuv/src/unix/tty.c \
libuv/src/unix/udp.c \
libuv/src/unix/proctitle.c \
libuv/src/unix/linux-core.c \
libuv/src/unix/linux-inotify.c \
libuv/src/unix/linux-syscalls.c \
libuv/src/unix/procfs-exepath.c \
libuv/src/unix/random-getrandom.c \
libuv/src/unix/random-sysctl-linux.c \
libuv/src/unix/epoll.c \
HEADERS += \
libuv/include/uv/unix.h \
libuv/src/unix/atomic-ops.h \
libuv/src/unix/darwin-stub.h \
libuv/src/unix/internal.h \
libuv/src/unix/linux-syscalls.h \
libuv/src/unix/os390-syscalls.h \
libuv/src/unix/spinlock.h \
}
编译测试
完成以上编辑后,即可进行工程构建和调试。
(main.cpp中添加)测试代码可用如下:
//#include <QCoreApplication>
#include <uv.h>
#include <stdio.h>
void onConnect(uv_stream_t* server, int status);
void onAlloc(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf);
void onRead(uv_stream_t* client, ssize_t nread, const uv_buf_t* buf);
void onWrite(uv_write_t* req, int status);
void onClose(uv_handle_t* handle);
int main() {
uv_loop_t* loop = uv_default_loop();
uv_tcp_t server;
uv_tcp_init(loop, &server);
struct sockaddr_in address;
uv_ip4_addr("0.0.0.0", 12345, &address); // 监听本地 12345 端口
uv_tcp_bind(&server, (struct sockaddr*)&address, 0);
uv_listen((uv_stream_t*)&server, SOMAXCONN, onConnect);
printf("Listening on port 12345...\n");
return uv_run(loop, UV_RUN_DEFAULT);
}
void onConnect(uv_stream_t* server, int status) {
if (status < 0) {
fprintf(stderr, "Error: %s\n", uv_strerror(status));
return;
}
uv_loop_t* loop = uv_default_loop();
uv_tcp_t* client = (uv_tcp_t*)malloc(sizeof(uv_tcp_t));
uv_tcp_init(loop, client);
if (uv_accept(server, (uv_stream_t*)client) == 0) {
struct sockaddr_in addr;
int len = sizeof(addr);
uv_tcp_getpeername(client, (struct sockaddr*)&addr, &len);
printf("Client connected from %s:%d\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
uv_write_t* req = (uv_write_t*)malloc(sizeof(uv_write_t));
char* message = "Hello, World!";
uv_buf_t buf = uv_buf_init(message, strlen(message));
uv_write(req, (uv_stream_t*)client, &buf, 1, onWrite);
}
else {
uv_close((uv_handle_t*)client, onClose);
}
}
void onAlloc(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) {
buf->base = (char*)malloc(suggested_size);
buf->len = suggested_size;
}
void onRead(uv_stream_t* client, ssize_t nread, const uv_buf_t* buf) {
if (nread <= 0) {
if (nread == UV_EOF) {
printf("Client disconnected\n");
}
else {
fprintf(stderr, "Error: %s\n", uv_strerror(nread));
}
uv_close((uv_handle_t*)client, onClose);
}
else {
printf("Received bytes: %ld\n", nread);
printf("Received message: %s\n", buf->base);
// 处理业务逻辑
free(buf->base);
}
}
void onWrite(uv_write_t* req, int status) {
if (status < 0) {
fprintf(stderr, "Error: %s\n", uv_strerror(status));
uv_close((uv_handle_t*)req->handle, onClose);
}
else {
uv_read_start((uv_stream_t*)req->handle, onAlloc, onRead);
}
free(req);
}
void onClose(uv_handle_t* handle) {
free(handle);
}
//int main(int argc, char *argv[])
//{
// QCoreApplication a(argc, argv);
// return a.exec();
//}