保留中の操作を (切断せずに) キャンセルする方法、またはブースト ライブラリ関数のタイムアウトを設定する方法はありますか?
つまり、boost asio でソケットをブロックする際にタイムアウトを設定したいですか?
socket.read_some(boost::asio::buffer(pData, maxSize), error_);
例: ソケットからいくつか読み取りたいが、10 秒経過したらエラーを発生させたい。
保留中の操作を (切断せずに) キャンセルする方法、またはブースト ライブラリ関数のタイムアウトを設定する方法はありますか?
つまり、boost asio でソケットをブロックする際にタイムアウトを設定したいですか?
socket.read_some(boost::asio::buffer(pData, maxSize), error_);
例: ソケットからいくつか読み取りたいが、10 秒経過したらエラーを発生させたい。
この質問がされたとき、ASIO には、OP が必要とすることを達成する方法、つまりブロッキング ソケット操作などのブロッキング操作をタイムアウトにする方法の例がなかったと思います。これを行う方法を正確に示す例があります。この例は長いように見えますが、それは WELL コメントが付けられているためです。「ワンショット」モードで ioservice を使用する方法を示します。
例は素晴らしい解決策だと思います。ここでの他のソリューションは移植性を壊し、ioservice を利用しません。移植性が重要ではなく、ioservice のオーバーヘッドが大きいように思われる場合は、ASIO を使用しないでください。いずれにせよ、ioservice が作成されるので (ほとんどすべての ASIO 機能がそれに依存し、同期ソケットも含まれます)、それを利用してください。
ASIO のドキュメントが更新されたので、ASIO が使用する「落とし穴」のいくつかを克服する方法に関する新しい例を確認してください。
async_readを実行し、希望するタイムアウトのタイマーを設定することもできます。次に、タイマーが起動した場合は、ソケットオブジェクトでcancelを呼び出します。それ以外の場合、読み取りが発生した場合は、タイマーをキャンセルできます。もちろん、これにはio_serviceオブジェクトを使用する必要があります。
編集:これを行うコードスニペットを見つけました
私は同じ質問をしていましたが、いくつかの調査の結果、私が思いついた最も単純でクリーンな解決策は、基礎となるネイティブ ソケットを取得し、読み取るデータが存在するまで選択を行うことでした。Select はタイムアウト パラメータを受け取ります。もちろん、ネイティブ ソケットを使用することは、そもそも asio を使用するという点に反し始めますが、繰り返しますが、これが最もクリーンな方法のようです。私が知る限り、asio は同期使用のためにこれを簡単に行う方法を提供していません。コード:
// socket here is: boost::shared_ptr<boost::asio::ip::tcp::socket> a_socket_ptr
// Set up a timed select call, so we can handle timeout cases.
fd_set fileDescriptorSet;
struct timeval timeStruct;
// set the timeout to 30 seconds
timeStruct.tv_sec = 30;
timeStruct.tv_usec = 0;
FD_ZERO(&fileDescriptorSet);
// We'll need to get the underlying native socket for this select call, in order
// to add a simple timeout on the read:
int nativeSocket = a_socket_ptr->native();
FD_SET(nativeSocket,&fileDescriptorSet);
select(nativeSocket+1,&fileDescriptorSet,NULL,NULL,&timeStruct);
if(!FD_ISSET(nativeSocket,&fileDescriptorSet)){ // timeout
std::string sMsg("TIMEOUT on read client data. Client IP: ");
sMsg.append(a_socket_ptr->remote_endpoint().address().to_string());
throw MyException(sMsg);
}
// now we know there's something to read, so read
boost::system::error_code error;
size_t iBytesRead = a_socket_ptr->read_some(boost::asio::buffer(myVector), error);
...
おそらく、これはあなたの状況に役立つでしょう。
Linux/BSD では、ソケットでの I/O 操作のタイムアウトは、オペレーティング システムによって直接サポートされています。このオプションは、 で有効にできますsetsocktopt()
。boost::asio
それを設定する方法を提供するのか、ソケットスクリプトを公開して直接設定できるようにするのかはわかりません.後者の場合は実際には移植性がありません.
完全を期すために、マニュアルページの説明を次に示します。
SO_RCVTIMEOとSO_SNDTIMEO
Specify the receiving or sending timeouts until reporting an error. The argument is a struct timeval. If an input or output function blocks for this period of time, and data has been sent or received, the return value of that function will be the amount of data transferred; if no data has been transferred and the timeout has been reached then -1 is returned with errno set to EAGAIN or EWOULDBLOCK just as if the socket was specified to be non-blocking. If the timeout is set to zero (the default) then the operation will never timeout. Timeouts only have effect for system calls that perform socket I/O (e.g., read(2), recvmsg(2), send(2), sendmsg(2)); timeouts have no effect for select(2), poll(2), epoll_wait(2), etc.
grepsedawk が言及したことに続きます。asio docoのTimeoutsセクションに、長時間実行されている非同期操作を一定期間後にキャンセルする方法を示すいくつかの例があります。ブースト Asio の例 . 非同期 TCP クライアントが最も役に立ちました。
幸せな非同期:)
SO_RCVTIMEO
の代わりに構造体をSO_SNDTIMEO
取り込みます。したがって、@Pavel Verevkin のオプション 1. はan の代わりに a を取り込む必要があり、オプション 2. は単一の整数値のみを格納するため、クラスを実装する必要があります。timeval
"sys/time.h"
int
timeval
int
boost::asio::detail::socket_option::integer
*nix では、alarm() を使用して、ソケット呼び出しが EINTR で失敗するようにします。