Mám server aplikáciu, ktorá používa boost ASIO komunikovať s niekoľkými klientmi. Server aplikácia beží na Linux server a klienti spustiť na Windows počítačoch.
Súčasný dizajn je multi-threaded hoci je tam len jeden boost ASIO thead (ktorý beží boost::asio::io_context
). Zvýraznenie ASIO vlákno je zodpovedný len za čítanie, písanie, a niektoré zriedkavé odoslanie. Čítanie je možné pomocou boost::asio::async_read
ale kópií výsledné správy tak, že iného vlákna môže robiť prácu spracovanie. Písanie je vykonané pomocou boost::asio::write
ale správy už boli skopírované a podal off na podporu ASIO niť
Vo väčšine prípadov, keď klient odpojí boost ASIO hádže chybu, som vypol spojené zásuvka, a iné zásuvky pokračovať v práci. Avšak ak sa klienta na pracovnej ploche systému Windows má moc zlyhanie pri boost::asio::write
je písanie, ktoré im potom boost nerozpoznal problém, a visí v boost::asio::write
. To visí na takmer 20 minút, niekedy a serverom nemôže komunikovať s ostatnými klientmi počas tejto doby
Z toho, čo som čítal, on-line autori boost ASIO nemajú v úmysle zaviesť časový limit parameter. Snažil som sa nastavenie SO_SNDTIMEO na 5 sekúnd, ale že nemal mať žiadny vplyv na písanie zavesiť. Ako teraz môj najlepší odhad vyriešiť problém je dať každej zásuvky inom vlákne tak, že jeden klient nemôže vziať nadol ostatných klientov. Existujú aj lepšie možnosti, ako toto? Ak by som si dať každý zásuvky svoje vlastné vlákno znamená to, že budem potrebovať boost::asio::io_context
za nite, aby sa zabránilo napísať zavesiť?
Edit: Po zhliadnutí komentáre snažil som sa redoing funkciu, ktorá hovory boost::asio::write
s boost::asio::async_write
. Nižšie som nejaký kód, ktorý bol zjednodušený TAK, ale stále ukazuje, čo je celková zmena bola:
Pôvodne s boost::asio::write
:
inline void MessagingServer::writeMessage(
GuiSession* const a_guiSession,
const PB::Message& a_msg
) {
boost::asio::dispatch(m_guiIoIoContext, [this, a_guiSession, a_msg]() {
// I removed code that writes a_msg's bytes into m_guiIoWriteBuf
// and sets totalSize to simplify for SO
boost::system::error_code error;
boost::asio::write(a_guiSession->m_guiIoGsSocket, boost::asio::buffer(m_guiIoWriteBuf, totalSize), error);
if (UNLIKELY(error))
ERRLOG << a_guiSession->m_gsSessionId << " write failed: " << error.message();
});
}
Prepracovaný s boost::asio::async_write
:
inline void MessagingServer::writeMessage(
GuiSession* const a_guiSession,
const PB::Message& a_msg
) {
a_guiSession->m_tempMutex.lock();
boost::asio::dispatch(m_guiIoIoContext, [this, a_guiSession, a_msg]() {
// I removed code that writes a_msg's bytes into m_guiIoWriteBuf
// and sets totalSize to simplify for SO
boost::asio::async_write(
a_guiSession->m_guiIoGsSocket,
boost::asio::buffer(m_guiIoWriteBuf, totalSize),
[this, a_guiSession](const boost::system::error_code& a_error, std::size_t) {
if (UNLIKELY(a_error))
ERRLOG << a_guiSession->m_gsSessionId << " write failed: " << a_error.message();
a_guiSession->m_tempMutex.unlock();
}
);
});
}
Zámok bol predstavený v druhej kód zaručiť iba jeden hovor boost::asio::async_write
bol aktívny v čase (som si vedomý, že tam sú ďalšie výkonné spôsoby, ako to urobiť, ale je to jednoduchšie pre testovanie). Obe tieto kódy majú rovnaký problém zavesenie boost ASIO, keď klient má výpadku napájania. Avšak oni to visieť v rôznych spôsobov, asynchrónne kód robí umožňujú zvýšiť ASIO vykonávať iné činnosti, len nie ďalej píše, kým visí jeden produkuje chybu
Počas samostatnej experiment som si vyskúšať nastavenie SO_KEEPALIVE
ale to tiež nepodarilo vyriešiť problém zavesiť