BoostASIOを使用するTCPサーバーがあります。boost::asio::ip::tcp::acceptor
LinuxでリンクスコープのIPv6アドレスを使用する場合、例外をスローせずにを作成できないことに気づきました。グローバルIPv6アドレスまたはIPv4アドレスを使用すると正常に機能します。
問題はスコープIDが正しく設定されていないことにあると確信していますが、問題を解決する方法がわかりません。
私はubuntuが提供するboost1.40.0ライブラリを使用してUbuntu11.04LTSで開発しています。これが私が持っているサーバーコードの非常に唖然としたバージョンで、問題を示しています:
#include <boost/asio.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/bind.hpp>
#include <iostream>
#include <string>
/* To Compile:
g++ -Wall -o ./asio-ipv6 ./asio-ipv6.cpp -lboost_system
*/
typedef boost::shared_ptr<boost::asio::ip::tcp::socket> TcpSocketPtr;
typedef boost::shared_ptr<boost::asio::ip::tcp::acceptor> TcpAcceptorPtr;
typedef boost::shared_ptr<boost::asio::ip::tcp::endpoint> TcpEndpointPtr;
class AsioServer{
public:
AsioServer(boost::asio::io_service& io): io_(io){};
//throws
void accept(const std::string& ipString,unsigned short port){
boost::asio::ip::address addr = boost::asio::ip::address::from_string(ipString);
std::cout << "Valid IP address " << ipString << std::endl;
this->endpoint_.reset(new boost::asio::ip::tcp::endpoint(addr,port));
std::cout << "Created endpoint" << std::endl;
//Will throw if a link local IPv6 address is used
acceptor_.reset(new boost::asio::ip::tcp::acceptor(this->io_,*(this->endpoint_)));
std::cout << "About to accept on " << *(this->endpoint_) << std::endl;
this->socket_.reset(new boost::asio::ip::tcp::socket(this->io_));
this->acceptor_->async_accept(*socket_ ,boost::bind(&AsioServer::handle_accept,this,boost::asio::placeholders::error));
}
private:
boost::asio::io_service& io_;
TcpSocketPtr socket_;
TcpAcceptorPtr acceptor_;
TcpEndpointPtr endpoint_;
void handle_accept(const boost::system::error_code &ec){
if(!ec){
std::cout << "Accepted connection!" << std::endl;
}
else{
std::cout << "Error accepting connection" << std::endl;
}
};
};
int main(int argc, char* argv[]){
boost::asio::io_service io;
std::string ipString("0.0.0.0");
if(argc > 1){
ipString.assign(argv[1]);
}
std::cout << "IP Set to " << ipString << std::endl;
AsioServer server(io);
try{
server.accept(ipString,4444);
}
catch(const std::exception& e){
std::cout << "Error caught: " << e.what() << std::endl;
}
io.run();
std::cout << "Done!" << std::endl;
return 0;
}
このマシンでは、eth0用に次のように構成されています。
$ ifconfig eth0
eth0 Link encap:Ethernet HWaddr 00:0c:29:10:cf:0e
inet addr:192.168.97.162 Bcast:192.168.97.255 Mask:255.255.255.0
inet6 addr: 2620:1c:8000:190:20c:29ff:fe10:cf0e/64 Scope:Global
inet6 addr: fe80::20c:29ff:fe10:cf0e/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:112470185 errors:2 dropped:1 overruns:0 frame:0
TX packets:5900249 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:2187237130 (2.1 GB) TX bytes:1640094885 (1.6 GB)
Interrupt:19 Base address:0x2000
192.168.97.162、0.0.0.0、127.0.0.1、:: 1または2620:1c:8000:190:20c:29ff:fe10:cf0eを使用してプログラムを実行すると正常に動作しますが、fe80 :: 20c:29ff:fe10:cf0eを使用すると失敗します「無効な引数」例外がスローされたアクセプターを作成します。
$ ./asio-ipv6 fe80::20c:29ff:fe10:cf0e
IP Set to fe80::20c:29ff:fe10:cf0e
Valid IP address fe80::20c:29ff:fe10:cf0e
Created endpoint
Error caught: Invalid argument
Done!
これは、ping6を使用していて、同じ「無効な引数」エラーが表示されることを思い出させます。修正は、IPv6アドレスに追加されたインターフェイスを渡すことです。
$ ping6 fe80::219:b9ff:fe2b:3a53 #Won't work
connect: Invalid argument
$ ping6 fe80::219:b9ff:fe2b:3a53%eth0 #Pass the interface to use to ping6
PING fe80::219:b9ff:fe2b:3a53%eth0(fe80::219:b9ff:fe2b:3a53) 56 data bytes
文字列からIPアドレスを作成しようとすると、BoostAsioではこれが機能しないようです。
$ ./asio-ipv6 fe80::20c:29ff:fe10:cf0e%eth0
IP Set to fe80::20c:29ff:fe10:cf0e%eth0
Error caught: Invalid argument
Done!
私の質問は、Boost ASIOを使用してリンクスコープのIPv6アドレスをどのようにリッスンするのですか?boost::asio::ip::address_v6
クラスにはscope_id()メンバー関数がありますが、スコープIDをunsigned longとして取得する場所、またはこれが問題であるかどうかはわかりません。