IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 开发工具 -> C++ websocketpp库 源码编译及使用(VS2019) -> 正文阅读

[开发工具]C++ websocketpp库 源码编译及使用(VS2019)

源码编译

下载源码

git clone git@github.com:zaphoyd/websocketpp.git

如果打不开可以试试:

git clone git@gitee.com:epson/websocketpp.git

添加websocketpp文件加到包含目录中

OpenSSL库

关于OpenSSL编译,参看:

C++ OpenSSL库 源码编译及使用(VS2019)_道-CSDN博客

这里需要用到openssl 1.1.1版本,最新3.0版本会报错。

Boost库

关于Boost编译,参看:

C++ boost库 源码编译及使用(VS2019)_道-CSDN博客

加入包含目录

?

加入库目录

?

简单测试

#include <iostream>
#include <websocketpp/config/asio_client.hpp>
#include <websocketpp/client.hpp>

#ifndef _DEBUG
#ifdef _WIN64
#pragma comment (lib,"x64/Release/libcrypto.lib")
#pragma comment (lib,"x64/Release/libssl.lib")
#else
#pragma comment (lib,"x86/Release/libcrypto.lib")
#pragma comment (lib,"x86/Release/libssl.lib")
#endif // _WIN64
#else
#ifdef _WIN64
#pragma comment (lib,"x64/Debug/libcrypto.lib")
#pragma comment (lib,"x64/Debug/libssl.lib")
#else
#pragma comment (lib,"x86/Debug/libcrypto.lib")
#pragma comment (lib,"x86/Debug/libssl.lib")
#endif // _WIN64
#endif

typedef websocketpp::client<websocketpp::config::asio_tls_client> client;
typedef websocketpp::lib::shared_ptr<websocketpp::lib::asio::ssl::context> context_ptr;

using websocketpp::lib::placeholders::_1;
using websocketpp::lib::placeholders::_2;
using websocketpp::lib::bind;

client m_ws;

/// Verify that one of the subject alternative names matches the given hostname
bool verify_subject_alternative_name(const char* hostname, X509* cert) {
	STACK_OF(GENERAL_NAME)* san_names = NULL;

	san_names = (STACK_OF(GENERAL_NAME)*) X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
	if (san_names == NULL) {
		return false;
	}

	int san_names_count = sk_GENERAL_NAME_num(san_names);

	bool result = false;

	for (int i = 0; i < san_names_count; i++) {
		const GENERAL_NAME* current_name = sk_GENERAL_NAME_value(san_names, i);

		if (current_name->type != GEN_DNS) {
			continue;
		}

		char const* dns_name = (char const*)ASN1_STRING_get0_data(current_name->d.dNSName);

		// Make sure there isn't an embedded NUL character in the DNS name
		if (ASN1_STRING_length(current_name->d.dNSName) != strlen(dns_name)) {
			break;
		}
		// Compare expected hostname with the CN
		result = (strcmp(hostname, dns_name) == 0);
	}
	sk_GENERAL_NAME_pop_free(san_names, GENERAL_NAME_free);

	return result;
}

/// Verify that the certificate common name matches the given hostname
bool verify_common_name(char const* hostname, X509* cert) {
	// Find the position of the CN field in the Subject field of the certificate
	int common_name_loc = X509_NAME_get_index_by_NID(X509_get_subject_name(cert), NID_commonName, -1);
	if (common_name_loc < 0) {
		return false;
	}

	// Extract the CN field
	X509_NAME_ENTRY* common_name_entry = X509_NAME_get_entry(X509_get_subject_name(cert), common_name_loc);
	if (common_name_entry == NULL) {
		return false;
	}

	// Convert the CN field to a C string
	ASN1_STRING* common_name_asn1 = X509_NAME_ENTRY_get_data(common_name_entry);
	if (common_name_asn1 == NULL) {
		return false;
	}

	char const* common_name_str = (char const*)ASN1_STRING_get0_data(common_name_asn1);

	// Make sure there isn't an embedded NUL character in the CN
	if (ASN1_STRING_length(common_name_asn1) != strlen(common_name_str)) {
		return false;
	}

	// Compare expected hostname with the CN
	return (strcmp(hostname, common_name_str) == 0);
}

bool verify_certificate(const char* hostname, bool preverified, boost::asio::ssl::verify_context& ctx) {
	// The verify callback can be used to check whether the certificate that is
	// being presented is valid for the peer. For example, RFC 2818 describes
	// the steps involved in doing this for HTTPS. Consult the OpenSSL
	// documentation for more details. Note that the callback is called once
	// for each certificate in the certificate chain, starting from the root
	// certificate authority.

	// Retrieve the depth of the current cert in the chain. 0 indicates the
	// actual server cert, upon which we will perform extra validation
	// (specifically, ensuring that the hostname matches. For other certs we
	// will use the 'preverified' flag from Asio, which incorporates a number of
	// non-implementation specific OpenSSL checking, such as the formatting of
	// certs and the trusted status based on the CA certs we imported earlier.
	int depth = X509_STORE_CTX_get_error_depth(ctx.native_handle());

	// if we are on the final cert and everything else checks out, ensure that
	// the hostname is present on the list of SANs or the common name (CN).
	if (depth == 0 && preverified) {
		X509* cert = X509_STORE_CTX_get_current_cert(ctx.native_handle());

		if (verify_subject_alternative_name(hostname, cert)) {
			return true;
		}
		else if (verify_common_name(hostname, cert)) {
			return true;
		}
		else {
			return false;
		}
	}

	return preverified;
}

context_ptr on_tls_init(const char* hostname, websocketpp::connection_hdl) {
	context_ptr ctx = websocketpp::lib::make_shared<boost::asio::ssl::context>(boost::asio::ssl::context::sslv23);

	try {
		ctx->set_options(boost::asio::ssl::context::default_workarounds |
			boost::asio::ssl::context::no_sslv2 |
			boost::asio::ssl::context::no_sslv3 |
			boost::asio::ssl::context::single_dh_use);

		ctx->set_verify_mode(boost::asio::ssl::verify_none);

		//ctx->set_verify_mode(boost::asio::ssl::verify_peer);
		ctx->set_verify_callback(bind(&verify_certificate, hostname, ::_1, ::_2));

		// Here we load the CA certificates of all CA's that this client trusts.
		//CString str;
		//str.Format("%sca-chain.cert.pem", theApp.m_lpszAppPath);
		//ctx->load_verify_file(str.GetBufferSetLength(str.GetLength()+1));

	}
	catch (std::exception& e) {
		std::cout << e.what() << std::endl;
	}
	return ctx;
}

void on_message(websocketpp::connection_hdl, client::message_ptr msg) {
	std::cout << msg->get_payload() << std::endl;
}

void on_fail(websocketpp::connection_hdl hdl) {
	std::cout << "on_fail" <<std::endl;
}

void on_open(websocketpp::connection_hdl hdl) {
	std::cout << "on_open" << std::endl;
	m_ws.send(hdl, "{\"cmd\":\"get_secret_no\"}", websocketpp::frame::opcode::text);
}
void on_close(websocketpp::connection_hdl) {
	std::cout << "on_close" << std::endl;
}

int main()
{
	std::string hostname = "openhw.work.weixin.qq.com";
	std::string port = "443";

	std::string uri = "wss://" + hostname + ":" + port;

	try {
		// Set logging to be pretty verbose (everything except message payloads)
		m_ws.set_access_channels(websocketpp::log::alevel::all);
		m_ws.clear_access_channels(websocketpp::log::alevel::frame_payload);
		m_ws.set_error_channels(websocketpp::log::elevel::all);

		// Initialize ASIO
		m_ws.init_asio();

		// Register our message handler
		m_ws.set_tls_init_handler(bind(&on_tls_init, hostname.c_str(), ::_1));
		m_ws.set_message_handler(&on_message);
		m_ws.set_open_handler(&on_open);
		m_ws.set_close_handler(&on_close);
		m_ws.set_fail_handler(&on_fail);

		websocketpp::lib::error_code ec;
		client::connection_ptr con = m_ws.get_connection(uri, ec);
		if (ec) {
			std::cout << ec.message() << std::endl;
		}

		// Note that connect here only requests a connection. No network messages are
		// exchanged until the event loop starts running in the next line.
		m_ws.connect(con);

		m_ws.get_alog().write(websocketpp::log::alevel::app, "Connecting to " + uri);

		// Start the ASIO io_service run loop
		// this will cause a single connection to be made to the server. c.run()
		// will exit when this connection is closed.
		m_ws.run();
	}
	catch (websocketpp::exception const& e) {
		std::cout << e.what() << std::endl;
	}
}

运行结果:

?

  开发工具 最新文章
Postman接口测试之Mock快速入门
ASCII码空格替换查表_最全ASCII码对照表0-2
如何使用 ssh 建立 socks 代理
Typora配合PicGo阿里云图床配置
SoapUI、Jmeter、Postman三种接口测试工具的
github用相对路径显示图片_GitHub 中 readm
Windows编译g2o及其g2o viewer
解决jupyter notebook无法连接/ jupyter连接
Git恢复到之前版本
VScode常用快捷键
上一篇文章      下一篇文章      查看所有文章
加:2021-09-29 10:30:38  更:2021-09-29 10:30:56 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/16 3:25:43-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码