一、克隆libuv源码
- 打开命令行或终端。
- 使用
git clone
命令克隆libuv的源码仓库。例如:git clone https://github.com/libuv/libuv.git
- 这将在当前目录下创建一个名为
libuv
的目录,其中包含libuv的源码。
二、编译安装libuv
- 进入libuv的源码目录:
cd libuv
- 运行
sh autogen.sh
以生成配置脚本(如果存在autogen.sh
)。这可能在某些libuv版本中需要,但不一定。 - 运行
./configure
脚本以准备编译环境。这个脚本会检查您的系统环境,并生成适合您的系统的Makefile文件。 - 编译libuv:
make
- (可选)运行测试以确保编译没有问题:
make check
- 安装libuv:
sudo make install
- 这会将libuv库安装到您的系统中,通常是
/usr/local/lib
目录。
三、把libuv文件、动态库放到项目中
将libuv下的include文件、.libs/libuv.so放到你项目中去
例如: 我把include文件放到我的项目中的Include/Libuv/UVInclude中
把libuv.so放到Lib中
── build
├── CMakeLists.txt
├── Include
│ └── Libuv
│ ├── Libuv.cpp
│ ├── Libuv.h
│ └── UVInclude
│ ├── uv
│ │ ├── aix.h
│ │ ├── bsd.h
│ │ ├── darwin.h
│ │ ├── errno.h
│ │ ├── linux.h
│ │ ├── os390.h
│ │ ├── posix.h
│ │ ├── sunos.h
│ │ ├── threadpool.h
│ │ ├── tree.h
│ │ ├── unix.h
│ │ ├── version.h
│ │ └── win.h
│ └── uv.h
├── Lib
│ └── libuv.so
└── Main.cpp
四、CMakeLists.txt编译规则增加
#限定cmake 版本最低2.8
cmake_minimum_required(VERSION 2.8)#项目名称
project(main)#向编译单元添加包含目录的路径。这允许源文件包含来自指定目录的头文件
include_directories(Include)#用于将指定目录下的所有源文件列表赋值给一个变量
aux_source_directory(Include/Libuv SRC_LIST1)#从指定目录查找对应的库
find_library(LIB libuv.so ./Lib)if(LIB)message("find libuv.so")
else()message("not find libuv.so")
endif()#添加一个可执行目标以及它的源文件
add_executable(main Main.cpp ${SRC_LIST1})#为指定的目标添加链接库, 这里增加libuv.so库
target_link_libraries(main ${LIB})
五、项目使用libuv库实现tcp连接
1、建立类( Libuv.h、Libuv.cpp) 封装使用
Libuv.h代码
#ifndef LIBUV
#define LIBUV
#include "UVInclude/uv.h"class Libuv{public:Libuv();void Init();private:};#endif
Libuv.cpp代码
#include<iostream>
#include <cstdlib>
#include <sstream>
#include "Libuv.h"
using namespace std;Libuv::Libuv(){}string get_client_ip(uv_tcp_t* client){
// 获取客户端的 socket 信息 struct sockaddr_storage peer_addr; int peer_addr_len = sizeof(peer_addr); if (uv_tcp_getpeername(client, (struct sockaddr*)&peer_addr, &peer_addr_len) == 0) { char ip_str[INET6_ADDRSTRLEN]; void* addr;int port;if (peer_addr.ss_family == AF_INET) { struct sockaddr_in* in = (struct sockaddr_in*)&peer_addr; addr = &(in->sin_addr);port= ntohs(in->sin_port);} else { struct sockaddr_in6* in6 = (struct sockaddr_in6*)&peer_addr; addr = &(in6->sin6_addr); port=ntohs(in6->sin6_port);} inet_ntop(peer_addr.ss_family, addr, ip_str, sizeof(ip_str)); //printf("Accepted connection from client IP: %s\n", ip_str); std::ostringstream oss;oss<<ip_str<<":"<<port;return oss.str();} else { // 如果获取客户端信息失败,可以获取错误信息 //fprintf(stderr, "Getpeername error %s\n", uv_strerror(uv_last_error(uv_default_loop()))); cout<<"getpeername error"<<endl;}return "";
}
void alloc_buffer(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) { *buf = uv_buf_init((char*)malloc(suggested_size), suggested_size);
} void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) { string ip_str = get_client_ip((uv_tcp_t*)stream);if (nread > 0) { std::cout <<"client:"<< ip_str<< ",Received: " << buf->base << std::endl; } else if (nread < 0) { if (nread != UV_EOF) //std::cerr << "Read error " << uv_err_name(uv_last_error(uv_default_loop())) << std::endl; uv_close((uv_handle_t*) stream, NULL);cout<<"close by client,ip:"<<ip_str<<endl;} else { /* EOF: call uv_close() */ cout<<"close by eof"<<endl;uv_close((uv_handle_t*) stream, NULL); } free(buf->base);
}
void on_connect_cb(uv_stream_t* server, int status) { if (status == -1) { //std::cerr << "Connection error: " << uv_strerror(uv_last_error(uv_default_loop())) << std::endl; cout<<"connection error"<<endl;return;}uv_tcp_t* client =(uv_tcp_t*)malloc(sizeof(uv_tcp_t));uv_tcp_init(uv_default_loop(),client);if(uv_accept(server, (uv_stream_t*)client) == 0) {string ip_str = get_client_ip(client);cout<<"accepted new connection, ip:"<<ip_str<<endl;uv_read_start((uv_stream_t*)client, alloc_buffer, read_cb);}else{cout<<"accepted error"<<endl;free(client);}
}void Libuv::Init(){cout<<"Libuv Init"<<endl;uv_loop_t *loop = uv_default_loop();uv_tcp_t server;uv_tcp_init(loop, &server);struct sockaddr_in addr;uv_ip4_addr("0.0.0.0", 9999, &addr);uv_tcp_bind(&server, (const struct sockaddr*)&addr, 0);uv_listen((uv_stream_t*)&server, 128, on_connect_cb);uv_run(loop, UV_RUN_DEFAULT);
}
2、main 使用Libuv类
main.cpp 代码
#include<iostream>
#include "Libuv/Libuv.h"using namespace std;int main(){Libuv libuv;libuv.Init();return 0;
}
六、运行结果
服务器:
Libuv Init
accepted new connection, ip:127.0.0.1:49094
client:127.0.0.1:49094,Received: hello worldclose by client,ip:127.0.0.1:49094
客户端:
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
hello world
^]telnet> q
Connection closed.