udp::socket receiver(ios, udp::endpoint(udp::v4(), port)); char read_buf[buf_len]; udp::endpoint sender_point; receiver.receive_from(buffer(read_buf, sizeof(read_buf)), sender_point);
受信したデータグラムに、バッファに割り当てたよりも多くのデータがある場合はどうなりますか?
WIN / LINUXプラットフォームでは動作に不一致があります。 Linuxでは、操作はスムーズに進み、要求されたとおりに正確に読み取られ、残りは破棄されます。 Winでは、読み取りデータも取得しますが、その後、例外も取得します。
これが起こる理由は次のとおりです。
receive_from関数の関数は、次のコードの実行に限定されます
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) int result = error_wrapper(::WSARecvFrom(s, bufs, recv_buf_count, &bytes_transferred, &recv_flags, addr, &tmp_addrlen, 0, 0), ec); *addrlen = (std::size_t)tmp_addrlen; ... if (result != 0) return socket_error_retval; ec = boost::system::error_code(); return bytes_transferred; #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) msghdr msg = msghdr(); init_msghdr_msg_name(msg.msg_name, addr); msg.msg_namelen = *addrlen; msg.msg_iov = bufs; msg.msg_iovlen = count; int result = error_wrapper(::recvmsg(s, &msg, flags), ec); *addrlen = msg.msg_namelen; if (result >= 0) ec = boost::system::error_code(); return result;
WSARecvFrom for Winおよびrecvmsg for Linuxは、ソケットからデータを受信するために使用されます。 関数の結果(成功/失敗)は、次の関数によって決定されます。
template <typename ReturnType> inline ReturnType error_wrapper(ReturnType return_value, boost::system::error_code& ec) { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) ec = boost::system::error_code(WSAGetLastError(), boost::asio::error::get_system_category()); #else ec = boost::system::error_code(errno, boost::asio::error::get_system_category()); #endif return return_value; }
WSARecvFrom関数の説明から、エラーステータスが返されることがわかります。
エラーが発生せず、受信操作がすぐに完了した場合、WSARecvFromはゼロを返します。 それ以外の場合、SOCKET_ERRORの値が返され、WSAGetLastErrorを呼び出すことで特定のエラーコードを取得できます。
その1つは次のとおりです。
WSAEMSGSIZE
メッセージが指定されたバッファーに対して大きすぎたため、(信頼性の低いプロトコルのみ)バッファーに収まらなかったメッセージの後続部分はすべて破棄されました。
recvファミリー関数は、正常に読み取られたバイト数を返します。エラーの場合は-1、errnoにステータスが返されます。 しかし、彼女の間違いのなかには、上記のようなものはありません。 Linuxは間違いではないことがわかりましたか? あまり好きではありません。 エラーコードは、関数に渡されるrecvmsg関数のmsg_flagsフィールドに書き込まれます(つまり、asioで使用されます)。
MSG_TRUNC
指定されたバッファよりも大きい場合でも、実際のパケット長を返します。 このフラグは、パケットプロトコルでのみ使用できます。
したがって、Winでの同じ操作はエラーと見なされ、Linuxでは正しいと見なされます。 これは明らかにasioに考慮されていません。
続く困難の1つは、データグラムがすべて読み込まれなかったことをWinで判断できないことです。
この問題の可能な解決策は、 利用可能な機能を使用することです 。 しかし、ここでも、さらに恐ろしい不一致が生じます。 Winプラットフォーム上のこの関数は、UDPソケット内のデータの総量(すべてのデータグラムのデータの合計)を返します。Linuxプラットフォームでは、サイズはデータグラムの最初(次の読み取りで処理されるもの)のみです。
そして、上記のすべての完全な例は次のとおりです。
ソース
出力勝利:
例外:receive_from:データグラムソケットに送信されたメッセージが内部メッセージバッファよりも大きいか、別のネットワークパラメータを超えました。 また、メッセージを受信するためのバッファがメッセージのサイズよりも小さい可能性があります。
いくつかのテスト
利用可能:36
利用可能:18
利用可能:0
出力Linux:
いくつかのテスト
利用可能:18
利用可能:18
利用可能:0
Boostバージョン1.44および1.49でテストされました。
ご清聴ありがとうございました。