- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我想通过 SSL 连接发送未经请求的消息。这意味着服务器不是基于客户端的请求发送消息,而是因为发生了客户端需要知道的某些事件。
我只是使用来自 boost 站点的 SSL 服务器示例,添加了一个在 10 秒后发送“hello”的计时器,在计时器到期之前一切正常(服务器回显的一切),也收到了“hello”,但是之后,应用程序在下次向服务器发送文本时崩溃。
对我来说更奇怪的是,当我禁用 SSL 代码时,使用普通套接字并使用 telnet 执行相同的操作,它工作正常并且继续正常工作!!!
我第二次遇到这个问题,我真的不知道为什么会这样。
下面是我为演示问题而更改的全部源代码。在没有 SSL 定义和使用 telnet 的情况下编译它,一切正常,定义 SSL 并使用 openssl,或者来自 boost 网站的客户端 SSL 示例,然后事情崩溃了。
#include <cstdlib>
#include <iostream>
#include <boost/bind.hpp>
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
//#define SSL
typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> ssl_socket;
class session
{
public:
session(boost::asio::io_service& io_service,
boost::asio::ssl::context& context)
#ifdef SSL
: socket_(io_service, context)
#else
: socket_(io_service)
#endif
{
}
ssl_socket::lowest_layer_type& socket()
{
return socket_.lowest_layer();
}
void start()
{
#ifdef SSL
socket_.async_handshake(boost::asio::ssl::stream_base::server,
boost::bind(&session::handle_handshake, this,
boost::asio::placeholders::error));
#else
socket_.async_read_some(boost::asio::buffer(data_, max_length),
boost::bind(&session::handle_read, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
boost::shared_ptr< boost::asio::deadline_timer > timer(new boost::asio::deadline_timer( socket_.get_io_service() ));
timer->expires_from_now( boost::posix_time::seconds( 10 ) );
timer->async_wait( boost::bind( &session::SayHello, this, _1, timer ) );
#endif
}
void handle_handshake(const boost::system::error_code& error)
{
if (!error)
{
socket_.async_read_some(boost::asio::buffer(data_, max_length),
boost::bind(&session::handle_read, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
boost::shared_ptr< boost::asio::deadline_timer > timer(new boost::asio::deadline_timer( socket_.get_io_service() ));
timer->expires_from_now( boost::posix_time::seconds( 10 ) );
timer->async_wait( boost::bind( &session::SayHello, this, _1, timer ) );
}
else
{
delete this;
}
}
void SayHello(const boost::system::error_code& error, boost::shared_ptr< boost::asio::deadline_timer > timer) {
std::string hello = "hello";
boost::asio::async_write(socket_,
boost::asio::buffer(hello, hello.length()),
boost::bind(&session::handle_write, this,
boost::asio::placeholders::error));
timer->expires_from_now( boost::posix_time::seconds( 10 ) );
timer->async_wait( boost::bind( &session::SayHello, this, _1, timer ) );
}
void handle_read(const boost::system::error_code& error,
size_t bytes_transferred)
{
if (!error)
{
boost::asio::async_write(socket_,
boost::asio::buffer(data_, bytes_transferred),
boost::bind(&session::handle_write, this,
boost::asio::placeholders::error));
}
else
{
std::cout << "session::handle_read() -> Delete, ErrorCode: "<< error.value() << std::endl;
delete this;
}
}
void handle_write(const boost::system::error_code& error)
{
if (!error)
{
socket_.async_read_some(boost::asio::buffer(data_, max_length),
boost::bind(&session::handle_read, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
else
{
std::cout << "session::handle_write() -> Delete, ErrorCode: "<< error.value() << std::endl;
delete this;
}
}
private:
#ifdef SSL
ssl_socket socket_;
#else
boost::asio::ip::tcp::socket socket_;
#endif
enum { max_length = 1024 };
char data_[max_length];
};
class server
{
public:
server(boost::asio::io_service& io_service, unsigned short port)
: io_service_(io_service),
acceptor_(io_service,
boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port)),
context_(boost::asio::ssl::context::sslv23)
{
#ifdef SSL
context_.set_options(
boost::asio::ssl::context::default_workarounds
| boost::asio::ssl::context::no_sslv2
| boost::asio::ssl::context::single_dh_use);
context_.set_password_callback(boost::bind(&server::get_password, this));
context_.use_certificate_chain_file("server.crt");
context_.use_private_key_file("server.key", boost::asio::ssl::context::pem);
context_.use_tmp_dh_file("dh512.pem");
#endif
start_accept();
}
std::string get_password() const
{
return "test";
}
void start_accept()
{
session* new_session = new session(io_service_, context_);
acceptor_.async_accept(new_session->socket(),
boost::bind(&server::handle_accept, this, new_session,
boost::asio::placeholders::error));
}
void handle_accept(session* new_session,
const boost::system::error_code& error)
{
if (!error)
{
new_session->start();
}
else
{
delete new_session;
}
start_accept();
}
private:
boost::asio::io_service& io_service_;
boost::asio::ip::tcp::acceptor acceptor_;
boost::asio::ssl::context context_;
};
int main(int argc, char* argv[])
{
try
{
boost::asio::io_service io_service;
using namespace std; // For atoi.
server s(io_service, 7777 /*atoi(argv[1])*/);
io_service.run();
}
catch (std::exception& e)
{
std::cerr << "Exception: " << e.what() << "\n";
}
return 0;
}
我在 2012 年 4 月 19 日使用 boost 1.49 和 OpenSSL 1.0.0i-fips。我尝试尽可能多地调查这个问题,最后一次遇到这个问题(几个月前),我收到了一个错误号,我可以追溯到此错误消息:error: decryption failed or bad record mac
。
但我不知道出了什么问题以及如何解决这个问题,欢迎提出任何建议。
最佳答案
问题是多个并发的异步读写。即使使用原始套接字,我也能够使该程序崩溃(glibc 检测到双重释放或损坏)。让我们看看 session 开始后会发生什么(在大括号中我输入了并发计划异步读取和写入的数量):
安排异步读取 (1, 0)
(假设数据来了)handle_read
被执行,它调度async write (0, 1)
(data are written) handle_write
执行,它调度async read (1, 0)
现在,它可以无限循环 1. - 3. 而不会出现任何问题。但随后计时器到期...
(假设,没有新的数据来自客户端,所以仍然有一个异步读取调度)定时器到期,所以执行SayHello
,它调度异步写入,仍然没问题( 1, 1)
(来自SayHello
的数据已写入,但仍然没有来自客户端的新数据)handle_write
被执行,它调度异步读取(2, 0)
现在,我们完成了。如果来自客户端的任何新数据到来,其中一部分可以由一个异步读取读取,一部分由另一个异步读取读取。对于原始套接字,它甚至可能看起来有效(尽管有可能安排了 2 个并发写入,因此客户端的回显可能看起来很复杂)。对于 SSL,这可能会破坏传入的数据流,这可能就是会发生的情况。
如何解决:
strand
在这种情况下无济于事(它不是并发处理程序执行,而是计划的异步读取和写入)。SayHello
中的异步写入处理程序什么都不做(那么不会有并发读取,但仍可能发生并发写入)。shared_ptr
而不是 delete this
是用 boost::asio 处理内存分配的更好方法。它将防止遗漏错误导致内存泄漏。关于c++ - boost::asio 中的未经请求的消息使应用程序崩溃,没有 SSL 它工作正常,为什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11919612/
据我所知,要将声音设置为铃声,应将其插入 MediaStore。在 MediaStore 中写入,需要 WRITE_EXTERNAL_STORAGE 权限。但是...有没有办法在不需要 WRITE_E
我只是想设置铃声。我不想授予 WRITE_SETTINGS 权限,我可以找到大部分答案来授予 WRITE_SETTINGS 权限但是我正在使用一个应用程序,该应用程序没有设置铃声的 WRITE_SET
我在 Windows 10 中以管理员身份运行 Android studio。AVD 是 Nexus 5X API 28。我正在尝试运行 flutter 演示,但设备下拉框仍然显示“无设备”,它只是有
我的应用程序构建于 spring-social-twitter允许用户使用 Twitter 登录的功能最近已停止工作。 我收到如下错误消息: Callback URL not approved for
我正在尝试使用 python-firebase 更新 Firebase库,但无法使用经过修改的示例代码进行身份验证: from firebase import firebase as fb auth
今天,当我尝试使用 GCC7 编译一个非常简单的 C++ 程序时,我遇到了一个非常奇怪的问题:程序没有向构造函数中的 vector 添加任何元素,当编译时没有优化(例如 -O0/-Og ) 来自 Re
简单问题:我正在尝试使用 Discord API 备份服务器(或公会,如果您使用官方术语)上的所有消息。 因此,我实现了 OAuth,没有任何问题,我有访问 token ,并且可以查询一些端点(我尝试
您好,我正在使用 msdn 中的以下代码供我公司内部使用: using System; public sealed class Singleton { private static volati
我们从 Google 的 GCM 服务中收到间歇性的 401 Unauthorized 错误。在过去,它 100% 的时间都有效。该问题可能与我们的路由器接受 IPv6 流量同时发生,但即使我们在适配
我有一个使用 Playwright + TS-Jest 设置 E2E 测试的项目。为了组织我的测试,我使用页面对象模型。结构看起来像这样: 我想在 tsconfig.json 中使用 TypeScri
我有一个后端应用程序在 Google Cloud Storage 中同步文件,我想在 javascript 中列出存储中的所有文件,而不需要从后端请求它们。我已经设置了 CORS,并且所有文件的 ac
我在尝试在私有(private) gitlab 存储库中发布 Artifact 时遇到问题。我正在使用 Maven 并使用个人访问 token 进行身份验证。当我运行 mvn deploy -s ~/
这是从 Google+ 登录中使用的 GoogleApiClient 获取 token 的传统方式: String token = GoogleAuthUtil.getToken(apiClient.
我在阅读 facebook Open Graph 文档后比较确定我不能让网站“订阅”公共(public)页面,除非该页面安装了我的应用程序。如果那是错误的,请告诉我。 我想做的是一个照片库,非常简单,
我是一名优秀的程序员,十分优秀!