200ms(5fps)ごとにudpパケット(イメージを含む)をブロードキャストする複数のピアを使用するセットアップがあります。
外部ストリームとして両方のローカルストリームを受信することはWindowsで正常に機能しますが、同じコード(socket->cancel();
Windows XPを除く、コードのコメントを参照)は、Linuxではかなり奇妙な動作を生成します。
- 別のマシンによって送信された最初の数(5〜7)パケット(このマシンがストリーミングを開始したとき)は、期待どおりに受信されます。
- この後、他のマシンからのパケットは、不規則で長い間隔(12秒、5秒、17秒など)の後に受信されるか、タイムアウト(20秒後に定義)を取得します。ある瞬間に、期待どおりに(3〜4)パケットのバーストが再び受信されます。
- マシン自体によって送信されたパケットは、まだ期待どおりに受信されています。
Wiresharkを使用すると、ローカルと外部の両方のパケットが適切に到着し、連続するパッケージ間の時間間隔が正しいことがわかります。この動作は、ローカルマシンが他の単一のストリームのみをリッスンしていて、ローカルストリームが無効になっている場合にも発生します。
これは受信者からのコードです(以下に提案されているようにいくつかの更新があります、ありがとう!):
Receiver::Receiver(port p)
{
this->port = p;
this->stop = false;
}
int Receiver::run()
{
io_service io_service;
boost::asio::ip::udp::socket socket(
io_service,
boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(),
this->port));
while(!stop)
{
const int bufflength = 65000;
int timeout = 20000;
char sockdata[bufflength];
boost::asio::ip::udp::endpoint remote_endpoint;
int rcvd;
bool read_success = this->receive_with_timeout(
sockdata, bufflength, &rcvd, &socket, remote_endpoint, timeout);
if(read_success)
{
std::cout << "read succes " << remote_endpoint.address().to_string() << std::endl;
}
else
{
std::cout << "read fail" << std::endl;
}
}
return 0;
}
void handle_receive_from(
bool* toset, boost::system::error_code error, size_t length, int* outsize)
{
if(!error || error == boost::asio::error::message_size)
{
*toset = length>0?true:false;
*outsize = length;
}
else
{
std::cout << error.message() << std::endl;
}
}
// Update: error check
void handle_timeout( bool* toset, boost::system::error_code error)
{
if(!error)
{
*toset = true;
}
else
{
std::cout << error.message() << std::endl;
}
}
bool Receiver::receive_with_timeout(
char* data, int buffl, int* outsize,
boost::asio::ip::udp::socket *socket,
boost::asio::ip::udp::endpoint &sender_endpoint, int msec_tout)
{
bool timer_overflow = false;
bool read_result = false;
deadline_timer timer( socket->get_io_service() );
timer.expires_from_now( boost::posix_time::milliseconds(msec_tout) );
timer.async_wait( boost::bind(&handle_timeout, &timer_overflow,
boost::asio::placeholders::error) );
socket->async_receive_from(
boost::asio::buffer(data, buffl), sender_endpoint,
boost::bind(&handle_receive_from, &read_result,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred, outsize));
socket->get_io_service().reset();
while ( socket->get_io_service().run_one())
{
if ( read_result )
{
timer.cancel();
}
else if ( timer_overflow )
{
//not to be used on Windows XP, Windows Server 2003, or earlier
socket->cancel();
// Update: added run_one()
socket->get_io_service().run_one();
}
}
// Update: added run_one()
socket->get_io_service().run_one();
return read_result;
}
タイマーが20秒を超えると、「操作がキャンセルされました」というエラーメッセージが返されますが、他に何が起こっているかについての情報を取得することは困難です。
誰かが問題を特定したり、何が問題になっているのかについてさらに情報を得るためのヒントを教えてもらえますか?どんな助けでも大歓迎です。