[英]OpenSSL client stuck in endless read
我正在使用cpp-httplib通過長時間輪詢從服務器檢索一些數據(也就是說,客戶端將向服務器發出請求,並且服務器將保持打開連接狀態,直到所需數據可用或超時為止)。
該程序在我的樹莓派上運行,它位於沒有傳出靜態IP地址的路由器后面。 每次重新分配ip(或至少接近該時間點)時,我的程序都會中斷,因為當前執行輪詢的線程將永遠卡在httplib::SSLClient::Get
,這是由阻塞引起的read()
系統調用。 服務器和客戶端超時都無法執行任何操作,而連接關閉應該使讀取立即返回0,這是我在這種情況下的預期。
使用gdb檢查程序將顯示以下內容:
(gdb) thread 2
(gdb) where
__libc_read (nbytes=5, buf=0x75608edb, fd=3) at ../sysdeps/unix/sysv/linux/read.c:26
__libc_read (fd=3, buf=0x75608edb, nbytes=5) at ../sysdeps/unix/sysv/linux/read.c:24
0x76d1862c in ?? () from /usr/lib/arm-linux-gnueabihf/libcrypto.so.1.1
Backtrace stopped: previous frame identical to this frame (corrupt stack?)
據我所知,我沒有做任何可能會意外覆蓋返回地址的事情。
為了進行比較,可以在此處找到SSLCLient::Get
期間的“正常”堆棧跟蹤。
實際的代碼很多,但是下面的簡短版本顯示了相同的行為:
#include <iostream>
#define CPPHTTPLIB_OPENSSL_SUPPORT 1
#include "httplib.h"
void poll(httplib::SSLClient* c, char* path) {
while (true) {
auto response = c->Get(path);
std::cout << response.body << std::endl;
}
}
int main(int argc, char* argv[]) {
if (argc >= 3) {
httplib::SSLClient client(argv[1], 443, 20);
std::thread poll_thread(poll, &client, argv[2]);
poll_thread.join();
} else {
std::cerr << "Usage: ./poll <host> <path>" << std::endl;
return 1;
}
}
我可以想到一些可能會或可能不會奏效的解決方法,但是我真的很想知道為什么會這樣以及如何首先發生這種情況。
只是擴展了我在評論中提到的keep_alive選項。
在您描述的場景中,底層的TCP套接字連接似乎以一種不干凈的方式終止了。 即,您說的是IP地址已重新分配。
理想情況下,當存在TCP套接字終止時,您希望您的代碼退出所有阻止的讀/輪詢操作。 正常的套接字關閉將發生這種情況,例如說遠程進程被殺死,或者遠程進程只是確定是時候關閉了。 但是,如果您的主機的IP地址已更改....我不確定是否一定會有低級別的TCP消息表明該連接現在已關閉,從而影響了連接。 因此,對於您的程序而言,結果是仍然可以保留本地套接字(本地TCP端點),而沒有意識到連接已斷開。
這是諸如keep_alive之類的地方。 這個想法是內核將發送保持活動的數據包以繼續測試是否建立了連接。 如果這些操作失敗,則可以關閉本地套接字(因此,阻塞讀取或阻塞選擇將返回,並帶有某種流終止錯誤)。
除keep_alive之外,您還可以考慮應用程序心跳消息(例如,websocket具有ping / pong)。 除了確保TCP連接保持建立狀態之外,它還可以確認遠程應用程序是否正常。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.