在当今这个互联互通的世界中,数据在各种设备和平台之间自由流动,而 libcurl,就像一把跨平台的万能工具,为开发者提供了处理各种网络数据传输任务所需的强大功能。它不仅是一个库,更是一种通用的解决方案,可以应对从桌面应用到嵌入式系统等各种场景的挑战。

核心:libcurl 是什么?

libcurl 是一个免费、开源且高度可移植的客户端 URL 传输库 1。它支持广泛的协议,包括 HTTP(S)、FTP(S)、SCP、SFTP、TFTP、TELNET、LDAP(S)、MQTT、IMAP、POP3、SMTP、RTMP 和 RTSP。这意味着,无论你的应用需要与哪种类型的网络服务进行通信,libcurl 都能提供支持。

为什么 libcurl 如此受欢迎?

  • 广泛的协议支持: libcurl 支持几乎所有主流的网络协议,使其成为处理各种数据传输场景的理想选择 12。
  • 卓越的跨平台能力: 这是 libcurl 最重要的特性之一。 无论你的应用运行在 Windows、Linux、macOS、iOS、Android、FreeBSD、OpenBSD 甚至是嵌入式系统上,libcurl 都能提供一致的 API 和功能 1。这极大地简化了跨平台应用的开发和维护。
  • 高度的灵活性和可定制性: libcurl 提供了大量的选项,允许你精细地控制数据传输的各个方面,例如超时时间、重试次数、SSL 证书验证、HTTP 头设置等等。
  • 卓越的性能: libcurl 使用 C 语言编写,并经过了大量的优化,以提供卓越的性能。它还支持连接池、HTTP/2 和 HTTP/HTTP/3 等技术,进一步提升数据传输效率 2。
  • 强大的安全性: libcurl 支持 SSL/TLS 加密,并提供了各种安全选项,例如证书验证、主机名验证等,以确保数据传输的安全性。
  • 成熟度和稳定性: libcurl 已经存在了 20 多年,经过了无数项目的验证,是一个非常成熟和稳定的库 1。
  • 活跃的社区: libcurl 拥有一个庞大而活跃的社区,你可以从中获得支持、分享经验,并参与到 libcurl 的开发中。

libcurl 的高级特性 (不仅仅是下载文件)

  • 异步 API: libcurl 提供了异步 API,允许你在不阻塞主线程的情况下执行数据传输任务。这对于构建高性能的网络应用至关重要。
  • 多路复用: libcurl 支持多路复用技术,允许你在单个连接上同时传输多个数据流。这可以显著提高数据传输效率,尤其是在高并发场景下。
  • HTTP/2 和 HTTP/3: libcurl 支持最新的 HTTP/2 和 HTTP/3 协议,这些协议提供了更高的性能和更低的延迟。
  • WebSocket: libcurl 支持 WebSocket 协议,允许你构建实时的双向通信应用。
  • 自定义协议处理: libcurl 允许你自定义协议处理程序,以支持非标准的或私有的协议。

libcurl 的常见使用场景 (从 FTP 客户端到嵌入式系统)

  • 构建 FTP 客户端: 使用 libcurl 可以轻松地实现一个功能完善的 FTP 客户端,支持文件上传、下载、目录浏览等功能 15。
  • 开发 API 客户端: 许多应用需要与各种 Web API 进行交互,例如获取天气信息、发送消息、支付等等。libcurl 可以帮助你轻松地发送 HTTP 请求,并处理 API 返回的数据。
  • 实现网络爬虫: 网络爬虫需要抓取大量的网页内容。libcurl 可以帮助你高效地下载网页,并处理 Cookie、重定向等问题。
  • 在物联网 (IoT) 设备中使用: IoT 设备通常需要与云服务器进行通信,例如发送传感器数据、接收控制指令等等。libcurl 可以被移植到各种嵌入式系统中,用于实现网络数据传输功能。
  • 音视频流媒体: libcurl 可以用于实现音视频流媒体的客户端,支持 HTTP Live Streaming (HLS)、Dynamic Adaptive Streaming over HTTP (DASH) 等协议。
  • 游戏开发: 在线游戏需要与游戏服务器进行通信,例如发送玩家的位置信息、接收游戏状态更新等等。libcurl 可以用于实现这些网络通信功能。
  • 金融交易系统: 金融交易系统需要与交易所进行通信,例如发送交易指令、接收市场数据等等。libcurl 可以用于实现这些网络通信功能,并保证数据传输的安全性。

libcurl 的跨平台特性及安装使用

libcurl 的跨平台特性是其最大的优势之一。以下是在不同平台下安装和使用 libcurl 的简要说明:

  • Windows:
    • 安装: 可以从 https://curl.se/windows/ 下载预编译的 libcurl 二进制文件。
    • 使用: 在 Visual Studio 等 IDE 中,需要配置包含目录和库目录,并链接 libcurl.lib
  • Linux (Debian/Ubuntu):
    • 安装: 使用 apt-get 命令安装:sudo apt-get install libcurl4-openssl-dev
    • 使用: 在编译时,需要链接 libcurl 库:gcc your_program.c -lcurl
  • Linux (Red Hat/CentOS):
    • 安装: 使用 yum 命令安装:sudo yum install libcurl-devel
    • 使用: 在编译时,需要链接 libcurl 库:gcc your_program.c -lcurl

**libcurl 与 Qt 的完美结合 **

Qt 是一个强大的跨平台应用开发框架,提供了丰富的 GUI 组件和网络编程接口。虽然 Qt 提供了 QNetworkAccessManager 等网络编程类,但在某些情况下,libcurl 仍然是更好的选择。

  • 为什么在 Qt 中使用 libcurl?

    • 更底层的控制: libcurl 提供了更底层的控制,允许你精细地调整数据传输的各个方面。
    • 更广泛的协议支持: libcurl 支持一些 QNetworkAccessManager 不支持的协议,例如 SCP、SFTP 等。
    • 某些特定场景下的性能优势: 在某些特定场景下,libcurl 的性能可能优于 QNetworkAccessManager
  • 如何在 Qt 中使用 libcurl?

    1. 直接使用 libcurl 的 C API: 这是最常见的方式。你需要包含 curl/curl.h 头文件,并链接 libcurl 库。
    2. 使用 Qt 封装的 libcurl 库: 例如 QtilitiesKFTP。这些库提供了更 Qt 风格的 API,使用起来更方便。
    3. 使用 QProcess 调用 curl 命令行工具: 这种方式比较简单,但性能较差。
  • 示例代码:

    1. 直接使用 libcurl 的 C API:

    #include <QCoreApplication>
    #include <QDebug>
    #include <curl/curl.h>
    #include <QFile>size_t write_data(void *buffer, size_t size, size_t nmemb, void *userp) {QFile *file = (QFile*)userp;return file->write((char*)buffer, size * nmemb);
    }int main(int argc, char *argv[]) {QCoreApplication a(argc, argv);CURL *curl;CURLcode res;QFile file("output.txt");if (!file.open(QIODevice::WriteOnly)) {qDebug() << "Failed to open file for writing";return -1;}curl_global_init(CURL_GLOBAL_DEFAULT);curl = curl_easy_init();if(curl) {curl_easy_setopt(curl, CURLOPT_URL, "https://www.example.com");curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);curl_easy_setopt(curl, CURLOPT_WRITEDATA, &file);res = curl_easy_perform(curl);curl_easy_cleanup(curl);if(res == CURLE_OK) {qDebug() << "Download successful!";} else {qDebug() << "Error:" << curl_easy_strerror(res);}}curl_global_cleanup();file.close();return a.exec();
    }
    

    2. 使用 QProcess 调用 curl 命令行工具:

    #include <QCoreApplication>
    #include <QDebug>
    #include <QProcess>int main(int argc, char *argv[]) {QCoreApplication a(argc, argv);QProcess process;QString program = "curl"; // 确保 curl 命令在系统 PATH 中QStringList arguments;arguments << "https://www.example.com" << "-o" << "output.html";process.start(program, arguments);process.waitForFinished();QByteArray output = process.readAllStandardOutput();QByteArray error = process.readAllStandardError();if (!error.isEmpty()) {qDebug() << "Error:" << error;} else {qDebug() << "Output:" << output;qDebug() << "Download successful!";}return a.exec();
    }
    

深入剖析 libcurl 的核心概念

  • CURL easy handle:

    • 作用: easy handle 是 libcurl 中最基本的概念,它代表一个独立的 HTTP(S)、FTP(S) 等协议的会话。你可以使用 easy handle 设置各种选项,例如 URL、请求方法、header、回调函数等。

    • 生命周期:

      1. 使用 curl_easy_init() 创建 easy handle。
      2. 使用 curl_easy_setopt() 设置 easy handle 的选项。
      3. 使用 curl_easy_perform() 执行数据传输。
      4. 使用 curl_easy_cleanup() 清理 easy handle。
    • 示例:

      CURL *curl = curl_easy_init();
      if(curl) {curl_easy_setopt(curl, CURLOPT_URL, "https://www.example.com");// ... 其他选项 ...CURLcode res = curl_easy_perform(curl);curl_easy_cleanup(curl);
      }
      
  • CURL multi handle:

    • 作用: multi handle 允许你同时管理多个 easy handle,实现并发传输。这可以显著提高下载速度,尤其是在下载多个小文件时。

    • 工作原理: multi handle 使用事件驱动机制,通过 select() 或 poll() 等系统调用监听 socket 事件,并在事件发生时调用相应的回调函数。

    • 示例:

      CURLM *multi_handle = curl_multi_init();
      CURL *easy_handle1 = curl_easy_init();
      CURL *easy_handle2 = curl_easy_init();curl_easy_setopt(easy_handle1, CURLOPT_URL, "https://www.example.com/file1.txt");
      curl_easy_setopt(easy_handle2, CURLOPT_URL, "https://www.example.com/file2.txt");curl_multi_add_handle(multi_handle, easy_handle1);
      curl_multi_add_handle(multi_handle, easy_handle2);int still_running = 0;
      do {CURLMcode mc = curl_multi_perform(multi_handle, &still_running);if(mc) {// 处理错误}// 等待 socket 事件// ...
      } while(still_running);curl_multi_remove_handle(multi_handle, easy_handle1);
      curl_multi_remove_handle(multi_handle, easy_handle2);
      curl_easy_cleanup(easy_handle1);
      curl_easy_cleanup(easy_handle2);
      curl_multi_cleanup(multi_handle);
      
  • CURL share handle:

    • 作用: share handle 允许你在多个 easy handle 之间共享会话信息,例如 Cookie、SSL 会话等。这可以避免重复的握手和认证过程,提高性能。

    • 线程安全: share handle 本身不是线程安全的,需要在多线程环境中使用锁来保护共享资源。

    • 示例:

      CURLSH *share_handle = curl_share_init();
      curl_share_setopt(share_handle, CURLSHOPT_SHARE, CURL_LOCK_DATA_COOKIE);
      curl_share_setopt(share_handle, CURLSHOPT_SHARE, CURL_LOCK_DATA_SSL_SESSION);CURL *easy_handle1 = curl_easy_init();
      CURL *easy_handle2 = curl_easy_init();curl_easy_setopt(easy_handle1, CURLOPT_SHARE, share_handle);
      curl_easy_setopt(easy_handle2, CURLOPT_SHARE, share_handle);// ...curl_easy_cleanup(easy_handle1);
      curl_easy_cleanup(easy_handle2);
      curl_share_cleanup(share_handle);
      
  • CURLcode:

    • 作用: CURLcode 是 libcurl 函数返回的错误码,用于指示函数执行的结果。

    • 常见错误码:

      • CURLE_OK (0): 一切正常。
      • CURLE_UNSUPPORTED_PROTOCOL (1): 不支持的协议。
      • CURLE_BAD_URL (2): URL 格式错误。
      • CURLE_COULDNT_RESOLVE_HOST (6): 无法解析主机名。
      • CURLE_COULDNT_CONNECT (7): 无法连接到服务器。
      • CURLE_HTTP_RETURNED_ERROR (22): HTTP 请求返回错误码(例如 404、500)。
      • CURLE_SSL_CONNECT_ERROR (35): SSL 连接错误。
      • CURLE_OPERATION_TIMEDOUT (28): 操作超时。
    • 示例:

      CURLcode res = curl_easy_perform(curl);
      if(res != CURLE_OK) {std::cerr << "curl_easy_perform() failed: " << curl_easy_strerror(res) << std::endl;
      }
      

7. 实际案例分析

  • 案例 1:开发一个简单的 HTTP 客户端

    这个案例演示了如何使用 libcurl 开发一个简单的 HTTP 客户端,可以发送 GET 和 POST 请求,并处理 HTTP 响应。

    #include <iostream>
    #include <string>
    #include <curl/curl.h>// 回调函数,用于接收 HTTP 响应数据
    size_t WriteCallback(void *contents, size_t size, size_t nmemb, std::string *output) {size_t total_size = size * nmemb;output->append((char*)contents, total_size);return total_size;
    }int main() {CURL *curl;CURLcode res;std::string readBuffer;// 初始化 libcurlcurl_global_init(CURL_GLOBAL_DEFAULT);// 创建一个 curl handlecurl = curl_easy_init();if(curl) {// 设置要请求的 URLcurl_easy_setopt(curl, CURLOPT_URL, "https://www.example.com");// 设置 write callback 函数curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);// 执行 HTTP 请求res = curl_easy_perform(curl);if(res != CURLE_OK) {std::cerr << "curl_easy_perform() failed: " << curl_easy_strerror(res) << std::endl;} else {std::cout << "HTTP Response:\n" << readBuffer << std::endl;}// 清理 curl handlecurl_easy_cleanup(curl);}// 清理 libcurlcurl_global_cleanup();return 0;
    }
    
  • 案例 2:实现一个多线程下载器 (简要示例)

    这个案例演示了如何使用 libcurl 和 Qt 的多线程功能实现一个简单的多线程下载器。由于完整的多线程下载器代码较长,这里只提供一个简要的示例,展示如何使用 curl_multi_perform 实现并发下载。

    #include <iostream>
    #include <fstream>
    #include <string>
    #include <vector>
    #include <thread>
    #include <mutex>
    #include <curl/curl.h>// 下载任务结构体
    struct DownloadTask {std::string url;std::string filename;};// 下载函数void DownloadFile(DownloadTask task) {CURL *curl;FILE *fp;CURLcode res;curl = curl_easy_init();if (curl) {fp = fopen(task.filename.c_str(), "wb");if (fp) {curl_easy_setopt(curl, CURLOPT_URL, task.url.c_str());curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, NULL);curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);res = curl_easy_perform(curl);fclose(fp);if (res != CURLE_OK) {std::cerr << "Download failed: " << curl_easy_strerror(res) << std::endl;} else {std::cout << "Download complete: " << task.filename << std::endl;}} else {std::cerr << "Failed to open file: " << task.filename << std::endl;}curl_easy_cleanup(curl);}}int main() {// 下载任务列表std::vector<DownloadTask> tasks = {{"https://www.example.com/file1.zip", "file1.zip"},{"https://www.example.com/file2.zip", "file2.zip"},{"https://www.example.com/file3.zip", "file3.zip"}};// 创建线程std::vector<std::thread> threads;for (auto &task : tasks) {threads.emplace_back(DownloadFile, task);}// 等待线程结束for (auto &thread : threads) {thread.join();}return 0;}```
  • 最佳实践 (Qt + libcurl):

    • 使用 Qt 的信号和槽机制处理异步操作: 可以将 libcurl 的异步 API 与 Qt 的信号和槽机制结合使用,以实现非阻塞的网络编程。
    • 使用 Qt 的数据类型: 可以使用 QByteArrayQString 等 Qt 的数据类型来处理 libcurl 返回的数据。
    • 注意线程安全: libcurl 不是完全线程安全的,需要在多线程环境中使用锁来保护共享资源。
    • 选择合适的封装库: 如果你希望使用更 Qt 风格的 API,可以考虑使用 QtilitiesKFTP 等封装库。
  • 使用场景示例:

    • 下载大文件: 使用 libcurl 可以更灵活地控制下载过程,例如支持断点续传、限速下载等。

    • 与 SCP/SFTP 服务器进行通信: QNetworkAccessManager 不支持 SCP/SFTP 协议,可以使用 libcurl 来实现这些功能。

    • 实现自定义的网络协议: 如果你需要实现自定义的网络协议,可以使用 libcurl 的自定义协议处理程序。

      libcurl 不仅仅是一个库,它是一种思想,一种解决网络数据传输问题的通用方法。无论你是开发桌面应用、移动应用、嵌入式系统还是其他类型的应用,libcurl 都能为你提供强大的支持,帮助你构建更高效、更安全、更可靠的网络应用。掌握 libcurl 的使用,将使你成为一名更出色的跨平台开发者。

参考链接

  • libcurl 官网: https://curl.se/libcurl/
  • curl 官网: https://curl.se/
  • curl GitHub 仓库: https://github.com/curl/curl
  • libcurl tutorial: https://curl.se/docs/tutorial.html

以上部分内容由AI辅助整理完成,文中部分代码暂未经过验证,请谨慎使用。后续将持续更新代码验证情况。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/81882.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/81882.shtml
英文地址,请注明出处:http://en.pswp.cn/pingmian/81882.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ElasticSearch 8.x 快速上手并了解核心概念

目录 核心概念概念总结 常见操作索引的常见操作常见的数据类型指定索引库字段类型mapping查看索引库的字段类型最高频使用的数据类型 核心概念 在新版Elasticsearch中&#xff0c;文档document就是一行记录(json)&#xff0c;而这些记录存在于索引库(index)中, 索引名称必须是…

优化 CRM 架构,解锁企业竞争力密码

引言 “在所有企业面临的挑战中&#xff0c;客户关系管理无疑是最为关键的一环。” —— 彼得德鲁克 在数字化浪潮席卷的当下&#xff0c;企业面临着前所未有的机遇与挑战。客户关系管理&#xff08;CRM&#xff09;作为企业运营的核心环节&#xff0c;其架构的优劣直接影响着…

深入理解Docker和K8S

深入理解Docker和K8S Docker 是大型架构的必备技能&#xff0c;也是云原生核心。Docker 容器化作为一种轻量级的虚拟化技术&#xff0c;其核心思想&#xff1a;将应用程序及其所有依赖项打包在一起&#xff0c;形成一个可移植的单元。 容器的本质是进程&#xff1a; 容器是在…

list.forEach(s -> countService.refreshArticleStatisticInfo(s.getId())); 讲解一下语法

这段代码使用了Java中的forEach方法结合Lambda表达式来遍历一个列表&#xff0c;并对列表中的每个元素执行特定操作。具体来说&#xff0c;它会遍历列表中的每一个元素&#xff0c;并调用countService.refreshArticleStatisticInfo(s.getId())方法来刷新每个文章的统计信息。下…

AI开发者的算力革命:GpuGeek平台全景实战指南(大模型训练/推理/微调全解析)

目录 背景一、AI工业化时代的算力困局与破局之道1.1 中小企业AI落地的三大障碍1.2 GpuGeek的破局创新1.3 核心价值 二、GpuGeek技术全景剖析2.1 核心架构设计 三、核心优势详解‌3.1 优势1&#xff1a;工业级显卡舰队‌‌‌3.2 优势2&#xff1a;开箱即用生态‌3.2.1 预置镜像库…

05算法学习_59. 螺旋矩阵 II

05算法学习_59. 螺旋矩阵 II 05算法学习_59. 螺旋矩阵 II题目描述&#xff1a;个人代码&#xff1a;学习思路&#xff1a;第一种写法&#xff1a;题解关键点&#xff1a; 个人学习时疑惑点解答&#xff1a; 05算法学习_59. 螺旋矩阵 II 力扣题目链接: 59. 螺旋矩阵 II 题目描…

JDK7Hashmap的头插法造成的环问题

单线程下的扩容 多线程下的扩容 next&#xff1d;e 然后e的next变成e

JAVA|后端编码规范

目录 零、引言 一、基础 二、集合 三、并发 四、日志 五、安全 零、引言 规范等级&#xff1a; 【强制】&#xff1a;强制遵守&#xff0c;来源于线上历史故障&#xff0c;将通过工具进行检查。【推荐】&#xff1a;推荐遵守&#xff0c;来源于日常代码审查、开发人员反馈…

2025-05-21 Python深度学习5——数据读取

文章目录 1 数据准备2 Dataset2.1 自定义 Dataset2.2 使用示例 3 TensorBoard3.1 安装3.2 标量可视化&#xff08;Scalars&#xff09;3.3 图像可视化&#xff08;Images&#xff09;3.4 其他常用功能 4 transform4.1 ToTensor()4.2 Normalize()4.3 Resize()4.4 Compose()4.5 C…

5月21日学习笔记

MYSQL三层结构 表1 数据库DB1 表2 数据库管理系统 客户端命令终端&#xff08;Dos&#xff09; DBMS 数据库DB2 表1 表2 数据库………. Mysql数据库-表的本质仍然是文件 表的一行称之为一条记录->在java程序中一行记录往往使用对象表示 SQL语…

二十、面向对象底层逻辑-ServiceRegistry接口设计集成注册中心

一、服务治理的基石接口 在微服务架构中&#xff0c;服务实例的动态注册与发现是保证系统弹性的关键机制。Spring Cloud Commons模块通过ServiceRegistry与Registration接口定义了服务注册的标准化模型&#xff0c;为不同服务发现组件&#xff08;Eureka、Consul、Nacos等&…

DeepSeek:以开源之力,引领AI技术新风潮

在年春节&#xff0c;大语言模型DeepSeek如同一枚震撼弹&#xff0c;在全球范围内引发了轰动&#xff0c;成功“破圈”&#xff0c;将中国的人工智能&#xff08;AI&#xff09;技术成果推向了世界舞台。 开源策略&#xff1a;打破技术壁垒 在AI行业&#xff0c;OpenAI等巨头…

完整改进RIME算法,基于修正多项式微分学习算子Rime-ice增长优化器,完整MATLAB代码获取

1 简介 为了有效地利用雾状冰生长的物理现象&#xff0c;最近开发了一种优化算法——雾状优化算法&#xff08;RIME&#xff09;。它模拟硬雾状和软雾状过程&#xff0c;构建硬雾状穿刺和软雾状搜索机制。在本研究中&#xff0c;引入了一种增强版本&#xff0c;称为修改的RIME…

PyTorch可视化工具——使用Visdom进行深度学习可视化

文章目录 前置环境Visdom安装并启动VisdomVisdom图形APIVisdom静态更新API详解通用参数说明使用示例Visdom动态更新API详解1. 使用updateappend参数2. ~~使用vis.updateTrace方法~~3. 完整训练监控示例 Visdom可视化操作散点图plot.scatter()散点图案例线性图vis.line()vis.lin…

Java使用Collections集合工具类

1、Collections 集合工具类 Java 中的 Collections 是一个非常有用的工具类&#xff0c;它提供了许多静态方法来操作或返回集合。这个类位于 java.util 包中&#xff0c;主要包含对集合进行操作的方法&#xff0c;比如排序、搜索、线程安全化等。 Java集合工具类的使用&#x…

Unity基础学习(五)Mono中的重要内容(1)延时函数

目录 一、Mono中的延时函数Invoke 1. Invoke作用&#xff1a;延迟指定时间后执行一次函数。API&#xff1a; 2. InvokeRepeating作用&#xff1a;延迟后开始重复执行函数。API&#xff1a; 3. CancelInvoke作用&#xff1a;停止所有延时函数&#xff0c;或停止指定函数的延时…

180KHz 60V 5A开关电流升压/升降压型DC-DC转换器XL4019升降压芯片

介绍 XL6019是一款专为升压、升降压设计的 单片集成电路&#xff08;升压和降压是由外围电路拓扑确定的&#xff09;&#xff0c;可工作在DC5V到40V输入电 压范围&#xff0c;低纹波&#xff0c;内置功率MOS。XL6019内 置固定频率振荡器与频率补偿电路&#xff0c;简化了电 路…

如何畅通需求收集渠道,获取用户反馈?

要畅通需求收集渠道、有效获取用户反馈&#xff0c;核心在于多样化反馈入口、闭环反馈机制、用户分层管理、反馈数据结构化分析等四个方面。其中&#xff0c;多样化反馈入口至关重要&#xff0c;不同用户有不同的沟通偏好&#xff0c;只有覆盖多个反馈路径&#xff0c;才能捕捉…

Python结合ollama和stramlit开发聊天机器人

Python结合ollama和stramlit开发聊天机器人 一、环境准备1、streamlit安装2、langchain安装3、ollama的安装 二、Ollama平台聊天机器人实现1、需求2、模型调用3、前端实现页面呈现代码实现 三、详细代码地址四、参考资源 一、环境准备 1、streamlit安装 # 通过 pip 安装 pip …

java jdbc执行Oracle sql文件

执行代码 import java.io.FileInputStream; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; import java.sql.Connection; import java.sql.DriverManager;import org.apache.ibatis.jdbc.ScriptRunner;public class ExecSqlFileController {pu…