赞
踩
git clone git@github.com:zaphoyd/websocketpp.git
如果打不开可以试试:
git clone git@gitee.com:epson/websocketpp.git
添加websocketpp文件加到包含目录中
关于OpenSSL编译,参看:
C++ OpenSSL库 源码编译及使用(VS2019)_道-CSDN博客
这里需要用到openssl 1.1.1版本,最新3.0版本会报错。
关于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;
- }
- }
运行结果:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。