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

2403C++,C++20协程库

原文

基于C++20协程的http--cinatra

cinatra是基于C++20无栈协程实现的跨平台,仅头,高性能,易用的http/https(http1.1),包括httpserverhttpclient,功能完备,不仅支持最普通的getpost等请求,还支持restfulapi,websocket,chunked,ranges,multipart,静态文件服务和反向代理等功能.

后面会分别介绍这些功能,文末也专门附上benchmark测试代码.

2.基本http请求

2.1.启动http服务器

#include <include/cinatra.hpp>
using namespace cinatra;
void start_server() {coro_http_server server(/*`thread_num=`*/std::thread::hardware_concurrency(), 9001);server.set_http_handler<GET>("/", [](coro_http_request &req, coro_http_response &resp) {resp.set_status_and_content(status_type::ok, "ok"); //`IO`线程中的响应});server.set_http_handler<GET, POST>("/in_thread_pool",[](coro_http_request &req,coro_http_response &resp) -> async_simple::coro::Lazy<void> {//在线程池中休息.co_await coro_io::post([&] {resp.set_status_and_content(status_type::ok, "ok in thread pool");});});server.sync_start();
}

几行代码即可创建一个http服务,先设置httpserver工作线程数和端口.然后设置http服务的url,httpmethod和对应的处理函数.
可在io线程或线程池中处理http请求.

2.2.client发请求

#include <include/cinatra.hpp>
using namespace cinatra;
async_simple::coro::Lazy<void> do_request() {coro_http_client client{};auto result = co_await client.async_get("http://127.0.0.1:9001/");assert(result.status == 200);assert(result.resp_body == "ok");for (auto [key, val] : result.resp_headers) {std::cout << key << ": " << val << "\n";}result = co_await client.async_get("/in_thread_pool");assert(result.status == 200);
}

httpclient异步请求服务器,返回结果中包括服务端响应的状态码,httpcontenthttp头,如果网络错误,可从result.net_err中取错码和错误message.

2.3.restfulapi

  coro_http_server server(/*`thread_num=`*/std::thread::hardware_concurrency(), 9001);server.set_http_handler<cinatra::GET, cinatra::POST>("/test2/{}/test3/{}",[](coro_http_request &req,coro_http_response &resp) -> async_simple::coro::Lazy<void> {co_await coro_io::post([&]() {CHECK(req.matches_.str(1) == "name");CHECK(req.matches_.str(2) == "test");resp.set_status_and_content(cinatra::status_type::ok, "hello world");});co_return;});server.set_http_handler<cinatra::GET, cinatra::POST>(R"(/numbers/(\d+)/test/(\d+))",[](coro_http_request &req, coro_http_response &response) {CHECK(req.matches_.str(1) == "100");CHECK(req.matches_.str(2) == "200");response.set_status_and_content(status_type::ok, "number regex ok");});server.set_http_handler<cinatra::GET, cinatra::POST>("/user/:id", [](coro_http_request &req, coro_http_response &response) {CHECK(req.params_["id"] == "cinatra");response.set_status_and_content(status_type::ok, "ok");});server.set_http_handler<cinatra::GET, cinatra::POST>("/user/:id/subscriptions",[](coro_http_request &req, coro_http_response &response) {CHECK(req.params_["id"] == "subid");response.set_status_and_content(status_type::ok, "ok");});server.set_http_handler<cinatra::GET, cinatra::POST>("/values/:x/:y/:z",[](coro_http_request &req, coro_http_response &response) {CHECK(req.params_["x"] == "guilliman");CHECK(req.params_["y"] == "cawl");CHECK(req.params_["z"] == "yvraine");response.set_status_and_content(status_type::ok, "ok");});server.async_start();coro_http_client client;client.get("http://127.0.0.1:9001/test2/name/test3/test");client.get("http://127.0.0.1:9001/numbers/100/test/200");client.get("http://127.0.0.1:9001/user/cinatra");client.get("http://127.0.0.1:9001/user/subid/subscriptions");client.get("http://127.0.0.1:9001/value/guilliman/cawl/yvraine");

2.4. https访问

#ifdef CINATRA_ENABLE_SSLcoro_http_client client{};result = co_await client.async_get("https://www.taobao.com");assert(result.status == 200);
#endif

访问https网站时,确保已安装了openssl并开启了ENABLE_SSL.

3. websocket

  cinatra::coro_http_server server(1, 9001);server.set_http_handler<cinatra::GET>("/ws_echo",[](cinatra::coro_http_request &req,cinatra::coro_http_response &resp) -> async_simple::coro::Lazy<void> {cinatra::websocket_result result{};while (true) {result = co_await req.get_conn()->read_websocket();if (result.ec) {break;}if (result.type == cinatra::ws_frame_type::WS_CLOSE_FRAME) {REQUIRE(result.data == "test close");break;}auto ec = co_await req.get_conn()->write_websocket(result.data);if (ec) {break;}}});server.sync_start();

在协程处理函数中,while循环异步读写websocket数据.

client端:

  cinatra::coro_http_client client{};std::string message(100, 'x');client.on_ws_close([](std::string_view reason) {std::cout << "web socket close " << reason << std::endl;});client.on_ws_msg([message](cinatra::resp_data data) {if (data.net_err) {std::cout << "ws_msg net error " << data.net_err.message() << "\n";return;}std::cout << "ws msg len: " << data.resp_body.size() << std::endl;REQUIRE(data.resp_body == message);});co_await client.async_ws_connect("ws://127.0.0.1:9001/ws_echo");co_await client.async_send_ws(message);co_await client.async_send_ws_close("test close");

client设置读回调和close回调分别处理收到的websocket消息和websocketclose消息.

4.静态文件服务

  std::string filename = "temp.txt";create_file(filename, 64);coro_http_server server(1, 9001);std::string virtual_path = "download";std::string files_root_path = "";  //当前路径server.set_static_res_dir(virtual_path,files_root_path);//在服务器启动之前设置此项,如果添加新文件,则需要重启服务器.server.async_start();coro_http_client client{};auto result =co_await client.async_get("http://127.0.0.1:9001/download/temp.txt");assert(result.status == 200);assert(result.resp_body.size() == 64);

服务端设置虚路径和实际文件路径,下载文件时输入虚路径实际路径下的文件名即可实现下载.

5.反向代理

假设有3个服务器需要代理,代理服务器根据负载均衡算法来选择其中的一个来访问并把结果返回给客户.

5.1.先启动3个被代理的服务器

  cinatra::coro_http_server web_one(1, 9001);web_one.set_http_handler<cinatra::GET, cinatra::POST>("/",[](coro_http_request &req,coro_http_response &response) -> async_simple::coro::Lazy<void> {co_await coro_io::post([&]() {response.set_status_and_content(status_type::ok, "web1");});});web_one.async_start();cinatra::coro_http_server web_two(1, 9002);web_two.set_http_handler<cinatra::GET, cinatra::POST>("/",[](coro_http_request &req,coro_http_response &response) -> async_simple::coro::Lazy<void> {co_await coro_io::post([&]() {response.set_status_and_content(status_type::ok, "web2");});});web_two.async_start();cinatra::coro_http_server web_three(1, 9003);web_three.set_http_handler<cinatra::GET, cinatra::POST>("/", [](coro_http_request &req, coro_http_response &response) {response.set_status_and_content(status_type::ok, "web3");});web_three.async_start();

5.2.启动代理服务器

设置roundrobin策略的代理服务器:

  coro_http_server proxy_rr(2, 8091);proxy_rr.set_http_proxy_handler<GET, POST>("/rr", {"127.0.0.1:9001", "127.0.0.1:9002", "127.0.0.1:9003"},coro_io::load_blance_algorithm::RR);proxy_rr.sync_start();

设置random策略的代理服务器:

  coro_http_server proxy_random(2, 8092);proxy_random.set_http_proxy_handler<GET, POST>("/random", {"127.0.0.1:9001", "127.0.0.1:9002", "127.0.0.1:9003"});proxy_random.sync_start();

设置weightroundrobin策略的代理服务器:

  coro_http_server proxy_wrr(2, 8090);proxy_wrr.set_http_proxy_handler<GET, POST>("/wrr", {"127.0.0.1:9001", "127.0.0.1:9002", "127.0.0.1:9003"},coro_io::load_blance_algorithm::WRR, {10, 5, 5});proxy_wrr.sync_start();  

5.3.client请求代理服务器

  coro_http_client client_rr;resp_data resp_rr = client_rr.get("http://127.0.0.1:8091/rr");assert(resp_rr.resp_body == "web1");resp_rr = client_rr.get("http://127.0.0.1:8091/rr");assert(resp_rr.resp_body == "web2");resp_rr = client_rr.get("http://127.0.0.1:8091/rr");assert(resp_rr.resp_body == "web3");coro_http_client client_wrr;resp_data resp = client_wrr.get("http://127.0.0.1:8090/wrr");assert(resp.resp_body == "web1");resp = client_wrr.get("http://127.0.0.1:8090/wrr");assert(resp.resp_body == "web1");resp = client_wrr.get("http://127.0.0.1:8090/wrr");assert(resp.resp_body == "web2");resp = client_wrr.get("http://127.0.0.1:8090/wrr");assert(resp.resp_body == "web3");  

6.增加切面

6.1.创建任意切面

struct log_t {bool before(coro_http_request &, coro_http_response &) {std::cout << "before log" << std::endl;return true;}bool after(coro_http_request &, coro_http_response &res) {std::cout << "after log" << std::endl;res.add_header("aaaa", "bbcc");return true;}
};
struct get_data {bool before(coro_http_request &req, coro_http_response &res) {req.set_aspect_data("hello world");return true;}
};

切面是实现了beforeafter函数的类.

6.2.应用切面

async_simple::coro::Lazy<void> use_aspects() {coro_http_server server(1, 9001);server.set_http_handler<GET>("/get",[](coro_http_request &req, coro_http_response &resp) {auto val = req.get_aspect_data();assert(val[0] == "hello world");resp.set_status_and_content(status_type::ok, "ok");},log_t{}, get_data{});//设置了两个切面,可按需设置任意个切面server.async_start();coro_http_client client{};auto result = co_await client.async_get("http://127.0.0.1:9001/get");assert(result.status == 200);
}

注册httphandler时设置了两个切面,该url的处理会先进入切面,切面返回true,才会继续往下执行业务逻辑,如果返回false则不会执行后续逻辑,返回false时,要在切面中调用resp.set_status_and_content设置状态码返回内容.

7.chunked,ranges,multipart

7.1.chunked上传下载

chunked协议适合大文件上传和下载:

async_simple::coro::Lazy<void> chunked_upload_download() {coro_http_server server(1, 9001);server.set_http_handler<GET, POST>("/chunked",[](coro_http_request &req,coro_http_response &resp) -> async_simple::coro::Lazy<void> {assert(req.get_content_type() == content_type::chunked);chunked_result result{};std::string content;while (true) {result = co_await req.get_conn()->read_chunked();if (result.ec) {co_return;}if (result.eof) {break;}content.append(result.data);}std::cout << "content size: " << content.size() << "\n";std::cout << content << "\n";resp.set_format_type(format_type::chunked);resp.set_status_and_content(status_type::ok, "chunked ok");});server.set_http_handler<GET, POST>("/write_chunked",[](coro_http_request &req,coro_http_response &resp) -> async_simple::coro::Lazy<void> {resp.set_format_type(format_type::chunked);bool ok;if (ok = co_await resp.get_conn()->begin_chunked(); !ok) {co_return;}std::vector<std::string> vec{"hello", " world", " ok"};for (auto &str : vec) {if (ok = co_await resp.get_conn()->write_chunked(str); !ok) {co_return;}}ok = co_await resp.get_conn()->end_chunked();});server.sync_start();result = co_await client.async_get("http://127.0.0.1:9001/write_chunked");assert(result.status == 200);assert(result.resp_body == "hello world ok");
}

clientchunked上传文件

coro_http_client client{};std::string filename = "test.txt";create_file(filename, 1010);coro_io::coro_file file{};co_await file.async_open(filename, coro_io::flags::read_only);std::string buf;detail::resize(buf, 100);auto fn = [&file, &buf]() -> async_simple::coro::Lazy<read_result> {auto [ec, size] = co_await file.async_read(buf.data(), buf.size());co_return read_result{buf, file.eof(), ec};};auto result = co_await client.async_upload_chunked("http://127.0.0.1:9001/chunked"sv, http_method::POST, std::move(fn));

client读文件分块上传文件整个过程都是异步的.

clientchunked下载文件:

  auto result = co_await client.async_get("http://127.0.0.1:9001/write_chunked");assert(result.status == 200);assert(result.resp_body == "hello world ok");

这样下载内存中,也可下载文件中.

  auto result = co_await client.async_download("http://127.0.0.1:9001/write_chunked", "download.txt");CHECK(std::filesystem::file_size("download.txt")==1010);

7.2.ranges下载

async_simple::coro::Lazy<void> byte_ranges_download() {create_file("test_multiple_range.txt", 64);coro_http_server server(1, 8090);server.set_static_res_dir("", "");server.async_start();std::this_thread::sleep_for(200ms);std::string uri = "http://127.0.0.1:8090/test_multiple_range.txt";{std::string filename = "test1.txt";std::error_code ec{};std::filesystem::remove(filename, ec);coro_http_client client{};resp_data result = co_await client.async_download(uri, filename, "1-10");assert(result.status == 206);assert(std::filesystem::file_size(filename) == 10);filename = "test2.txt";std::filesystem::remove(filename, ec);result = co_await client.async_download(uri, filename, "10-15");assert(result.status == 206);assert(std::filesystem::file_size(filename) == 6);}{coro_http_client client{};std::string uri = "http://127.0.0.1:8090/test_multiple_range.txt";client.add_header("Range", "bytes=1-10,20-30");auto result = co_await client.async_get(uri);assert(result.status == 206);assert(result.resp_body.size() == 21);std::string filename = "test_ranges.txt";client.add_header("Range", "bytes=0-10,21-30");result = co_await client.async_download(uri, filename);assert(result.status == 206);assert(fs::file_size(filename) == 21);}
}

7.3.multipart上传下载

  coro_http_server server(1, 8090);server.set_http_handler<cinatra::PUT, cinatra::POST>("/multipart_upload",[](coro_http_request &req,coro_http_response &resp) -> async_simple::coro::Lazy<void> {assert(req.get_content_type() == content_type::multipart);auto boundary = req.get_boundary();multipart_reader_t multipart(req.get_conn());while (true) {auto part_head = co_await multipart.read_part_head();if (part_head.ec) {co_return;}std::cout << part_head.name << "\n";std::cout << part_head.filename << "\n";std::shared_ptr<coro_io::coro_file> file;std::string filename;if (!part_head.filename.empty()) {file = std::make_shared<coro_io::coro_file>();filename = std::to_string(std::chrono::system_clock::now().time_since_epoch().count());size_t pos = part_head.filename.rfind('.');if (pos != std::string::npos) {auto extent = part_head.filename.substr(pos);filename += extent;}std::cout << filename << "\n";co_await file->async_open(filename, coro_io::flags::create_write);if (!file->is_open()) {resp.set_status_and_content(status_type::internal_server_error, "file open failed");co_return;}}auto part_body = co_await multipart.read_part_body(boundary);if (part_body.ec) {co_return;}if (!filename.empty()) {auto ec = co_await file->async_write(part_body.data.data(), part_body.data.size());if (ec) {co_return;}file->close();CHECK(fs::file_size(filename) == 1024);}else {std::cout << part_body.data << "\n";}if (part_body.eof) {break;}}resp.set_status_and_content(status_type::ok, "ok");co_return;});server.async_start();std::string filename = "test_1024.txt";create_file(filename);coro_http_client client{};std::string uri = "http://127.0.0.1:8090/multipart_upload";client.add_str_part("test", "test value");client.add_file_part("test file", filename);auto result =async_simple::coro::syncAwait(client.async_upload_multipart(uri));CHECK(result.status == 200);

8.benchmarkcode

8.1. brpc http benchmark code
DEFINE_int32(port, 9001, "TCP Port of this server");
DEFINE_int32(idle_timeout_s, -1,"Connection will be closed if there is no ""read/write operations during the last `idle_timeout_s'");
class HttpServiceImpl : public HttpService {
public:HttpServiceImpl() {}virtual ~HttpServiceImpl() {}void Echo(google::protobuf::RpcController *cntl_base, const HttpRequest *,HttpResponse *, google::protobuf::Closure *done) {brpc::ClosureGuard done_guard(done);brpc::Controller *cntl = static_cast<brpc::Controller *>(cntl_base);std::string date_str{get_gmt_time_str()};cntl->http_response().SetHeader("Date", date_str);cntl->http_response().SetHeader("Server", "brpc");cntl->http_response().set_content_type("text/plain");butil::IOBufBuilder os;os << "hello, world!";os.move_to(cntl->response_attachment());}
};
int main(int argc, char *argv[]) {GFLAGS_NS::ParseCommandLineFlags(&argc, &argv, true);brpc::Server server;example::HttpServiceImpl http_svc;if (server.AddService(&http_svc, brpc::SERVER_DOESNT_OWN_SERVICE) != 0) {LOG(ERROR) << "Fail to add http_svc";return -1;}brpc::ServerOptions options;options.idle_timeout_sec = FLAGS_idle_timeout_s;if (server.Start(FLAGS_port, &options) != 0) {LOG(ERROR) << "Fail to start HttpServer";return -1;}server.RunUntilAskedToQuit();return 0;
}

8.2.drogonbenchmarkcode

#include <drogon/drogon.h>
using namespace drogon;
int main() {app().setLogPath("./").setLogLevel(trantor::Logger::kWarn).addListener("0.0.0.0", 9001).setThreadNum(0).registerSyncAdvice([](const HttpRequestPtr &req) -> HttpResponsePtr {auto response = HttpResponse::newHttpResponse();response->setBody("Hello, world!");return response;}).run();
}

8.3.nginxhttp配置

user nginx;
worker_processes auto;
worker_cpu_affinity auto;
error_log stderr error;
#worker_rlimit_nofile 1024000;
timer_resolution 1s;
daemon off;
events {worker_connections 32768;multi_accept off; #default
}
http {include /etc/nginx/mime.types;access_log off;server_tokens off;msie_padding off;sendfile off; #defaulttcp_nopush off; #defaulttcp_nodelay on; #defaultkeepalive_timeout 65;keepalive_disable none; #default msie6keepalive_requests 300000; #default 100server {listen 9001 default_server reuseport deferred fastopen=4096;root /;location = /plaintext {default_type text/plain;return 200 "Hello, World!";}}
}

8.4.cinatrabenchmarkcode

#include <cinatra.hpp>
using namespace cinatra;
using namespace std::chrono_literals;
int main() {coro_http_server server(std::thread::hardware_concurrency(), 8090);server.set_http_handler<GET>("/plaintext", [](coro_http_request& req, coro_http_response& resp) {resp.get_conn()->set_multi_buf(false);resp.set_content_type<resp_content_type::txt>();resp.set_status_and_content(status_type::ok, "Hello, world!");});server.sync_start();
}

相关文章:

2403C++,C++20协程库

原文 基于C20协程的http库--cinatra cinatra是基于C20无栈协程实现的跨平台,仅头,高性能,易用的http/https库(http1.1),包括httpserver和httpclient,功能完备,不仅支持最普通的getpost等请求,还支持restfulapi,websocket,chunked,ranges,multipart,静态文件服务和反向代理等功…...

mybatis动态加载mapper.xml

mybatis动态加载mapper.xml mybatis动态加载mapper.xml、springboot mybatis动态加载mapper.xml 教程连接&#xff1a;https://blog.csdn.net/weixin_44480167/article/details/136356398...

安卓类加载机制

目录 一、ClassLoader介绍二、双亲委托机制三、类的加载过程 一、ClassLoader介绍 任何一个 Java 程序都是由一个或多个 class 文件组成&#xff0c;在程序运行时&#xff0c;需要将 class 文件加载到 JVM 中才可以使用&#xff0c;负责加载这些 class 文件的就是 Java 的类加…...

FPGA高端项目:FPGA基于GS2971的SDI视频接收+HLS图像缩放+多路视频拼接,提供4套工程源码和技术支持

目录 1、前言免责声明 2、相关方案推荐本博已有的 SDI 编解码方案本方案的SDI接收转HDMI输出应用本方案的SDI接收图像缩放应用本方案的SDI接收纯verilog图像缩放纯verilog多路视频拼接应用本方案的SDI接收HLS动态字符叠加输出应用本方案的SDI接收HLS多路视频融合叠加应用本方案…...

[计算机网络]--五种IO模型和select

前言 作者&#xff1a;小蜗牛向前冲 名言&#xff1a;我可以接受失败&#xff0c;但我不能接受放弃 如果觉的博主的文章还不错的话&#xff0c;还请点赞&#xff0c;收藏&#xff0c;关注&#x1f440;支持博主。如果发现有问题的地方欢迎❀大家在评论区指正 目录 一、五种IO…...

【力扣经典面试题】14. 最长公共前缀

目录 一、题目描述 二、解题思路 三、解题步骤 四、代码实现&#xff08;C版详细注释&#xff09; 五、总结 欢迎点赞关注哦&#xff01;创作不易&#xff0c;你的支持是我的不竭动力&#xff0c;更多精彩等你哦。 一、题目描述 编写一个函数来查找字符串数组中的最长公共前缀。…...

Linux操作系统的vim常用命令和vim 键盘图

在vi编辑器的命令模式下&#xff0c;命令的组成格式是&#xff1a;nnc。其中&#xff0c;字符c是命令&#xff0c;nn是整数值&#xff0c;它表示该命令将重复执行nn次&#xff0c;如果不给出重复次数的nn值&#xff0c;则命令将只执行一次。例如&#xff0c;在命令模式下按j键表…...

SpringCloudGateway工作原理与链路图

SpringCloudGateway基本介绍 Spring Cloud Gateway 构建于Spring Boot 2.x、 Spring WebFlux和Project Reactor之上。因此,在使用 Spring Cloud Gateway 时,您可能不会应用许多熟悉的同步库(例如 Spring Data 和 Spring Security)和模式。 Spring Cloud Gateway 需要 Sprin…...

VUE2与VUE3之间的主要区别

当谈到 Vue.js 的版本时&#xff0c;Vue 2 和 Vue 3 是最常被提及的两个版本。下面是 Vue 2 和 Vue 3 之间的一些主要区别&#xff1a; 1. 性能提升&#xff1a; Vue 3 在底层核心重写了响应式系统&#xff0c;采用了 Proxy 对象&#xff0c;大幅提高了性能。Vue 3 还引入了静…...

CSS浮动实战,经典好文

零基础学web前端开发要怎么去学? 首先要学习的就是基础知识&#xff1a;html、css和JavaScript。HTML是内容&#xff0c;CSS是表现&#xff0c;JavaScript是行为。前端开发的门槛其实非常低&#xff0c;与服务器端语言先慢后快的学习曲线相比&#xff0c;前端开发的学习曲线是…...

如何搭建Nacos集群

1.搭建Nacos集群 众所周知&#xff0c;在实际的工作中&#xff0c;Nacos的生成环境下一定要部署为集群状态 其中包含3个nacos节点&#xff0c;然后一个负载均衡器代理3个Nacos。这里负载均衡器可以使用nginx。 我们计划的集群结构&#xff1a; 我就直接在本机上开三个Nacos来搭…...

未来已来!AI大模型引领科技革命

未来已来&#xff01;AI大模型正以惊人的速度引领着科技革命。随着科技的发展&#xff0c;人工智能在各个领域展现出了非凡的能力和潜力&#xff0c;大模型更是成为了科技领域的明星。从自然语言处理到图像识别&#xff0c;从智能推荐到语音识别&#xff0c;大模型的应用正在改…...

VBA如何记录单元格中字符内容和格式

实例需求&#xff1a;Excel单元格中的字符可以设置不同的字体格式&#xff08;大小、颜色等&#xff09;&#xff0c;有时需要将这些信息保存起来&#xff0c;以便于后续代码的处理&#xff08;例如替换后恢复原字体颜色&#xff0c;或者统计某种指定格式字符个数等等&#xff…...

逻辑漏洞(pikachu)

#水平&#xff0c;垂直越权&#xff0c;未授权访问 通过个更换某个id之类的身份标识&#xff0c;从而使A账号获取&#xff08;修改、删除&#xff09;B账号数据 使用低权限身份的账号&#xff0c;发送高权限账号才能有的请求&#xff0c;获得其高权限操作 通过删除请求中的认…...

阿里云服务器2核4G多少钱?支持多少在线?并发数性能测试

阿里云2核4G服务器多少钱一年&#xff1f;2核4G配置1个月多少钱&#xff1f;2核4G服务器30元3个月、轻量应用服务器2核4G4M带宽165元一年、企业用户2核4G5M带宽199元一年。可以在阿里云CLUB中心查看 aliyun.club 当前最新2核4G服务器精准报价、优惠券和活动信息。 阿里云官方2…...

粘包与拆包

优质博文&#xff1a;IT-BLOG-CN 一、粘包出现的原因 服务端与客户端没有约定好要使用的数据结构。Socket Client实际是将数据包发送到一个缓存buffer中&#xff0c;通过buffer刷到数据链路层。因服务端接收数据包时&#xff0c;不能断定数据包1何时结束&#xff0c;就有可能出…...

基于QGIS的研究区域遥感影像裁切下载方法-以岳麓区为例

目录 前言 一、数据说明 1、遥感影像 2、矢量范围 二、按矢量范围导出 1、第一步、导出影像 2、第二步、设置输出格式 3、设置裁切范围 4、设置分辨率 三、按矢量范围掩膜 1、第一步、打开裁剪工具 2、第二步、参数设置 ​编辑 3、执行掩膜 四、webgis支持 1、生成运行…...

YOLOv8-Openvino-ByteTrack【CPU】

纯检测如下&#xff1a; YOLOv5-Openvino和ONNXRuntime推理【CPU】 YOLOv6-Openvino和ONNXRuntime推理【CPU】 YOLOv8-Openvino和ONNXRuntime推理【CPU】 YOLOv9-Openvino和ONNXRuntime推理【CPU】 注&#xff1a;YOLOv8和YOLOv9代码内容基本一致&#xff01; 全部代码Github&…...

【Linux命令】tload

tload 显示系统负载状况。 详细 tload命令以图形化的方式输出当前系统的平均负载到指定的终端。假设不给予终端机编号&#xff0c;则会在执行tload指令的终端机显示负载情形。 语法 tload &#xff08;选项&#xff09;&#xff08;参数&#xff09;选项 -s : 指定闲时的…...

Qt 通过pdfium将网络上的pdf显示为图片

前言 遇到个需求&#xff0c;就是在qt客户端显示服务器上的pdf文档&#xff0c;文档以base64格式返回给客户端。以下是实现方法&#xff1a; 1、在pro文件增加以下代码&#xff1a; INCLUDEPATH $$PWD/PDFiumSDK/include/publicDEPENDPATH $$PWD/PDFiumSDK/include/public…...

Java 语言特性(面试系列1)

一、面向对象编程 1. 封装&#xff08;Encapsulation&#xff09; 定义&#xff1a;将数据&#xff08;属性&#xff09;和操作数据的方法绑定在一起&#xff0c;通过访问控制符&#xff08;private、protected、public&#xff09;隐藏内部实现细节。示例&#xff1a; public …...

Leetcode 3576. Transform Array to All Equal Elements

Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接&#xff1a;3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到&#xf…...

基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销&#xff0c;平衡网络负载&#xff0c;延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...

Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件

今天呢&#xff0c;博主的学习进度也是步入了Java Mybatis 框架&#xff0c;目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学&#xff0c;希望能对大家有所帮助&#xff0c;也特别欢迎大家指点不足之处&#xff0c;小生很乐意接受正确的建议&…...

无法与IP建立连接,未能下载VSCode服务器

如题&#xff0c;在远程连接服务器的时候突然遇到了这个提示。 查阅了一圈&#xff0c;发现是VSCode版本自动更新惹的祸&#xff01;&#xff01;&#xff01; 在VSCode的帮助->关于这里发现前几天VSCode自动更新了&#xff0c;我的版本号变成了1.100.3 才导致了远程连接出…...

理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端

&#x1f31f; 什么是 MCP&#xff1f; 模型控制协议 (MCP) 是一种创新的协议&#xff0c;旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议&#xff0c;它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...

css的定位(position)详解:相对定位 绝对定位 固定定位

在 CSS 中&#xff0c;元素的定位通过 position 属性控制&#xff0c;共有 5 种定位模式&#xff1a;static&#xff08;静态定位&#xff09;、relative&#xff08;相对定位&#xff09;、absolute&#xff08;绝对定位&#xff09;、fixed&#xff08;固定定位&#xff09;和…...

USB Over IP专用硬件的5个特点

USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中&#xff0c;从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备&#xff08;如专用硬件设备&#xff09;&#xff0c;从而消除了直接物理连接的需要。USB over IP的…...

Python Einops库:深度学习中的张量操作革命

Einops&#xff08;爱因斯坦操作库&#xff09;就像给张量操作戴上了一副"语义眼镜"——让你用人类能理解的方式告诉计算机如何操作多维数组。这个基于爱因斯坦求和约定的库&#xff0c;用类似自然语言的表达式替代了晦涩的API调用&#xff0c;彻底改变了深度学习工程…...

(一)单例模式

一、前言 单例模式属于六大创建型模式,即在软件设计过程中,主要关注创建对象的结果,并不关心创建对象的过程及细节。创建型设计模式将类对象的实例化过程进行抽象化接口设计,从而隐藏了类对象的实例是如何被创建的,封装了软件系统使用的具体对象类型。 六大创建型模式包括…...