我在Windows上使用Boost :: ASIO版本1.52.0,在使用VC ++中使用Visual Studio 2008代码运行Win 8的测试计算机上使用SSL版本C.
我有一些代码可以成功连接到具有给定URL的TCP服务器:
// Create the resolver and query objects to resolve the host name in serverPath to an ip address.
boost::asio::ip::tcp::resolver resolver(*IOService);
boost::asio::ip::tcp::resolver::query query(serverPath, port);
boost::asio::ip::tcp::resolver::iterator EndpointIterator = resolver.resolve(query);
// Set up an SSL context.
boost::asio::ssl::context ctx(*IOService, boost::asio::ssl::context::tlsv1_client);
// Specify to not verify the server certificiate right now.
ctx.set_verify_mode(boost::asio::ssl::context::verify_none);
// Init the socket object used to initially communicate with the server.
pSocket = new boost::asio::ssl::stream<boost::asio::ip::tcp::socket>(*IOService, ctx);
//
// The thread we are on now, is most likely the user interface thread. Create a thread to handle all incoming socket work messages.
// This thread is created for each connection to a server.
if (!RcvThreadCreated)
{
WorkerThreads.create_thread(boost::bind(&SSLSocket::RcvWorkerThread, this));
RcvThreadCreated = true;
WorkerThreads.create_thread(boost::bind(&SSLSocket::SendWorkerThread, this));
}
// Try to connect to the server. Note - add timeout logic at some point.
boost::asio::async_connect(pSocket->lowest_layer(), EndpointIterator,
boost::bind(&SSLSocket::HandleConnect, this, boost::asio::placeholders::error));
根据一些研究,如果用IP地址替换serverPath中的URL,则无法使用解析IP地址的上述代码。看起来正确的方法是创建这样的端点:
const boost::asio::ip::address IP(boost::asio::ip::address::from_string(serverPath));
int iport = atoi(port.c_str());
boost::asio::ip::tcp::endpoint EP(IP, iport);
这部分似乎编译好了。但是,稍后在async_connect方法中:
// Try to connect to the server. Note - add timeout logic at some point.
boost::asio::async_connect(pSocket->lowest_layer(), EP,
boost::bind(&SSLSocket::HandleConnect, this, boost::asio::placeholders::error));
它会产生错误。我猜测async_connect方法想要查看第二个参数的迭代器。但是,我不确定如何创建一个。
根据以下link,答案表明可以使用套接字对象上的connect方法。但是,当我尝试这样做时:
pSocket->connect(EP);
编译器发出错误 - 错误C2039:
'connect' : is not a member of 'boost::asio::ssl::stream<Stream>'
那么,有人可以展示一些简单的代码,提供一种连接到具有IP地址而不是URL的服务器的方法吗?
如果那是不可能的,那么有没有办法从IP地址进行反向查找以获取URL?
答案 0 :(得分:1)
您的async_connect()代码行未编译,因为您传递的是成员函数指针而未绑定实例。您已在代码中的其他位置正确绑定了成员函数,因此我认为这只是一种疏忽。正确的行将是:
pSocket->next_layer().async_connect(
EP,
boost::bind(&SSLSocket::HandleConnect, this, boost::asio::placeholder::error));
至于您的原始问题,获取IP地址的端点,在IP地址查询上使用ip :: tcp :: resolver工作正常,因此您不必为名称和地址分别设置代码路径。使用ssl :: stream上的lowest_layer()来访问底层的ip :: tcp :: socket是访问connect()和async_connect()的正确方法。
除了使用ssl :: context创建ssl :: stream并在建立连接后使用async_handshake()之外,您的SSL代码应该与TCP代码几乎完全相同。您也可以在TCP代码中使用lowest_layer()(它只返回自身),这可以强调相似之处。
我不保证此代码编译因为我从工作代码中简化了它,但是如果你执行async_resolve(),你的解析处理程序方法看起来就像(sp_
是一个套接字/流指针):< / p>
void Pimpl::handleResolve(
const boost::system::error_code& ec,
boost::asio::ip::tcp::resolver::iterator endpointIterator) {
if (ec) {
// error handling here
return;
}
sp_->lowest_layer().async_connect(
*endpointIterator,
boost::bind(&Pimpl::handleConnect, this, endpointIterator, boost::asio::placeholder::error));
}
然后你的连接处理程序看起来像(这会尝试端点,直到它得到一个有效的或不再有的):
void Pimpl::handleConnect(
boost::asio::ip::tcp::resolver::iterator endpointIterator,
const boost::system::error_code& ec) {
if (!ec) {
sp_->async_handshake(
boost::asio::ssl::stream_base::client,
boost::bind(&Pimpl::handleHandshake, this, boost::asio::placeholder::error));
}
else if (++endpointIterator != boost::asio::ip::tcp::resolver::iterator()) {
// Try connecting to the next endpoint.
sp_->lowest_layer().close();
sp_->lowest_layer().async_connect(
*endpointIterator,
boost::bind(&Pimpl::handleConnect, this, endpointIterator, boost::asio::placeholder::error));
}
else {
// error handling here
}
}
使这个特定于ssl :: stream指针而不是ip :: tcp :: socket指针的唯一行是async_handshake()调用。
答案 1 :(得分:0)
我找到了解决问题的方法。我使用ssl :: stream类作为套接字对象,错误的原因是因为它没有connect方法。但是,它确实有一个next_layer()方法,它返回一个可以调用connect或async_connect方法的对象。我在编译async_connect时遇到问题,但connect方法有效。然后,我随后调用我的HandleConnect方法:
boost::system::error_code EC;
pSocket->next_layer().connect(EP, EC);
HandleConnect(EC);
在回答@SamMiller代码请求时,请在下面给出。我仍然想知道如何为boost :: asio :: async_connect调用创建端点的迭代器,以及如何调用next_layer对象的async_connect方法。
void SSLSocket::Connect(SSLSocket* psSLS, const string& serverPath, string& port)
{
// Connects to the server.
// serverPath - specifies the path to the server. Can be either an ip address or url.
// port - port server is listening on.
//
try
{
Locking CodeLock(SocketLock); // Single thread the code.
// If the user has tried to connect before, then make sure everything is clean before trying to do so again.
if (pSocket)
{
delete pSocket;
pSocket = 0;
}
// If serverPath is a URL, then resolve the address.
if ((serverPath[0] < '0') || (serverPath[0] > '9')) // Assumes that the first char of the server path is not a number when resolving to an ip addr.
{
// Create the resolver and query objects to resolve the host name in serverPath to an ip address.
boost::asio::ip::tcp::resolver resolver(*IOService);
boost::asio::ip::tcp::resolver::query query(serverPath, port);
boost::asio::ip::tcp::resolver::iterator EndpointIterator = resolver.resolve(query);
// Set up an SSL context.
boost::asio::ssl::context ctx(*IOService, boost::asio::ssl::context::tlsv1_client);
// Specify to not verify the server certificiate right now.
ctx.set_verify_mode(boost::asio::ssl::context::verify_none);
// Init the socket object used to initially communicate with the server.
pSocket = new boost::asio::ssl::stream<boost::asio::ip::tcp::socket>(*IOService, ctx);
//
// The thread we are on now, is most likely the user interface thread. Create a thread to handle all incoming socket work messages.
// This thread is created for each connection to a server.
if (!RcvThreadCreated)
{
WorkerThreads.create_thread(boost::bind(&SSLSocket::RcvWorkerThread, this));
RcvThreadCreated = true;
WorkerThreads.create_thread(boost::bind(&SSLSocket::SendWorkerThread, this));
}
// Try to connect to the server. Note - add timeout logic at some point.
boost::asio::async_connect(pSocket->lowest_layer(), EndpointIterator,
boost::bind(&SSLSocket::HandleConnect, this, boost::asio::placeholders::error));
}
else
{
// serverPath is an ip address, so try to connect using that.
//
// Create an endpoint with the specified ip address.
const boost::asio::ip::address IP(boost::asio::ip::address::from_string(serverPath));
int iport = atoi(port.c_str());
const boost::asio::ip::tcp::endpoint EP(IP, iport);
// Set up an SSL context.
boost::asio::ssl::context ctx(*IOService, boost::asio::ssl::context::tlsv1_client);
// Specify to not verify the server certificiate right now.
ctx.set_verify_mode(boost::asio::ssl::context::verify_none);
// Init the socket object used to initially communicate with the server.
pSocket = new boost::asio::ssl::stream<boost::asio::ip::tcp::socket>(*IOService, ctx);
//
// The thread we are on now, is most likely the user interface thread. Create a thread to handle all incoming socket work messages.
// This thread is created for each connection to a server.
if (!RcvThreadCreated)
{
WorkerThreads.create_thread(boost::bind(&SSLSocket::RcvWorkerThread, this));
RcvThreadCreated = true;
WorkerThreads.create_thread(boost::bind(&SSLSocket::SendWorkerThread, this));
}
// Try to connect to the server. Note - add timeout logic at some point.
// pSocket->next_layer().async_connect(EP, &SSLSocket::HandleConnect);
boost::system::error_code EC;
pSocket->next_layer().connect(EP, EC);
if (EC)
{
// Log an error. This worker thread should exit gracefully after this.
stringstream ss;
ss << "SSLSocket::Connect: connect failed to " << sClientIp << " : " << uiClientPort << ". Error: " << EC.message() + ".\n";
Log.LogString(ss.str(), LogError);
}
HandleConnect(EC);
}
}
catch (std::exception& e)
{
stringstream ss;
ss << "SSLSocket::Connect: threw an error - " << e.what() << ".\n";
Log.LogString(ss.str(), LogError);
Stop();
}
}
这是以下行生成的错误:
pSocket->next_layer().async_connect(EP, &SSLSocket::HandleConnect); // Does not compile
代替:
boost::system::error_code EC;
pSocket->next_layer().connect(EP, EC); // Compiles and works properly.
错误讯息:
1>c:\boost_1_52_0\boost\asio\basic_socket.hpp(706) : error C2064: term does not evaluate to a function taking 1 arguments
1> c:\users\bob\documents\visual studio 2008\projects\attackpoker1\win32client\sslsockets\sslsocket.cpp(114) : see reference to function template instantiation 'void boost::asio::basic_socket<Protocol,SocketService>::async_connect<void(__thiscall SSLSocket::* )(const boost::system::error_code &)>(const boost::asio::ip::basic_endpoint<InternetProtocol> &,const ConnectHandler &)' being compiled
1> with
1> [
1> Protocol=boost::asio::ip::tcp,
1> SocketService=boost::asio::stream_socket_service<boost::asio::ip::tcp>,
1> InternetProtocol=boost::asio::ip::tcp,
1> ConnectHandler=void (__thiscall SSLSocket::* )(const boost::system::error_code &)
1> ]