C++ 使用CURL开源库实现Http/Https的get/post请求进行字串和文件传输

CURL开源库介绍

CURL 是一个功能强大的开源库,用于在各种平台上进行网络数据传输。它支持众多的网络协议,像 HTTP、HTTPS、FTP、SMTP 等,能让开发者方便地在程序里实现与远程服务器的通信。
CURL 可以在 Windows、Linux、macOS 等多种操作系统上使用;
CURL 支持多种网络协议,能处理复杂的网络请求,如设置请求头、处理 cookies、上传和下载文件等。
使用前,编译CURL 源码,生成动态库,引入时包括头文件一起,网上也有别人已经编译好的现成的库可以下载使用。
CURL的头文件
生成的库:
在这里插入图片描述
在你要使用的项目里加上curl的头文件

#include <curl\curl.h>

这下你就可以使用CURL里的接口完成功能了。

CURL常用的接口说明:

  • 初始化与清理相关的接口:
  1. curl_easy_init()
    功能:创建并初始化一个新的 CURL 句柄,用于后续的网络操作。这个句柄就像一个会话的载体,后续的请求设置和执行都围绕它展开。
    返回值:成功时返回一个指向新创建的 CURL 句柄的指针;失败则返回 NULL。
  2. curl_easy_cleanup(CURL *handle)
    功能:释放 CURL 句柄占用的所有资源,包括内存、网络连接等。在使用完 CURL 句柄后,必须调用此函数以避免资源泄漏。
    参数:handle 是之前通过 curl_easy_init() 得到的 CURL 句柄。
  • 请求选项设置相关的接口:
  1. curl_easy_setopt(CURL *handle, CURLoption option, …)
    功能:设置 CURL 句柄的各种选项,这些选项可以控制请求的各个方面,如请求的 URL、请求方法、请求头、回调函数等。
    参数:
    handle:CURL 句柄。
    option:CURLoption 类型的常量,指定要设置的选项。
    可变参数:根据不同的 option,需要传入相应的参数值。
    常用 option 有:
    CURLOPT_URL:设置请求的 URL。
    CURLOPT_POST:将请求方法设置为 POST。
    CURLOPT_HTTPHEADER:设置请求头。
    CURLOPT_POSTFIELDS:设置 POST 请求的数据。
  2. curl_slist_append(struct curl_slist *list, const char *string)
    功能:用于构建一个链表来存储请求头信息。每次调用该函数可以将一个新的请求头字符串添加到链表中。
    参数:
    list:指向 curl_slist 链表的指针,如果是第一次添加,可传入 NULL。
    string:要添加的请求头字符串,格式为 Header-Name: Header-Value。
    返回值:返回更新后的链表指针。
  • 回调函数设置相关的接口:
  1. CURLOPT_WRITEFUNCTION 和 CURLOPT_WRITEDATA
    功能:CURLOPT_WRITEFUNCTION:设置一个回调函数,当服务器返回响应数据时,CURL 会调用该回调函数来处理响应数据。
    CURLOPT_WRITEDATA:传递一个用户自定义的指针给回调函数,用于在回调函数中存储或处理数据。
  2. CURLOPT_READFUNCTION 和 CURLOPT_READDATA
    功能:CURLOPT_READFUNCTION:设置一个回调函数,用于在发送数据时从用户提供的数据源中读取数据。
    CURLOPT_READDATA:传递一个用户自定义的指针给回调函数,用于标识数据源。
  • 多线程与异步操作相关的接口:
  1. curl_multi_init()
    功能:初始化一个 CURLM 句柄,用于多线程或异步的网络操作。该句柄可以管理多个 CURL 句柄,实现并发请求。
    返回值:成功时返回一个新的 CURLM 句柄指针;失败返回 NULL。
  2. curl_multi_add_handle(CURLM *multi_handle, CURL *easy_handle)
    功能:将一个 CURL 句柄添加到 CURLM 句柄管理的句柄列表中,以便进行并发处理。
    参数:
    multi_handle:CURLM 句柄。
    easy_handle:要添加的 CURL 句柄。
  3. curl_multi_perform(CURLM *multi_handle, int *still_running)
    功能:在 CURLM 句柄管理的所有 CURL 句柄上执行网络操作。该函数会尝试处理尽可能多的请求,并返回仍在运行的请求数量。
    参数:
    multi_handle:CURLM 句柄。
    still_running:指向一个整数的指针,用于存储仍在运行的请求数量。
  4. curl_multi_remove_handle(CURLM *multi_handle, CURL *easy_handle)
    功能:从 CURLM 句柄管理的句柄列表中移除一个 CURL 句柄。
    参数:
    multi_handle:CURLM 句柄。
    easy_handle:要移除的 CURL 句柄。
  5. curl_multi_cleanup(CURLM *multi_handle)
    功能:释放 CURLM 句柄占用的所有资源。在使用完 CURLM 句柄后,必须调用此函数进行清理。
    参数:multi_handle 是 CURLM 句柄。

接口流程使用:

简单的同步调用模式的使用流程:

  1. 调用curl_global_init()初始化libcurl ;
  2. 调用curl_easy_init()函数得到 easy;
  3. interface型指针 调用curl_easy_setopt()设置传输选项;
  4. 根据curl_easy_setopt()设置的传输选项,实现回调函数以完成用户特定任务;
  5. 调用curl_easy_perform()函数完成传输任务,返回错误码 ;
  6. 调用curl_easy_cleanup()释放内存;
  7. 调用curl_global_cleanup() (可以不用调用);

在整过过程中设置curl_easy_setopt()参数是最关键的,了解相关参数及对应作用很重要。

举例说明CURL的调用实现

//http回调写函数
static size_t   CurlWriteBuffer(char *buffer, size_t size, size_t nmemb, std::string* stream)
{
    //第二个参数为每个数据的大小,第三个为数据个数,最后一个为接收变量
	size_t sizes = size*nmemb;
	if(stream == NULL) 
		return 0;
	stream->append(buffer,sizes);
	return sizes;
}

//http发送封装
int  HttpClient::posturl(std::string& msg,	std::string& url, bool IsSSL)
{
	CURL* pCurl=NULL;        //一个libcurl的handle
	CURLcode res;            //返回状态码
	std::string response;    //返回信息

    curl_global_init(CURL_GLOBAL_ALL);      //全局初始化
	pCurl = curl_easy_init();                //创建一个handle

	//设置请求头
	struct  curl_slist* pHeader = NULL;
	//传json格式,字符编码为utf8
	header_ = curl_slist_append(pHeader ,"Content-Type: application/json;charset=utf-8");

    //添加请求头到handle
	curl_easy_setopt(pCurl, CURLOPT_HTTPHEADER, pHeader );

    //设置URL
	curl_easy_setopt(pCurl, CURLOPT_URL, url.c_str());  

	CURLOPT_WRITEFUNCTION 将后继的动作交给write_data函数处理
	curl_easy_setopt(pCurl,CURLOPT_POSTFIELDS,msg.c_str());            //post请求消息数据    
	curl_easy_setopt(pCurl,CURLOPT_POSTFIELDSIZE,msg.length());        //消息长度
	curl_easy_setopt(pCurl, CURLOPT_WRITEFUNCTION, CurlWriteBuffer);   //回调函数
	curl_easy_setopt(pCurl,CURLOPT_WRITEDATA,&response);               //数据接收变量
	curl_easy_setopt(pCurl,CURLOPT_TIMEOUT,m_settinginfo.m_http_timeout);  //连接超时时间

    //不支持ssl验证
	if(m_settinginfo.m_ssl == 0)
	{
		curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYPEER, 0);//设定为不验证证书和HOST
		curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYHOST, 0);
	}
	else
	{
		// 配置 https 请求所需证书
		if (m_settinginfo.m_ssl == 1)    //ssl单向验证,不验证服务器
		{
			curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYPEER, 0L);		
		}else
		{//双向验证
			curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYPEER, 1L);
			curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYHOST, 0);
			curl_easy_setopt(pCurl,CURLOPT_CAINFO,ca_info.ca_path.c_str()); 
		}

        //设置客户端信息
		curl_easy_setopt(pCurl, CURLOPT_SSLCERT, ca_info.client_cert_path.c_str());
		curl_easy_setopt(pCurl,CURLOPT_SSLCERTTYPE,"PEM");  
		curl_easy_setopt(pCurl, CURLOPT_SSLKEY, ca_info.client_key_path.c_str());
		curl_easy_setopt(pCurl,CURLOPT_SSLKEYTYPE,"PEM"); 
  
        //如果客户端证书密钥使用密码加密,设置加密密码
		//curl_easy_setopt(pCurl, CURLOPT_KEYPASSWD, "your_key_password");
 }

    //执行http连接
	res = curl_easy_perform(pCurl);

    //清除消息头
	curl_slist_free_all(pHeader);

    //清除handle
    curl_easy_cleanup(pCurl);
    
	return 0;
}

再看一段完整的CURL封装成get,post等形式,进行字串传输和文件上传的请求,可以直接拿去使用。

//Http的Get请求
int HttpClient::ExecuteGetRequestCURL(const char* strUrl, const char* pszGet, const char* pszCookie, int nTimeOut)
{
	CURLcode res;
	m_strResponse = "";
	struct curl_slist* headers = NULL;
	CURL* curl = curl_easy_init();
	if (NULL == curl)
	{
		return CURLE_FAILED_INIT;
	}
	std::string strOutData = strUrl;
	strOutData += pszGet;
	curl_easy_setopt(curl, CURLOPT_URL, strOutData.c_str());
	curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
	curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData);
	curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&m_strResponse);
	/**
	* 当多个线程都使用超时处理的时候,同时主线程中有sleep或是wait等操作。
	* 如果不设置这个选项,libcurl将会发信号打断这个wait从而导致程序退出。
	*/
	curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
	//连接超时设置10s,数据请求超时设置60s
	curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10);
	curl_easy_setopt(curl, CURLOPT_TIMEOUT, nTimeOut);
	res = curl_easy_perform(curl);
	if (res != CURLE_OK)
		m_strResponse = "";
	curl_easy_cleanup(curl);
	return res;
}
//Http的post请求
int HttpClient::ExecutePostRequestCURL(const char* strUrl, const char* pszKey, const char* pszPost, const char* pszCookie, int nTimeOut)
{
	CURLcode res;
	m_strResponse = "";

	CURL* curl = curl_easy_init();
	if (NULL == curl)
	{
		return CURLE_FAILED_INIT;
	}

	///
	struct curl_slist* headerlist = NULL;
	struct curl_httppost* formpost = NULL;
	struct curl_httppost* last = NULL;
	//headerlist = curl_slist_append(headerlist, "Content-Type:application/json;charset=UTF-8");
	//curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist);

	res = curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, "gzip, deflate, br");//设置CURLOPT_ACCEPT_ENCODING (7.21.8之前为CURLOPT_ENCODING )
	if (CURLE_OK != res)
	{
		curl_easy_cleanup(curl);
		return CURLE_FAILED_INIT;
	}
	curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L);
	if (CURLE_OK != res)
	{
		curl_easy_cleanup(curl);
		return CURLE_FAILED_INIT;
	}
	curl_formadd(&formpost, &last, CURLFORM_PTRNAME, pszKey, CURLFORM_PTRCONTENTS, pszPost, CURLFORM_END);	//以这种方式上传可以避免特殊字符被改变
	if (CURLE_OK != res)
	{
		curl_easy_cleanup(curl);
		return CURLE_FAILED_INIT;
	}
	curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);                     //构造post参数    
	if (CURLE_OK != res)
	{
		curl_easy_cleanup(curl);
		return CURLE_FAILED_INIT;
	}
	/
	curl_easy_setopt(curl, CURLOPT_URL, strUrl);
	if (CURLE_OK != res)
	{
		curl_easy_cleanup(curl);
		return CURLE_FAILED_INIT;
	}
	//curl_easy_setopt(curl, CURLOPT_POST, 1);
	//curl_easy_setopt(curl, CURLOPT_POSTFIELDS, pszPost);
	curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
	if (CURLE_OK != res)
	{
		curl_easy_cleanup(curl);
		return CURLE_FAILED_INIT;
	}
	curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData);
	if (CURLE_OK != res)
	{
		curl_easy_cleanup(curl);
		return CURLE_FAILED_INIT;
	}
	curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&m_strResponse);
	if (CURLE_OK != res)
	{
		curl_easy_cleanup(curl);
		return CURLE_FAILED_INIT;
	}
	curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
	if (CURLE_OK != res)
	{
		curl_easy_cleanup(curl);
		return CURLE_FAILED_INIT;
	}
	if ((pszCookie != NULL)&&(strlen(pszCookie)>0))
	{ 
		curl_easy_setopt(curl, CURLOPT_COOKIEFILE, (void *)&pszCookie);
		curl_easy_setopt(curl, CURLOPT_COOKIEJAR, (void *)&pszCookie);
	}
	//连接超时设置,数据请求超时设置
	curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10);
	curl_easy_setopt(curl, CURLOPT_TIMEOUT, nTimeOut);
	res = curl_easy_perform(curl);
	if (res != CURLE_OK)
	{
		m_strResponse = "";
		// 获取详细错误信息
		const char* szErr = curl_easy_strerror(res);
		fprintf(stderr, "curl_easy_perform() failed: %s\n", szErr);
	}
		
	// 清空
	curl_easy_cleanup(curl);
	// 释放表单
	curl_formfree(formpost);
	// 释放表头
	curl_slist_free_all (headerlist); 

	return res;
}

//https的Get请求
int HttpClient::ExecuteHttpsGetCURL(const std::string & strUrl, const char* pszGet, const char * pCaPath, int nTimeOut)
{
	CURLcode res;
	CURL* curl = curl_easy_init();
	if (NULL == curl)
	{
		return CURLE_FAILED_INIT;
	}
	std::string strOutData = strUrl;
	strOutData += pszGet;
	curl_easy_setopt(curl, CURLOPT_URL, strOutData.c_str());
	curl_easy_setopt(curl, CURLOPT_HEADER, 0 ); 
	curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
	curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData);
	curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&m_strResponse);
	curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
	curl_easy_setopt(curl, CURLOPT_TIMEOUT, nTimeOut);
	if (NULL == pCaPath)
	{
		curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
		curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false);
	}
	else
	{
		curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, true);
		curl_easy_setopt(curl, CURLOPT_CAINFO, pCaPath);
	}
	curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10);
	//curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3);
	//curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
	//curl_easy_setopt(curl,CURLOPT_TRANSFERTEXT,1); 
	res = curl_easy_perform(curl);
	if (res != CURLE_OK)
		m_strResponse = "";
	curl_easy_cleanup(curl);
	return res;
}

//https的Post请求
int HttpClient::ExecuteHttpsPostCURL(const std::string& strUrl, const std::string& strKey, const std::string& strPost, const std::string& strCookie, const char* pCaPath, int nTimeOut)
{
	CURLcode res;
	CURL* curl = curl_easy_init();
	if (NULL == curl)
	{
		return CURLE_FAILED_INIT;
	}
	///
	struct curl_slist* headers = NULL;
	struct curl_httppost* post = NULL;
	struct curl_httppost* last = NULL;
	curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, "gzip, deflate, br");//设置CURLOPT_ACCEPT_ENCODING (7.21.8之前为CURLOPT_ENCODING )
	curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L);
	curl_formadd(&post, &last, CURLFORM_PTRNAME, strKey.c_str(), CURLFORM_PTRCONTENTS, strPost.c_str(), CURLFORM_END);	//以这种方式上传可以避免特殊字符被改变
	curl_easy_setopt(curl, CURLOPT_HTTPPOST, post);                     //构造post参数

	curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str());
// 	curl_easy_setopt(curl, CURLOPT_POST, 1);
// 	curl_easy_setopt(curl, CURLOPT_POSTFIELDS, strPost.c_str());
	curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
	curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData);
	curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&m_strResponse);
	curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
	//curl_easy_setopt(curl, CURLOPT_TIMEOUT, 60*5);
	//curl_easy_setopt(curl, CURLOPT_TIMEOUT, 60*5);

	if (strCookie.length()>0)
	{
		curl_easy_setopt(curl, CURLOPT_COOKIEFILE, (void *)&strCookie);
		curl_easy_setopt(curl, CURLOPT_COOKIEJAR, (void *)&strCookie);
	}

	if (NULL == pCaPath)
	{
		//curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
		//curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false);
		curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
		curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
	}
	else
	{
		//缺省情况就是PEM,所以无需设置,另外支持DER
		//curl_easy_setopt(curl,CURLOPT_SSLCERTTYPE,"PEM");
		curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, true);
		curl_easy_setopt(curl, CURLOPT_CAINFO, pCaPath);
	}
	curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 20);
	curl_easy_setopt(curl, CURLOPT_TIMEOUT, nTimeOut);
	curl_easy_setopt(curl, CURLOPT_SSLVERSION, 3);
	res = curl_easy_perform(curl);
	curl_easy_cleanup(curl);
	return res;
}

static size_t OnWriteData(void* buffer, size_t size, size_t nmemb, void* lpVoid)
{			
	std::string* str = reinterpret_cast<std::string*>(lpVoid);
	if (NULL == str || NULL == buffer)
	{
		return -1;
	}

	char* pData =  reinterpret_cast<char*>(buffer);
	str->append(pData, size * nmemb);
	return nmemb;
}

long HttpClient::GetRespone(char* pszResponse, long &lRespLen)
{
	long lRet = 0;

	if (m_strResponse.length() <= 0)
	{
		lRet = 1;
		goto err;
	}
	if (pszResponse == NULL)
	{
		lRespLen = m_strResponse.length();
		goto err;
	}

	if (lRespLen < m_strResponse.length())
	{
		lRet = 1;
		goto err;
	}

	memset(pszResponse, 0, lRespLen);
	memcpy(pszResponse, m_strResponse.c_str(), m_strResponse.length());
	lRespLen = m_strResponse.length();
err:
	return lRet;
}

long HttpClient::GetFileNameAndExt(const std::string & strFilePath,
	std::string & strFileName,
	std::string & strFileExt)
{
	long lRet = 0;

	strFileExt = "";
	strFileName = "";

	int nPos = strFilePath.rfind('.');
	if (nPos == -1)
	{
		lRet = CURLE_FAILED_INIT;	//文件不存在
		goto err;
	}
	strFileExt = strFilePath.substr(nPos+1, strFilePath.length());

	nPos = strFilePath.rfind('\\');
	if (nPos == -1)
	{
		nPos = strFilePath.rfind('/');
		if (nPos == -1)
		{
			strFileName = strFilePath;
			goto err;
		}

	}
	strFileName = strFilePath.substr(nPos+1, strFilePath.length());
err:
	return lRet;
}
//Http的post传文件请求
//strParamName是"bindingSeal",strParamVal值是对应的json包,strParamName2是"sealImages",strParamVal2值是图片名称
long HttpClient::HttpUploadFileCURL(LPCTSTR strUrl, const string& strFilePath, const string& strParamName, const string& strParamVal, const string& strParamName2, const string& strParamVal2, string& strResponse)
{
	CURL* curl;
	CURLcode res;
	long lRet = 0;
	std::string strFileName;
	std::string strFileExt;
	StringTool strTool;
	string strCRUL = strTool.WideToAsc(strUrl);
	lRet = GetFileNameAndExt(strFilePath, strFileName, strFileExt);
	if (lRet != 0)
		goto err;
	curl = curl_easy_init();
	struct curl_httppost* post = NULL;
	struct curl_httppost* last = NULL;
	if (curl == NULL)
	{
		lRet = CURLE_FAILED_INIT;
		goto err;
	}
	curl_easy_setopt(curl, CURLOPT_URL, (char *)strCRUL.c_str());           //指定url
	//form-data key(path) 和 value(device_cover)
	curl_formadd(&post, &last, CURLFORM_PTRNAME, strParamName.c_str()/*"parma"*/, CURLFORM_PTRCONTENTS, strParamVal.c_str(), CURLFORM_END);
	curl_formadd(&post, &last, CURLFORM_PTRNAME,  strParamName2.c_str(), CURLFORM_FILE, strFilePath.c_str(),CURLFORM_FILENAME, strFileName.c_str(),CURLFORM_CONTENTTYPE,"image/png", CURLFORM_END);
	//curl_formadd(&post, &last, CURLFORM_PTRNAME,  strParamName2.c_str(), CURLFORM_FILE, strFilePath.c_str(),CURLFORM_FILENAME, strFileName.c_str(),CURLFORM_CONTENTTYPE,"image/PNG", CURLFORM_END);

	curl_easy_setopt(curl, CURLOPT_HTTPPOST, post);                     //构造post参数    
	curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData);          //绑定相应
	curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse);        //绑定响应内容的地址

	res = curl_easy_perform(curl);                          //执行请求
	if(res == 0){
		curl_easy_cleanup(curl);    
		lRet =  res;
		goto err;
	}
	else{
		lRet =  res;
		goto err;
	}

	lRet = res;

err:
	return lRet;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/966183.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

mapbox进阶,添加绘图扩展插件,绘制圆形

👨‍⚕️ 主页: gis分享者 👨‍⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨‍⚕️ 收录于专栏:mapbox 从入门到精通 文章目录 一、🍀前言1.1 ☘️mapboxgl.Map 地图对象1.2 ☘️mapboxgl.Map style属性1.3 ☘️MapboxDraw 绘图控件二、🍀添加绘图扩…

网络工程师 (24)数据封装与解封装

一、数据封装 数据封装是指将协议数据单元&#xff08;PDU&#xff09;封装在一组协议头和尾中的过程。在OSI 7层参考模型中&#xff0c;数据从应用层开始&#xff0c;逐层向下封装&#xff0c;直到物理层。每一层都会为其PDU添加相应的协议头和尾&#xff0c;以包含必要的通信…

OSPF基础(3):区域划分

OSPF的区域划分 1、区域产生背景 路由器在同一个区域中泛洪LSA。为了确保每台路由器都拥有对网络拓扑的一致认知&#xff0c;LSDB需要在区域内进行同步。OSPF域如果仅有一个区域&#xff0c;随着网络规模越来越大&#xff0c;OSPF路由器的数量越来越多&#xff0c;这将导致诸…

C++----继承

一、继承的基本概念 本质&#xff1a;代码复用类关系建模&#xff08;是多态的基础&#xff09; class Person { /*...*/ }; class Student : public Person { /*...*/ }; // public继承 派生类继承基类成员&#xff08;数据方法&#xff09;&#xff0c;可以通过监视窗口检…

【DeepSeek】DeepSeek小模型蒸馏与本地部署深度解析DeepSeek小模型蒸馏与本地部署深度解析

一、引言与背景 在人工智能领域&#xff0c;大型语言模型&#xff08;LLM&#xff09;如DeepSeek以其卓越的自然语言理解和生成能力&#xff0c;推动了众多应用场景的发展。然而&#xff0c;大型模型的高昂计算和存储成本&#xff0c;以及潜在的数据隐私风险&#xff0c;限制了…

ZZNUOJ(C/C++)基础练习1081——1090(详解版)

目录 1081 : n个数求和 &#xff08;多实例测试&#xff09; C C 1082 : 敲7&#xff08;多实例测试&#xff09; C C 1083 : 数值统计(多实例测试) C C 1084 : 计算两点间的距离&#xff08;多实例测试&#xff09; C C 1085 : 求奇数的乘积&#xff08;多实例测试…

axios 发起 post请求 json 需要传入数据格式

• 1. axios 发起 post请求 json 传入数据格式 • 2. axios get请求 1. axios 发起 post请求 json 传入数据格式 使用 axios 发起 POST 请求并以 JSON 格式传递数据是前端开发中常见的操作。 下面是一个简单的示例&#xff0c;展示如何使用 axios 向服务器发送包含 JSON 数…

硬盘接入电脑提示格式化?是什么原因?怎么解决?

有时候&#xff0c;当你将硬盘接入电脑时&#xff0c;看到系统弹出“使用驱动器中的光盘之前需要将其格式化”的提示&#xff0c;肯定会感到十分困惑和焦虑。这种情况不仅让人担心数据丢失&#xff0c;也可能影响正常使用。为什么硬盘会突然要求格式化&#xff1f;是硬盘出了问…

使用Python实现PDF与SVG相互转换

目录 使用工具 使用Python将SVG转换为PDF 使用Python将SVG添加到现有PDF中 使用Python将PDF转换为SVG 使用Python将PDF的特定页面转换为SVG SVG&#xff08;可缩放矢量图形&#xff09;和PDF&#xff08;便携式文档格式&#xff09;是两种常见且广泛使用的文件格式。SVG是…

【大数据技术】搭建完全分布式高可用大数据集群(Kafka)

搭建完全分布式高可用大数据集群(Kafka) kafka_2.13-3.9.0.tgz注:请在阅读本篇文章前,将以上资源下载下来。 写在前面 本文主要介绍搭建完全分布式高可用集群 Kafka 的详细步骤。 注意: 统一约定将软件安装包存放于虚拟机的/software目录下,软件安装至/opt目录下。 安…

【C++篇】C++11新特性总结1

目录 1&#xff0c;C11的发展历史 2&#xff0c;列表初始化 2.1C98传统的{} 2.2&#xff0c;C11中的{} 2.3&#xff0c;C11中的std::initializer_list 3&#xff0c;右值引用和移动语义 3.1&#xff0c;左值和右值 3.2&#xff0c;左值引用和右值引用 3.3&#xff0c;…

Redis --- 使用HyperLogLog实现UV(访客量)

UV 和 PV 是网站或应用数据分析中的常用指标&#xff0c;用于衡量用户活跃度和页面访问量。 UV (Unique Visitor 独立访客)&#xff1a; 指的是在一定时间内访问过网站或应用的独立用户数量。通常根据用户的 IP 地址、Cookies 或用户 ID 等来唯一标识一个用户。示例&#xff1…

【机器学习案列】糖尿病风险可视化及预测

&#x1f9d1; 博主简介&#xff1a;曾任某智慧城市类企业算法总监&#xff0c;目前在美国市场的物流公司从事高级算法工程师一职&#xff0c;深耕人工智能领域&#xff0c;精通python数据挖掘、可视化、机器学习等&#xff0c;发表过AI相关的专利并多次在AI类比赛中获奖。CSDN…

单片机之基本元器件的工作原理

一、二极管 二极管的工作原理 二极管是一种由P型半导体和N型半导体结合形成的PN结器件&#xff0c;具有单向导电性。 1. PN结形成 P型半导体&#xff1a;掺入三价元素&#xff0c;形成空穴作为多数载流子。N型半导体&#xff1a;掺入五价元素&#xff0c;形成自由电子作为多…

llama.cpp GGUF 模型格式

llama.cpp GGUF 模型格式 1. Specification1.1. GGUF Naming Convention (命名规则)1.1.1. Validating Above Naming Convention 1.2. File Structure 2. Standardized key-value pairs2.1. General2.1.1. Required2.1.2. General metadata2.1.3. Source metadata 2.2. LLM2.2.…

Conmi的正确答案——Rider中添加icon作为exe的图标

C#版本&#xff1a;.net 8.0 Rider版本&#xff1a;#RD-243.22562.250&#xff08;非商业使用版&#xff09; 1、添加图标到解决方案下&#xff1a; 2、打开“App.xaml”配置文件&#xff0c;添加配置&#xff1a; <Applicationx:Class"ComTransmit.App"xmlns&q…

告别手动操作!用Ansible user模块高效管理 Linux账户

在企业运维环境中&#xff0c;服务器的用户管理是一项基础但非常重要的任务。比如&#xff0c;当有新员工加入时&#xff0c;我们需要在多台服务器上为他们创建账户并分配合适的权限。而当员工离职或岗位发生变化时&#xff0c;我们也需要迅速禁用或删除他们的账户&#xff0c;…

C++小等于的所有奇数和=最大奇数除2加1的平方。

缘由 三种思路解题&#xff1a;依据算术推导得到一个规律&#xff1a;小等于的所有奇数和等于最大奇数除以2加1的平方。将在后续发布&#xff0c;总计有十种推导出来的实现代码。 int a 0,aa 1,aaa 0;cin >> a; while (aa<a) aaa aa, aa 2;cout << aaa;i…

【CPP】CPP经典面试题

文章目录 引言1. C 基础1.1 C 中的 const 关键字1.2 C 中的 static 关键字 2. 内存管理2.1 C 中的 new 和 delete2.2 内存泄漏 3. 面向对象编程3.1 继承和多态3.2 多重继承 4. 模板和泛型编程4.1 函数模板4.2 类模板 5. STL 和标准库5.1 容器5.2 迭代器 6. 高级特性6.1 移动语义…

深入浅出谈VR(虚拟现实、VR镜头)

1、VR是什么鬼&#xff1f; 近两年VR这次词火遍网上网下&#xff0c;到底什么是VR&#xff1f;VR是“Virtual Reality”&#xff0c;中文名字是虚拟现实&#xff0c;是指采用计算机技术为核心的现代高科技手段生成一种虚拟环境&#xff0c;用户借助特殊的输入/输出设备&#x…