C++ Boost ASIO: bagaimana cara membaca/menulis dengan batas waktu?

Dari membaca entri Stack Overflow lainnya dan dokumentasi boost::asio, saya telah mengonfirmasi bahwa tidak ada panggilan baca/tulis ASIO sinkron yang juga menyediakan batas waktu yang mudah digunakan sebagai parameter panggilan.

Saya sedang mengonversi aplikasi soket Linux jadul dengan panggilan pilih(2) yang menggunakan batas waktu, dan saya perlu melakukan hal yang kurang lebih sama.

Jadi apa cara terbaik untuk melakukan ini di boost::asio? Melihat dokumentasi asio, ada banyak contoh membingungkan tentang berbagai hal yang berkaitan dengan pengatur waktu, tapi saya cukup bingung.

Saya ingin melihat contoh yang mudah dibaca: Membaca dari soket, tetapi menunggu maksimal X detik setelah itu fungsi akan kembali tanpa apa-apa, atau kembali dengan apa pun yang dapat dibacanya dari soket sebelum batas waktu habis.


person Stéphane    schedule 29.12.2010    source sumber
comment
Bisakah Anda menjelaskan apa yang membingungkan tentang contoh ini: think-async.com/Asio/asio-1.4.7/src/examples/timeouts/ - Logika pentingnya adalah, Anda mengirimkan 2 tugas async, satu tugas baca/tulis dan yang lainnya batas waktu jika baca/tulis kembali terlebih dahulu Anda mematikan pengatur waktu tenggat waktu, jika pengatur waktu tenggat waktu mengembalikan logikanya adalah baca/tulis masih luar biasa - dari sana Anda melanjutkan dengan logika batas waktu Anda. sangat sangat sederhana.   -  person    schedule 29.12.2010
comment
Ada satu kasus sudut yang mungkin muncul di jaringan hf yang terkait dengan antrian callback. batas waktu cb diantri, lalu baca/tulis diantri. Anda menemukan batas waktu cb dan mulai menjalankan logika batas waktu padahal kenyataannya baca/tulis telah selesai, solusi yang mungkin saya lihat adalah sesuatu yang mirip dengan kunci periksa ulang - singkatnya, lakukan batas waktu kedua ketika batas waktu pertama kembali, tapi kemudian ini memiliki masalah yang sama bagaimana jika baca/tulis diantri setelah batas waktu ke-2 adalah antrian...   -  person    schedule 29.12.2010
comment
Ingatlah bahwa batas waktu adalah kondisi yang sulit, Anda mengatakan jika saya tidak mendapatkan sesuatu dalam jangka waktu tertentu, saya akan melakukan sesuatu yang spesifik - ini termasuk fakta bahwa proses baca/tulis mungkin telah terjadi dan sedang dalam perjalanan. bagi Anda, itu tidak mengubah fakta bahwa Anda belum menerimanya.   -  person    schedule 29.12.2010
comment
@zenikoder Saya yakin kebingungannya adalah konstruksi batas waktu yang disediakan oleh asio menegakkan menggunakan metode asinkron, mereka tidak dapat digunakan dengan metode sinkron.   -  person Sam Miller    schedule 29.12.2010
comment
@Sam: Anda dapat membuat batas waktu sinkron, Anda cukup menyembunyikan panggilan asinkron di belakang antarmuka sinkronisasi yang memblokir, hingga batas waktu atau baca/tulis terjadi.   -  person    schedule 29.12.2010


Jawaban (2)


Hal ini telah dibahas di milis asio, ada tiket yang meminta fitur tersebut demikian juga. Singkatnya, disarankan untuk menggunakan metode asinkron jika Anda menginginkan waktu habis dan pembatalan.


Jika Anda tidak dapat mengonversi ke metode asinkron, Anda dapat mencoba opsi soket SO_RCVTIMEO dan SO_SNDTIMEO. Mereka dapat diatur dengan setsockopt, deskriptornya dapat diperoleh dengan rel boost::asio::ip::tcp::socket::native. Halaman manual man 7 socket mengatakan

SO_RCVTIMEO dan SO_SNDTIMEO Tentukan batas waktu penerimaan atau pengiriman hingga melaporkan kesalahan. Argumennya adalah timeval struct. Jika fungsi masukan atau keluaran diblokir selama periode waktu ini, dan data telah dikirim atau diterima, nilai kembalian fungsi tersebut adalah jumlah data yang ditransfer; jika tidak ada data yang ditransfer dan batas waktu telah tercapai maka -1 dikembalikan dengan errno disetel ke EAGAIN atau EWOULDBLOCK sama seperti jika soket ditentukan sebagai non-pemblokiran. Jika batas waktu diatur ke nol (default) maka operasi tidak akan pernah habis waktu. Batas waktu hanya berlaku untuk panggilan sistem yang menjalankan I/O soket (misalnya, read(2), recvmsg(2), send(2), sendmsg(2)); batas waktu tidak berpengaruh untuk pilih(2), jajak pendapat(2), epoll_wait(2), dll.

person Sam Miller    schedule 29.12.2010
comment
Apakah Anda membaca tanggapan CH terhadap permintaan tersebut? ASIO mereplikasi fungsionalitas OS di C++, jika Anda memerlukan semacam fungsionalitas time-out, Anda dipersilakan untuk mengimplementasikannya menggunakan bit-n-pieces yang disediakan ASIO. - person ; 29.12.2010

Saya menggunakan beberapa asio docs untuk menghasilkan ini:

class TimeoutAdjust
{
public:
  TimeoutAdjust(unsigned int dwTimeout) : m_dwTimeout(dwTimeout) {};

  template<class Protocol>
  int level(const Protocol& p) const {return SOL_SOCKET;}

  template<class Protocol>
  int name(const Protocol& p) const {return SO_SNDTIMEO;}

  template<class Protocol>
  const void* data(const Protocol& p) const {return &m_dwTimeout;}

  template<class Protocol>
  size_t size(const Protocol& p) const {return sizeof(m_dwTimeout);}
private:
  unsigned int m_dwTimeout;
};

Penggunaan:

TimeoutAdjust adjust(5000);
sSocket.set_option(adjust);

Saya men-debugnya, dan tampaknya melakukan apa yang seharusnya.

person ArtHare    schedule 06.07.2013
comment
Apa yang saya baca di sini adalah SO_SNDTIMEO membutuhkan timeval, bukan unsigned int. linux.die.net/man/7/socket - person updogliu; 15.07.2014
comment
Ah, dokumen MS menggunakan DWORD untuk SO_SNDTIMEO. Sepertinya timeval adalah sepasang int yang panjang, jadi berhati-hatilah pembaca. Dokumen MS: msdn.microsoft. com/en-ca/library/windows/desktop/ - person ArtHare; 15.07.2014
comment
Setelah menggunakan kode di atas saya mendapatkan pengecualian Pengecualian: set_option: Argumen tidak valid. Jika Anda memiliki beberapa kode referensi, silakan bagikan yang sama. - person asim; 12.09.2014