一、克隆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 world
close 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.