[英]How to accept boost::asio::ssl::stream<boost::asio::ip::tcp::socket> as an argument of type boost::asio::ip::tcp::socket
[英]boost::asio::ip::tcp::socket - How to bind to a specific local port
我正在制作一個客戶端套接字。
為了讓我的測試人員更輕松,我想指定套接字將使用的網卡和端口。
昨天,在我的谷歌搜索中,我發現: Binding boost asio to local tcp endpoint
通過執行 open、bind 和 async_connect,我能夠綁定到特定的網卡,並且我開始在 Wireshark 中看到流量。
但是,Wireshark 報告套接字已被賦予一個隨機端口,而不是我指定的端口。 我想如果端口正在使用它會填寫傳遞給綁定方法的 error_code 。
我做錯了什么?
這是我的最小示例,從我的真實解決方案中提取和編輯。
// Boost Includes
#include <boost/asio.hpp>
#include <boost/atomic.hpp>
#include <boost/bind.hpp>
#include <boost/thread.hpp>
#include <boost/thread/condition_variable.hpp>
// Standard Includes
#include <exception>
#include <memory>
#include <string>
#include <sstream>
boost::asio::io_service g_ioService; /** ASIO sockets require an io_service to run on*/
boost::thread g_thread; /** thread that will run the io_service and hence where callbacks are called*/
boost::asio::ip::tcp::socket g_socket(g_ioService); /** Aync socket*/
boost::asio::ip::tcp::resolver g_resolver(g_ioService); /** Resolves IP Addresses*/
//--------------------------------------------------------------------------------------------------
void OnConnect(const boost::system::error_code & errorCode, boost::asio::ip::tcp::resolver::iterator endpoint)
{
if (errorCode || endpoint == boost::asio::ip::tcp::resolver::iterator())
{
// Error - An error occured while attempting to connect
throw std::runtime_error("An error occured while attempting to connect");
}
// We connected to an endpoint
/*
// Start reading from the socket
auto callback = boost::bind(OnReceive, boost::asio::placeholders::error);
boost::asio::async_read_until(g_socket, m_receiveBuffer, '\n', callback);
*/
}
//--------------------------------------------------------------------------------------------------
void Connect()
{
const std::string hostName = "10.84.0.36";
const unsigned int port = 1007;
// Resolve to translate the server machine name into a list of endpoints
std::ostringstream converter;
converter << port;
const std::string portAsString = converter.str();
boost::asio::ip::tcp::resolver::query query(hostName, portAsString);
boost::system::error_code errorCode;
boost::asio::ip::tcp::resolver::iterator itEnd;
boost::asio::ip::tcp::resolver::iterator itEndpoint = g_resolver.resolve(query, errorCode);
if (errorCode || itEndpoint == itEnd)
{
// Error - Could not resolve either machine
throw std::runtime_error("Could not resolve either machine");
}
g_socket.open(boost::asio::ip::tcp::v4(), errorCode);
if (errorCode)
{
// Could open the g_socket
throw std::runtime_error("Could open the g_socket");
}
boost::asio::ip::tcp::endpoint localEndpoint(boost::asio::ip::address::from_string("10.86.0.18"), 6000);
g_socket.bind(localEndpoint, errorCode);
if (errorCode)
{
// Could bind the g_socket to local endpoint
throw std::runtime_error("Could bind the socket to local endpoint");
}
// Attempt to asynchronously connect using each possible end point until we find one that works
boost::asio::async_connect(g_socket, itEndpoint, boost::bind(OnConnect, boost::asio::placeholders::error, boost::asio::placeholders::iterator));
}
//--------------------------------------------------------------------------------------------------
void g_ioServiceg_threadProc()
{
try
{
// Connect to the server
Connect();
// Run the asynchronous callbacks from the g_socket on this thread
// Until the io_service is stopped from another thread
g_ioService.run();
}
catch (...)
{
throw std::runtime_error("unhandled exception caught from io_service g_thread");
}
}
//--------------------------------------------------------------------------------------------------
int main()
{
// Start up the IO service thread
g_thread.swap(boost::thread(g_ioServiceg_threadProc));
// Hang out awhile
boost::this_thread::sleep_for(boost::chrono::seconds(60));
// Stop the io service and allow the g_thread to exit
// This will cancel any outstanding work on the io_service
g_ioService.stop();
// Join our g_thread
if (g_thread.joinable())
{
g_thread.join();
}
return true;
}
正如您在以下屏幕截圖中看到的,選擇了一個隨機端口 32781,而不是我請求的端口 6000。
6000 是遠程端點端口,它被正確使用(否則,您將無法連接到服務器端)。
來自: https : //idea.popcount.org/2014-04-03-bind-before-connect/
TCP/IP 連接由四元素元組標識:{源 IP、源端口、目標 IP、目標端口}。 要建立 TCP/IP 連接,只需要目標 IP 和端口號,操作系統會自動選擇源 IP 和端口。
由於您沒有綁定到本地端口,因此會從“臨時端口范圍”中隨機選擇一個。 到目前為止,這是通常的連接方式。
不要害怕:
可以通過在調用
connect()
之前調用bind()
來要求內核選擇特定的源 IP 和端口s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # Let the source address be 192.168.1.21:1234 s.bind(("192.168.1.21", 1234)) s.connect(("www.google.com", 80))
樣本是python。
你這樣做了,但仍然得到另一個端口。 提示端口可能不可用。
查看鏈接文章中關於SO_REUSEADDR
和SO_REUSEPORT
的信息
我懷疑話題啟動者是否仍然對這個問題感興趣,但對於像我這樣的所有未來尋求者,這里是解決方案。
這里的問題是boost::asio::connect
在為提供的范圍內的每個端點調用connect
之前關閉套接字:
來自 boost/asio/impl/connect.hpp:
template <typename Protocol BOOST_ASIO_SVC_TPARAM,
typename Iterator, typename ConnectCondition>
Iterator connect(basic_socket<Protocol BOOST_ASIO_SVC_TARG>& s,
Iterator begin, Iterator end, ConnectCondition connect_condition,
boost::system::error_code& ec)
{
ec = boost::system::error_code();
for (Iterator iter = begin; iter != end; ++iter)
{
iter = (detail::call_connect_condition(connect_condition, ec, iter, end));
if (iter != end)
{
s.close(ec); // <------
s.connect(*iter, ec);
if (!ec)
return iter;
}
...
}
這就是綁定地址被重置的原因。 為了保持綁定,可以直接使用socket.connect/async_connect(...)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.