当前位置: 首页 > news >正文

Asio2网络库

  • header only,不依赖boost库,不需要单独编译,在工程的Include目录中添加asio2路径,在源码中#include <asio2/asio2.hpp>即可使用;
  • 支持tcp, udp, http, websocket, rpc, ssl, icmp, serial_port;
  • 支持可靠UDP(基于KCP),支持SSL;
  • TCP支持各种数据拆包功能(单个字符或字符串或用户自定义协议等);
  • 跨平台,支持windows,linux,macos,arm,android,32位,64位等;在msvc gcc clang ndk mingw下编译通过;
  • 基于C++17,基于asio (standalone asio或boost::asio均可);
  • example目录包含大量示例代码,各种使用方法请参考示例代码;
  • 与其它框架的一点区别:

  • 目前看到的很多基于asio的框架的模式大都如下:
    tcp_server server; // 声明一个server
    server.run();      // 调用run函数,run函数是阻塞的,run之后怎么退出却不知道.
    这种模式需要用户自己去处理程序退出后的逻辑,包括连接的正常关闭,
    资源释放等问题,而这些问题自己处理起来是很烦琐的.
    asio2框架已经处理过了这些问题,你可以在如MFC的OnInitDialog等地方调用server.start(...),
    start(...)函数是非阻塞的,什么时候想退出了只需要server.stop()即可.stop()是阻塞的,
    stop时如果有未发送完的数据,会保证一定在数据发送完之后才会退出,
    tcp下也会保证所有连接都正常关闭以后才会退出,你不用考虑资源的正确释放等一系列琐碎的问题.

 TCP:

服务端:
asio2::tcp_server server;
server.bind_recv([&](std::shared_ptr<asio2::tcp_session> & session_ptr, std::string_view s)
{printf("recv : %zu %.*s\n", s.size(), (int)s.size(), s.data());// 异步发送(所有发送操作都是异步且线程安全的)session_ptr->async_send(s);// 发送时指定一个回调函数,当发送完成后会调用此回调函数,bytes_sent表示实际发送的字节数,// 发送是否有错误可以用asio2::get_last_error()函数来获取错误码// session_ptr->async_send(s, [](std::size_t bytes_sent) {});
}).bind_connect([&](auto & session_ptr)
{session_ptr->no_delay(true);printf("client enter : %s %u %s %u\n",session_ptr->remote_address().c_str(), session_ptr->remote_port(),session_ptr->local_address().c_str(), session_ptr->local_port());// 可以用session_ptr这个会话启动一个定时器,这个定时器是在这个session_ptr会话的数据收// 发线程中执行的,这对于连接状态的判断或其它需求很有用(尤其在UDP这种无连接的协议中,有// 时需要在数据处理过程中使用一个定时器来延时做某些操作,而且这个定时器还需要和数据处理// 在同一个线程中安全触发)//session_ptr->start_timer(1, std::chrono::seconds(1), []() {});
}).bind_disconnect([&](auto & session_ptr)
{printf("client leave : %s %u %s\n",session_ptr->remote_address().c_str(), session_ptr->remote_port(),asio2::last_error_msg().c_str());
});
server.start("0.0.0.0", "8080");// 按\n自动拆包(可以指定任意字符)
//server.start("0.0.0.0", "8080", '\n');// 按\r\n自动拆包(可以指定任意字符串)
//server.start("0.0.0.0", "8080", "\r\n");// 按自定义规则自动拆包(match_role请参考example代码)(用于对用户自定义的协议拆包)
// 对自定义协议拆包时,match_role如何使用的详细说明请看:https://blog.csdn.net/zhllxt/article/details/104772948
//server.start("0.0.0.0", "8080", match_role('#'));// 每次接收固定的100字节
//server.start("0.0.0.0", "8080", asio::transfer_exactly(100));// 数据报模式的TCP,无论发送多长的数据,双方接收的一定是相应长度的整包数据
//server.start("0.0.0.0", "8080", asio2::use_dgram);
客户端:
asio2::tcp_client client;
// 客户端在断开时默认会自动重连// 禁止自动重连
//client.auto_reconnect(false);// 启用自动重连 默认在断开连接后延时1秒就会开始重连
//client.auto_reconnect(true);// 启用自动重连 并设置自定义的延时
client.auto_reconnect(true, std::chrono::seconds(3));client.bind_connect([&]()
{if (asio2::get_last_error())printf("connect failure : %d %s\n", asio2::last_error_val(), asio2::last_error_msg().c_str());elseprintf("connect success : %s %u\n", client.local_address().c_str(), client.local_port());// 如果连接成功 就可以调用异步发送函数发送数据了if (!asio2::get_last_error())client.async_send("<abcdefghijklmnopqrstovuxyz0123456789>");// 如果在通信线程中调用同步发送函数会退化为异步调用(这里的bind_connect的回调函数就位于通信线程中)// client.send("abc");}).bind_disconnect([]()
{printf("disconnect : %d %s\n", asio2::last_error_val(), asio2::last_error_msg().c_str());
}).bind_recv([&](std::string_view sv)
{printf("recv : %zu %.*s\n", sv.size(), (int)sv.size(), sv.data());client.async_send(sv);
})绑定全局函数//.bind_recv(on_recv)绑定成员函数(具体请查看example代码)//.bind_recv(std::bind(&listener::on_recv, &lis, std::placeholders::_1)) 按lis对象的引用来绑定成员函数(具体请查看example代码)//.bind_recv(&listener::on_recv, lis) 按lis对象的指针来绑定成员函数(具体请查看example代码)//.bind_recv(&listener::on_recv, &lis) ;
// 异步连接服务端
//client.async_start("0.0.0.0", "8080");// 同步连接服务端
client.start("0.0.0.0", "8080");// 连接成功后,可以调用发送函数(这里是主线程不在通信线程中)
// 同步发送和异步发送可以混用,是线程安全的(一定会在A发送完之后才会发送B)
std::size_t bytes_sent = client.send("abc");
// 同步发送函数的返回值为发送的字节数 可以用get_last_error()查看是否发生错误
if(asio2::get_last_error())
{printf("同步发送数据失败:%s\n", asio2::last_error_msg().data());
}// 按\n自动拆包(可以指定任意字符)
//client.async_start("0.0.0.0", "8080", '\n');// 按\r\n自动拆包(可以指定任意字符串)
//client.async_start("0.0.0.0", "8080", "\r\n"); // 按自定义规则自动拆包(match_role请参考example代码)(用于对用户自定义的协议拆包)
// 对自定义协议拆包时,match_role如何使用的详细说明请看:https://blog.csdn.net/zhllxt/article/details/104772948
//client.async_start("0.0.0.0", "8080", match_role); // 每次接收固定的100字节
//client.async_start("0.0.0.0", "8080", asio::transfer_exactly(100)); // 数据报模式的TCP,无论发送多长的数据,双方接收的一定是相应长度的整包数据
//client.start("0.0.0.0", "8080", asio2::use_dgram); // 发送时也可以指定use_future参数,然后通过返回值future来阻塞等待直到发送完成,发送结果的错误码和发送字节数
// 保存在返回值future中(注意,不能在通信线程中用future去等待,这会阻塞通信线程进而导致死锁)
// std::future<std::pair<asio::error_code, std::size_t>> future = client.async_send("abc", asio::use_future); 

UDP:

服务端:
asio2::udp_server server;
// ... 绑定监听器(请查看example代码)
server.start("0.0.0.0", "8080"); // 常规UDP
//server.start("0.0.0.0", "8080", asio2::use_kcp); // 可靠UDP
客户端:
asio2::udp_client client;
// ... 绑定监听器(请查看example代码)
client.start("0.0.0.0", "8080");
//client.async_start("0.0.0.0", "8080", asio2::use_kcp); // 可靠UDP

RPC:        

服务端:
// 全局函数示例,当服务端的RPC函数被调用时,如果想知道是哪个客户端调用的,将这个RPC函数的第一
// 个参数设置为连接对象的智能指针即可(如果不关心是哪个客户端调用的,第一个参数可以不要),如下:
int add(std::shared_ptr<asio2::rpc_session>& session_ptr, int a, int b)
{return a + b;
}// rpc默认是按照"数据长度+数据内容"的格式来发送数据的,因此客户端可能会恶意组包,导致解析出的
// "数据长度"非常长,此时就会分配大量内存来接收完整数据包.避免此问题的办法就是是指定缓冲区最
// 大值,如果发送的数据超过缓冲区最大值,就会将该连接直接关闭.所有tcp udp http websocket,server
// client 等均支持这个功能.
asio2::rpc_server server(512,  // 接收缓冲区的初始大小1024, // 接收缓冲区的最大大小4     // 多少个并发线程
);// ... 绑定监听器(请查看example代码)// 绑定RPC全局函数
server.bind("add", add);// 绑定RPC成员函数
server.bind("mul", &A::mul, a);// 绑定lambda表达式
server.bind("cat", [&](const std::string& a, const std::string& b) { return a + b; });// 绑定成员函数(按引用) a的定义请查看example代码
server.bind("get_user", &A::get_user, a);// 绑定成员函数(按指针) a的定义请查看example代码
server.bind("del_user", &A::del_user, &a);// 服务端也可以调用客户端的RPC函数(通过连接对象session_ptr)
session_ptr->async_call([](int v)
{printf("sub : %d err : %d %s\n", v, asio2::last_error_val(), asio2::last_error_msg().c_str());
}, std::chrono::seconds(10), "sub", 15, 6);//server.start("0.0.0.0", "8080");
客户端:
asio2::rpc_client client;
// ... 绑定监听器(请查看example代码)
// 不仅server可以绑定RPC函数给client调用,同时client也可以绑定RPC函数给server调用。请参考example代码。
client.start("0.0.0.0", "8080");// 同步调用RPC函数
int sum = client.call<int>(std::chrono::seconds(3), "add", 11, 2);
printf("sum : %d err : %d %s\n", sum, asio2::last_error_val(), asio2::last_error_msg().c_str());// 异步调用RPC函数,
// 第一个参数是回调函数,当调用完成或超时会自动调用该回调函数
// 第二个参数是调用超时,可以不填,如果不填则使用默认超时
// 第三个参数是rpc函数名,之后的参数是rpc函数的参数
client.async_call([](int v)
{// 如果超时或发生其它错误,可以通过asio2::get_last_error()等一系列函数获取错误信息printf("sum : %d err : %d %s\n", v, asio2::last_error_val(), asio2::last_error_msg().c_str());
}, "add", 10, 20);// 上面的调用方式的参数位置很容易搞混,因此也支持链式调用,如下(其它示例请查看example):
client.timeout(std::chrono::seconds(5)).async_call("mul", 2.5, 2.5).response([](double v)
{std::cout << "mul1 " << v << std::endl;
});
int sum = client.timeout(std::chrono::seconds(3)).call<int>("add", 11, 32);// 返回值为用户自定义数据类型(user类型的定义请查看example代码)
user u = client.call<user>("get_user");
printf("%s %d ", u.name.c_str(), u.age);
for (auto &[k, v] : u.purview)
{printf("%d %s ", k, v.c_str());
}
printf("\n");u.name = "hanmeimei";
u.age = ((int)time(nullptr)) % 100;
u.purview = { {10,"get"},{20,"set"} };// 如果RPC函数的返回值为void,则用户回调函数参数为空
client.async_call([]()
{
}, "del_user", std::move(u));// 只调用rpc函数,不需要返回结果
client.async_call("del_user", std::move(u));

HTTP:

服务端:
// http 请求拦截器
struct aop_log
{bool before(http::web_request& req, http::web_response& rep){asio2::detail::ignore_unused(rep);printf("aop_log before %s\n", req.method_string().data());// 返回true则后续的拦截器会接着调用,返回false则后续的拦截器不会被调用return true;}bool after(std::shared_ptr<asio2::http_session>& session_ptr, http::web_request& req, http::web_response& rep){asio2::detail::ignore_unused(session_ptr, req, rep);printf("aop_log after\n");return true;}
};struct aop_check
{bool before(std::shared_ptr<asio2::http_session>& session_ptr, http::web_request& req, http::web_response& rep){asio2::detail::ignore_unused(session_ptr, req, rep);printf("aop_check before\n");return true;}bool after(http::web_request& req, http::web_response& rep){asio2::detail::ignore_unused(req, rep);printf("aop_check after\n");return true;}
};asio2::http_server server;server.bind<http::verb::get, http::verb::post>("/index.*", [](http::web_request& req, http::web_response& rep)
{std::cout << req.path() << std::endl;std::cout << req.query() << std::endl;rep.fill_file("../../../index.html");rep.chunked(true);}, aop_log{});server.bind<http::verb::get>("/del_user",[](std::shared_ptr<asio2::http_session>& session_ptr, http::web_request& req, http::web_response& rep)
{// 回调函数的第一个参数可以是会话指针session_ptr(这个参数也可以不要)printf("del_user ip : %s\n", session_ptr->remote_address().data());// fill_page函数用给定的错误代码构造一个简单的标准错误页,<html>...</html>这样rep.fill_page(http::status::ok, "del_user successed.");}, aop_check{});server.bind<http::verb::get>("/api/user/*", [](http::web_request& req, http::web_response& rep)
{rep.fill_text("the user name is hanmeimei, .....");}, aop_log{}, aop_check{});server.bind<http::verb::get>("/defer", [](http::web_request& req, http::web_response& rep)
{// 使用defer让http响应延迟发送,defer的智能指针销毁时,才会自动发送responsestd::shared_ptr<http::response_defer> rep_defer = rep.defer();std::thread([rep_defer, &rep]() mutable{std::this_thread::sleep_for(std::chrono::milliseconds(1000));auto newrep = asio2::http_client::execute("http://www.baidu.com");rep = std::move(newrep);}).detach();}, aop_log{}, aop_check{});// 对websocket的支持
server.bind("/ws", websocket::listener<asio2::http_session>{}.on("message", [](std::shared_ptr<asio2::http_session>& session_ptr, std::string_view data)
{printf("ws msg : %zu %.*s\n", data.size(), (int)data.size(), data.data());session_ptr->async_send(data);}).on("open", [](std::shared_ptr<asio2::http_session>& session_ptr)
{printf("ws open\n");// 打印websocket的http请求头std::cout << session_ptr->request() << std::endl;// 如何给websocket响应头填充额外信息session_ptr->ws_stream().set_option(websocket::stream_base::decorator([](websocket::response_type& rep){rep.set(http::field::authorization, " http-server-coro");}));}).on("close", [](std::shared_ptr<asio2::http_session>& session_ptr)
{printf("ws close\n");}));server.bind_not_found([](http::web_request& req, http::web_response& rep)
{// fill_page函数可以构造一个简单的标准错误页rep.fill_page(http::status::not_found);
});
客户端:
// 1. http下载大文件并直接保存
// The file is in this directory: /asio2/example/bin/x64/QQ9.6.7.28807.exe
asio2::https_client::download("https://dldir1.qq.com/qqfile/qq/PCQQ9.6.7/QQ9.6.7.28807.exe","QQ9.6.7.28807.exe");// 2. http下载大文件并循环调用回调函数,可在回调函数中写入文件,可实现进度条之类功能
std::fstream hugefile("CentOS-7-x86_64-DVD-2009.iso", std::ios::out | std::ios::binary | std::ios::trunc);
asio2::https_client::download(asio::ssl::context{ asio::ssl::context::tlsv13 },"https://mirrors.tuna.tsinghua.edu.cn/centos/7.9.2009/isos/x86_64/CentOS-7-x86_64-DVD-2009.iso",//[](auto& header) // http header callback. this param is optional. the body callback is required.//{//	std::cout << header << std::endl;//},[&hugefile](std::string_view chunk) // http body callback.{hugefile.write(chunk.data(), chunk.size());}
);
hugefile.close();// 通过URL字符串生成一个http请求对象
auto req1 = http::make_request("http://www.baidu.com/get_user?name=abc");
// 通过URL字符串直接请求某个网址,返回结果在rep1中
auto rep1 = asio2::http_client::execute("http://www.baidu.com/get_user?name=abc");
// 通过asio2::get_last_error()判断是否发生错误
if (asio2::get_last_error())std::cout << asio2::last_error_msg() << std::endl;
elsestd::cout << rep1 << std::endl; // 打印http请求结果// 通过http协议字符串生成一个http请求对象
auto req2 = http::make_request("GET / HTTP/1.1\r\nHost: 192.168.0.1\r\n\r\n");
// 通过请求对象发送http请求
auto rep2 = asio2::http_client::execute("www.baidu.com", "80", req2, std::chrono::seconds(3));
if (asio2::get_last_error())std::cout << asio2::last_error_msg() << std::endl;
elsestd::cout << rep2 << std::endl;std::stringstream ss;
ss << rep2;
std::string result = ss.str(); // 通过这种方式将http请求结果转换为字符串// 获取url中的path部分的值
auto path = asio2::http::url_to_path("/get_user?name=abc");
std::cout << path << std::endl;// 获取url中的query部分的值
auto query = asio2::http::url_to_query("/get_user?name=abc");
std::cout << query << std::endl;std::cout << std::endl;auto rep3 = asio2::http_client::execute("www.baidu.com", "80", "/api/get_user?name=abc");
if (asio2::get_last_error())std::cout << asio2::last_error_msg() << std::endl;
elsestd::cout << rep3 << std::endl;// URL编解码
std::string en = http::url_encode(R"(http://www.baidu.com/json={"qeury":"name like '%abc%'","id":1})");
std::cout << en << std::endl;
std::string de = http::url_decode(en);
std::cout << de << std::endl;// 其它的更多用法请查看example示例代码

ICMP:

asio2::ping ping;
ping.timeout(std::chrono::seconds(3))  // 设置ping超时 默认3秒.interval(std::chrono::seconds(1)) // 设置ping间隔 默认1秒.bind_recv([](asio2::icmp_rep& rep)
{if (rep.is_timeout())std::cout << "request timed out" << std::endl;elsestd::cout << rep.total_length() - rep.header_length()<< " bytes from " << rep.source_address()<< ": icmp_seq=" << rep.sequence_number()<< ", ttl=" << rep.time_to_live()<< ", time=" << rep.milliseconds() << "ms"<< std::endl;
}).start("151.101.193.69");

SSL:

asio2::tcps_server server;
// 设置证书模式
// 如果是 verify_peer | verify_fail_if_no_peer_cert 则客户端必须要使用证书否则握手失败
// 如果是 verify_peer 或者是 verify_fail_if_no_peer_cert 则客户端用不用证书都可以
server.set_verify_mode(asio::ssl::verify_peer | asio::ssl::verify_fail_if_no_peer_cert);
// 从内存字符串加载SSL证书(具体请查看example代码) 字符串的具体定义请查看example代码
server.set_cert_buffer(ca_crt, server_crt, server_key, "server"); // use memory string for cert
server.set_dh_buffer(dh);
// 从文件加载SSL证书(注意编译后把example/cert目录下的证书拷贝到exe目录下 否则会提示加载证书失败)
server.set_cert_file("ca.crt", "server.crt", "server.key", "server"); // use file for cert
server.set_dh_file("dh1024.pem");
// 如何制作自己的证书:
// 1. 生成服务端私有密钥
// openssl genrsa -des3 -out server.key 1024
// 2. 生成服务端证书请求文件
// openssl req -new -key server.key -out server.csr -config openssl.cnf
// 3. 生成客户端私有密钥
// openssl genrsa -des3 -out client.key 1024
// 4. 生成客户端证书请求文件
// openssl req -new -key client.key -out client.csr -config openssl.cnf
// 5. 生成CA私有密钥
// openssl genrsa -des3 -out ca.key 2048
// 6. 生成CA证书文件
// openssl req -new -x509 -key ca.key -out ca.crt -days 3650 -config openssl.cnf
// 7. 生成服务端证书
// openssl ca -in server.csr -out server.crt -cert ca.crt -keyfile ca.key -config openssl.cnf
// 8. 生成客户端证书
// openssl ca -in client.csr -out client.crt -cert ca.crt -keyfile ca.key -config openssl.cnf
// 9. 生成dh文件
// openssl dhparam -out dh1024.pem 1024
// 说明:openssl是个exe文件,在tool/openssl/x64/bin目录下 openssl.cnf在tool/openssl/x64/ssl目录下
// 生成证书过程中的其它细节百度搜索即可找到相关说明

串口:

std::string_view device = "COM1"; // windows
//std::string_view device = "/dev/ttyS0"; // linux
std::string_view baud_rate = "9600";asio2::serial_port sp;
sp.bind_init([&]()
{// 设置串口参数sp.socket().set_option(asio::serial_port::flow_control(asio::serial_port::flow_control::type::none));sp.socket().set_option(asio::serial_port::parity(asio::serial_port::parity::type::none));sp.socket().set_option(asio::serial_port::stop_bits(asio::serial_port::stop_bits::type::one));sp.socket().set_option(asio::serial_port::character_size(8));}).bind_recv([&](std::string_view sv)
{printf("recv : %zu %.*s\n", sv.size(), (int)sv.size(), sv.data());// 接收串口数据std::string s;uint8_t len = uint8_t(10 + (std::rand() % 20));s += '<';for (uint8_t i = 0; i < len; i++){s += (char)((std::rand() % 26) + 'a');}s += '>';sp.async_send(s, []() {});});// 没有指定如何解析串口数据,需要用户自己去解析串口数据
//sp.start(device, baud_rate);// 按照单个字符'>'作为数据分隔符自动解析串口数据
sp.start(device, baud_rate, '>');// 按照字符串"\r\n"作为数据分隔符自动解析串口数据
//sp.start(device, baud_rate, "\r\n");// 按照用户自定义的协议自动解析,关于match_role如何使用请参考tcp部分说明
//sp.start(device, baud_rate, match_role);//sp.start(device, baud_rate, asio::transfer_at_least(1));
//sp.start(device, baud_rate, asio::transfer_exactly(10));
定时器
// 框架中提供了定时器功能,使用非常简单,如下(更多示例请参考example/timer/timer.cpp):
asio2::timer timer;
// 参数1表示定时器ID,参数2表示定时器间隔,参数3为定时器回调函数
timer.start_timer(1, std::chrono::seconds(1), [&]()
{printf("timer 1\n");if (true) // 满足某个条件时关闭定时器,当然也可以在其它任意地方关闭定时器timer.stop_timer(1);
});
// 执行5次的定时器,定时器id是字符串"id2",定时器间隔是2000毫秒
timer.start_timer("id2", 2000, 5, []()
{printf("timer id2, loop 5 times\n");
});
// 首次执行会延时5000毫秒的定时器,定时器id是5,定时器间隔是1000毫秒
timer.start_timer(5, std::chrono::milliseconds(1000), std::chrono::milliseconds(5000), []()
{printf("timer 5, loop infinite, delay 5 seconds\n");
});
// 所有的server,client,session等都继承了timer,所以server,client,session也可以使用定时器功能.

相关文章:

Asio2网络库

header only,不依赖boost库,不需要单独编译,在工程的Include目录中添加asio2路径,在源码中#include <asio2/asio2.hpp>即可使用;支持tcp, udp, http, websocket, rpc, ssl, icmp, serial_port;支持可靠UDP(基于KCP),支持SSL;TCP支持各种数据拆包功能(单个字符或字符串或用…...

Uniapp 微信小程序内打开web网页

技术栈&#xff1a;Uniapp Vue3 简介 实际业务中有时候会需要在本微信小程序内打开web页面&#xff0c;这时候可以封装一个路由页面专门用于此场景。 在路由跳转的时候携带路由参数&#xff0c;拼接上web url&#xff0c;接收页面进行参数接收即可。 实现 webview页面 新…...

学习线性表_3

单链表的删除 直接删除即可删除后要free //删除第i个位置的元素 //删除时L是不会变的&#xff0c;所以不需要加引用 bool ListDelect(LinkList L,int i) {//i 1,即删除头指针//拿到要删除结点的前一个结点LinkList p GetElem(L,i-1);if(NULLp){return false;}//拿到要删除的结…...

智能桥梁安全运行监测系统守护桥梁安全卫士

一、方案背景 桥梁作为交通基础设施中不可或缺的重要组成部分&#xff0c;其安全稳定的运行直接关联到广大人民群众的生命财产安全以及整个社会的稳定与和谐。桥梁不仅是连接两地的通道&#xff0c;更是经济发展和社会进步的重要纽带。为了确保桥梁的安全运行&#xff0c;桥梁安…...

Arrays.asList()新增报错,该怎么解决

一、前言 在 Java 开发中&#xff0c;Arrays.asList() 是一个常用的工具方法&#xff0c;它允许开发者快速将数组转换为列表。尽管这个方法非常方便&#xff0c;但许多开发者在使用时可能会遭遇一个常见的错误&#xff1a;尝试向由 Arrays.asList() 返回的列表中添加元素时抛出…...

28.UE5实现对话系统

目录 1.对话结构的设计&#xff08;重点&#xff09; 2.NPC对话接口的实现 2.1创建类型为pawn的蓝图 2.2创建对话接口 3.对话组件的创建 4.对话的UI设计 4.1UI_对话内容 4.2UI_对话选项 4.3UI_对话选项框 5.对话组件的逻辑实现 通过组件蓝图&#xff0c;也就是下图中的…...

会议直击|美格智能亮相2024紫光展锐全球合作伙伴大会,融合5G+AI共拓全球市场

11月26日&#xff0c;2024紫光展锐全球合作伙伴大会在上海举办&#xff0c;作为紫光展锐年度盛会&#xff0c;吸引来自全球的众多合作伙伴和行业专家、学者共同参与。美格智能与紫光展锐竭诚合作多年&#xff0c;共同面向5G、AI和卫星通信为代表的前沿科技&#xff0c;聚焦技术…...

IDEA报错: java: JPS incremental annotation processing is disabled 解决

起因 换了个电脑打开了之前某个老项目IDEA启动springcloud其中某个服务直接报错&#xff0c;信息如下 java: JPS incremental annotation processing is disabled. Compilation results on partial recompilation may be inaccurate. Use build process “jps.track.ap.depen…...

面对深度伪造:OWASP发布专业应对指南

从美国大选造谣视频到AI编写的网络钓鱼邮件&#xff0c;深度伪造&#xff08;deepfake&#xff09;诈骗和生成式人工智能攻击日益猖獗&#xff0c;人眼越来越难以辨识&#xff0c;企业迫切需要为网络安全团队制定AI安全事件响应指南。 深度伪造攻击威胁日益增加 全球范围内&…...

IDEA全局设置-解决maven加载过慢的问题

一、IDEA全局设置 注意&#xff1a;如果不是全局设置&#xff0c;仅仅针对某个项目有效&#xff1b;例在利用网上教程解决maven加载过慢的问题时&#xff0c;按步骤设置却得不到解决&#xff0c;原因就是没有在全局设置。 1.如何进行全局设置 a.在项目页面&#xff0c;点击f…...

【阅读笔记】Android广播的处理流程

关于Android的解析&#xff0c;有很多优质内容&#xff0c;看了后记录一下阅读笔记&#xff0c;也是一种有意义的事情&#xff0c; 今天就看看“那个写代码的”这位大佬关于广播的梳理&#xff0c; https://blog.csdn.net/a572423926/category_11509429.html https://blog.c…...

queue 和 Stack

import scala.collection.mutable //queue:队列.排队打饭.... //特点&#xff1a;先进先出 //Stack:栈 //特点&#xff1a;先进后出 class ob5 { def main(args: Array[String]): Unit { val q1 mutable.Queue(1) q1.enqueue(2)//入队 q1.enqueue(3)//入队 q1.enqueue(4)…...

C#窗体小程序计算器

使其能完成2个数的加、减、乘、除基本运算。界面如下图&#xff0c;单击相应的运算符按钮&#xff0c;则完成相应的运算&#xff0c;并将结果显示出来&#xff0c;同时不允许在结果栏中输入内容 代码如下&#xff1a; private void button1_Click(object sender, EventArgs e)…...

Linux——自定义简单shell

shell 自定义shell目标普通命令和内建命令&#xff08;补充&#xff09; shell实现实现原理实现代码 自定义shell 目标 能处理普通命令能处理内建命令要能帮助我们理解内建命令/本地变量/环境变量这些概念理解shell的运行 普通命令和内建命令&#xff08;补充&#xff09; …...

大模型开发和微调工具Llama-Factory-->WebUI

WebUI LLaMA-Factory 支持通过 WebUI 零代码微调大模型。 通过如下指令进入 WebUI llamafactory-cli webui# 如果是国内&#xff0c; # USE_MODELSCOPE_HUB 设为 1&#xff0c;表示模型从 ModelScope 魔搭社区下载。 # 避免从 HuggingFace 下载模型导致网速不畅 USE_MODELSC…...

【网络】应用层协议HTTPHTTPcookie与sessionHTTPS协议原理

主页&#xff1a;醋溜马桶圈-CSDN博客 专栏&#xff1a;计算机网络原理_醋溜马桶圈的博客-CSDN博客 gitee&#xff1a;mnxcc (mnxcc) - Gitee.com 目录 1.应用层协议HTTP 2.认识 URL 2.1 urlencode 和 urldecode 3.HTTP 协议请求与响应格式 3.1 HTTP 请求 3.2 HTTP 响应 …...

基于LSTM的文本多分类任务

概述&#xff1a; LSTM&#xff08;Long Short-Term Memory&#xff0c;长短时记忆&#xff09;模型是一种特殊的循环神经网络&#xff08;RNN&#xff09;架构&#xff0c;由Hochreiter和Schmidhuber于1997年提出。LSTM被设计来解决标准RNN在处理序列数据时遇到的长期依赖问题…...

Git忽略文件

在Git中&#xff0c;你可以通过修改 .gitignore 文件来忽略整个文件夹。以下是具体步骤&#xff1a; 打开或创建 .gitignore 文件 确保你的项目根目录下有一个 .gitignore 文件。如果没有&#xff0c;创建一个&#xff1a; touch .gitignore 在 .gitignore 文件中添加要忽略…...

Spring的事务管理

tx标签用于配置事务管理用于声明和配置事务的相关属性 transaction-manager指定一个事务管理器的引用&#xff0c;用于管理事务的生命周期。propagation指定事务的传播属性&#xff0c;决定了在嵌套事务中如何处理事务。isolation指定事务的隔离级别&#xff0c;用于控制事务之…...

java int值可以直接赋值给char类型 详解

在 Java 中&#xff0c;int 值可以直接赋值给 char 类型&#xff0c;但有一定的限制和机制。以下是详细的解释&#xff1a; 1. Java 中的 char 和 int 类型关系 char 的本质 char 是一个 16 位无符号整数类型&#xff0c;用于表示 Unicode 字符。范围为 0 到 65535&#xff0…...

淘宝商品数据获取:Python爬虫技术的应用与实践

引言 随着电子商务的蓬勃发展&#xff0c;淘宝作为中国最大的电商平台之一&#xff0c;拥有海量的商品数据。这些数据对于市场分析、消费者行为研究、商品推荐系统等领域具有极高的价值。然而&#xff0c;如何高效、合法地从淘宝平台获取这些数据&#xff0c;成为了一个技术挑…...

【力扣】389.找不同

问题描述 思路解析 只有小写字母&#xff0c;这种设计参数小的&#xff0c;直接桶排序我最开始的想法是使用两个不同的数组&#xff0c;分别存入他们单个字符转换后的值&#xff0c;然后比较是否相同。也确实通过了 看了题解后&#xff0c;发现可以优化&#xff0c;首先因为t相…...

何时在 SQL 中使用 CHAR、VARCHAR 和 VARCHAR(MAX)

在管理数据库表时&#xff0c;考虑 CHAR、VARCHAR 和 VARCHAR(MAX) 是必不可少的。此外&#xff0c;使用正确的工具&#xff08;例如dbForge Studio for SQL Server&#xff09; &#xff0c;与数据库相关的任务都会变得更加容易。它是针对 SQL Server 专业人员的强大的一体化解…...

pnpm安装electron出现postinstall$ node install.js报错

pnpm install --registryhttp://registry.npm.taobao.org安装依赖包的时候出现了postinstall$ node install.js报错 找到install.js 找到downloadArtifact方法&#xff0c;添加如下代码 mirrorOptions:{mirror:"http://npmmirror.com/mirrors/electron/"}http://n…...

如何从 Hugging Face 数据集中随机采样数据并保存为新的 Arrow 文件

如何从 Hugging Face 数据集中随机采样数据并保存为新的 Arrow 文件 在使用 Hugging Face 的数据集进行模型训练时&#xff0c;有时我们并不需要整个数据集&#xff0c;尤其是当数据集非常大时。为了节省存储空间和提高训练效率&#xff0c;我们可以从数据集中随机采样一部分数…...

Rook入门:打造云原生Ceph存储的全面学习路径(上)

文章目录 一.Rook简介二.Rook与Ceph架构2.1 Rook结构体系2.2 Rook包含组件2.3 Rook与kubernetes结合的架构图如下2.4 ceph特点2.5 ceph架构2.6 ceph组件 三.Rook部署Ceph集群3.1 部署条件3.2 获取rook最新版本3.3 rook资源文件目录结构3.4 部署Rook/CRD/Ceph集群3.5 查看rook部…...

AWS账号提额

Lightsail提额 控制台右上角&#xff0c;用户名点开&#xff0c;选择Service Quotas 在导航栏中AWS服务中找到lightsail点进去 在搜索框搜索instance找到相应的实例类型申请配额 4.根据自己的需求选择要提额的地区 5.根据需求来提升配额数量,提升小额配额等大约1小时生效 Ligh…...

计算机网络(三)

一个IP包&#xff0c;其数据长度为4900字节&#xff0c;通过一个MTU为1220字节的网络时&#xff0c;路由器的分片情况如何&#xff1f;请用图表的形式表示出路由器分片情况。 已知 IP 包的数据长度为 4900 字节&#xff0c;IP 首部长度通常为 20 字节&#xff0c;所以整个 IP …...

去哪儿Android面试题及参考答案

TCP 的三次握手与四次挥手过程是什么? TCP(Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的传输层通信协议 ,三次握手和四次挥手是其建立连接和断开连接的重要过程。 三次握手过程 第一次握手:客户端向服务器发送一个 SYN(同步序列号)包,其中包…...

探索温度计的数字化设计:一个可视化温度数据的Web图表案例

随着科技的发展&#xff0c;数据可视化在各个领域中的应用越来越广泛。在温度监控和展示方面&#xff0c;传统的温度计已逐渐被数字化温度计所取代。本文将介绍一个使用Echarts库创建的温度计Web图表&#xff0c;该图表通过动态数据可视化展示了温度值&#xff0c;并通过渐变色…...

JS API事件监听(绑定)

事件监听 语法 元素对象.addEventListener(事件监听,要执行的函数) 事件监听三要素 事件源&#xff1a;那个dom元素被事件触发了&#xff0c;要获取dom元素 事件类型&#xff1a;用说明方式触发&#xff0c;比如鼠标单击click、鼠标经过mouseover等 事件调用的函数&#x…...

【k8s】kube-state-metrics 和 metrics-server

kube-state-metrics 和 metrics-server 是 Kubernetes 生态系统中两个重要的监控组件&#xff0c;但它们的功能和用途有所不同。下面是对这两个组件的详细介绍&#xff1a; kube-state-metrics 功能&#xff1a; kube-state-metrics 是一个简单的服务&#xff0c;它监听 Kub…...

Linux设置开启启动脚本

1.问题 每次启动虚拟机需要手动启动网络&#xff0c;不然没有enss33选项 需要启动 /mnt/hgfs/dft_shared/init_env/initaial_env.sh 文件 2.解决方案 2.1 修改/etc/rc.d/rc.local 文件 /etc/rc.d/rc.local 文件会在 Linux 系统各项服务都启动完毕之后再被运行。所以你想要…...

数据结构-图(一)

文章目录 图一、图的基本概念&#xff08;一&#xff09;图的定义&#xff08;二&#xff09;有向图与无向图&#xff08;三&#xff09;顶点的度、入度与出度&#xff08;四&#xff09;路径、回路与连通图 二、图的存储及基本操作&#xff08;一&#xff09;邻接矩阵&#xf…...

SQL面试题——抖音SQL面试题 最近一笔有效订单

最近一笔有效订单 题目背景如下,现有订单表order,包含订单ID,订单时间,下单用户,当前订单是否有效 +---------+----------------------+----------+-----------+ | ord_id | ord_time | user_id | is_valid | +---------+----------------------+--------…...

【人工智能基础05】决策树模型

文章目录 一. 基础内容1. 决策树基本原理1.1. 定义1.2. 表示成条件概率 2. 决策树的训练算法2.1. 划分选择的算法信息增益&#xff08;ID3 算法&#xff09;信息增益比&#xff08;C4.5 算法&#xff09;基尼指数&#xff08;CART 算法&#xff09;举例说明&#xff1a;计算各个…...

远程桌面协助控制软件 RustDesk v1.3.3 多语言中文版

RustDesk 是一款开源的远程桌面软件&#xff0c;支持多平台操作&#xff0c;包括Windows、macOS、Linux、iOS、Android和Web。它提供端到端加密和基于角色的访问控制&#xff0c;确保安全性和隐私保护。使用简单&#xff0c;无需复杂配置&#xff0c;通过输入ID和密码即可快速连…...

git的学习笔记

一&#xff0c;git的安装 mac电脑的安装 xcode-select --install windows安装&#xff0c;用指令麻烦一些 随便找个视频观看看教程&#xff0c;去官网下载就可以了。 centos安装 sudo yum install git -y ubuntu安装 sudo apt-get install git -y 查看git安装的版本 git --ver…...

【目标检测】YOLO:深度挖掘YOLO的性能指标。

YOLO 性能指标 1、物体检测指标2、性能评估指标详解2.1 平均精度&#xff08;mAP&#xff09;2.2 每秒帧数&#xff08;FPS&#xff09;2.3 交并比&#xff08;IoU&#xff09;2.4 混淆矩阵&#xff08;Confusion Matrix&#xff09;2.5 F1-Score2.6 PR曲线&#xff08;Precisi…...

第一届帕鲁杯”应急响应“解析-上部分

这个帕鲁杯是一个模拟真实生产场景的应急响应题目&#xff0c;这个具有拓扑网络结构&#xff0c;考察综合能力以及对各个系统的应急响应 网络拓扑结构图如下 相关的资产情况如下 mysql01&#xff1a;10.66.1.10mysql02&#xff1a;10.66.1.11PC01&#xff1a;10.66.1.12PC02…...

前端http,ws拉流播放视频

可以在西瓜播放器官网APi调试拉取的视频流是否可以播放 类似http拉流地址为&#xff1a;http://localhost:8866/live?urlrtsp://admin:admin123192.168.11.50:554/cam/realmonitor?channel1&subtype01 <!DOCTYPE html> <html><head><meta charset…...

揭开广告引擎的神秘面纱:如何在0.1秒内精准匹配用户需求?

目录 一、广告系统与广告引擎介绍 &#xff08;一&#xff09;广告系统与广告粗分 &#xff08;二&#xff09;广告引擎在广告系统中的重要性分析 二、广告引擎整体架构和工作过程 &#xff08;一&#xff09;一般概述 &#xff08;二&#xff09;核心功能架构图 三、标…...

【2024】使用Docker搭建redis sentinel哨兵模式集群全流程(包含部署、测试、错误点指正以及直接部署)

目录&#x1f4bb; 前言**Docker Compose介绍**最终实现效果 一、搭建集群1、创建文件结构2、创建redis节点3、验证节点4、创建sentinel哨兵5、验证Sentinel功能 二、spring连接1、添加依赖2、添加配置3、启动测试 三、直接部署流程1、拉取配置2、修改端口创建 前言 本篇文章主…...

Spring WebFlux与Spring MVC

Spring WebFlux 是对 Spring Boot 项目中传统 Spring MVC 部分的一种替代选择&#xff0c;主要是为了解决现代 Web 应用在高并发和低延迟场景下的性能瓶颈。 1.WebFlux 是对 Spring MVC 的替代 架构替代&#xff1a; Spring MVC 使用的是基于 Servlet 规范的阻塞式模型&#xf…...

江协科技最新OLED保姆级移植hal库

江协科技最新OLED移植到hal库保姆级步骤 源码工程存档 工程和源码下载(密码 1i8y) 原因 江协科技的开源OLED封装的非常完美, 可以满足我们日常的大部分开发, 如果可以用在hal库 ,将是如虎添翼, 为我们开发调试又增加一个新的瑞士军刀, 所以我们接下来手把手的去官网移植源码…...

Vue框架开发一个简单的购物车(Vue.js)

让我们利用所学知识来开发一个简单的购物车 &#xff08;记得暴露属性和方法&#xff01;&#xff01;&#xff01;&#xff09; 首先来看一下最基本的一个html框架 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"&…...

探索嵌入式硬件设计:揭秘智能设备的心脏

目录 引言 嵌入式系统简介 嵌入式硬件设计的组成部分 设计流程 微控制器选择 原理图设计 PCB布局 编程与调试 系统集成与测试 深入理解微控制器 存储器管理 输入/输出接口 通信接口 电源管理 硬件抽象层&#xff08;HAL&#xff09; 操作系统&#xff08;OS&am…...

逆向攻防世界CTF系列42-reverse_re3

逆向攻防世界CTF系列42-reverse_re3 参考&#xff1a;CTF-reverse-reverse_re3&#xff08;全网最详细wp&#xff0c;超4000字有效解析&#xff09;_ctfreverse题目-CSDN博客 64位无壳 _int64 __fastcall main(__int64 a1, char **a2, char **a3) {int v4; // [rsp4h] [rbp-…...

AIGC时代 | 如何从零开始学网页设计及3D编程

文章目录 一、网页设计入门1. 基础知识2. 学习平台与资源3. 示例代码&#xff1a;简单的HTMLCSSJavaScript网页 二、3D编程入门1. 基础知识2. 学习平台与资源3. 示例代码&#xff1a;简单的Unity 3D游戏 《编程真好玩&#xff1a;从零开始学网页设计及3D编程》内容简介作者简介…...

EMall实践DDD模拟电商系统总结

目录 一、事件风暴 二、系统用例 三、领域上下文 四、架构设计 &#xff08;一&#xff09;六边形架构 &#xff08;二&#xff09;系统分层 五、系统实现 &#xff08;一&#xff09;项目结构 &#xff08;二&#xff09;提交订单功能实现 &#xff08;三&#xff0…...