[英]SocketException (SocketException: Failed host lookup: 'test' (OS Error: nodename nor servname provided, or not known, errno = 8))
[英]SocketException: Failed host lookup: ‘...com’ (OS Error: nodename nor servname provided, or not known, errno = 8)
我們處於生產應用程序面臨以下套接字異常並且在此之后無法執行任何其他網絡操作的情況。
DioError [DioErrorType.DEFAULT]: SocketException: Failed host lookup: ‘xyz.abc.com’ (OS Error: nodename nor servname provided, or not known, errno = 8)
注意:重復遇到一位擁有 iPhone X 的用戶,iOS 14.4
我們使用Dio作為網絡客戶端, Retrofit內部使用來自 dart 的 HttpClient。 對於 Dio,異常無法在模擬環境中重現,但直接使用 HttpClient,可以在 iOS 模擬器中使用以下代碼重現相同的異常。
HttpClient userAgent = new HttpClient();
bool run = true;
while (run) {
try {
await userAgent.getUrl(Uri.parse('https://www.google.com'));
print('Number of api executed');
} catch (e) {
print(e);
if (e is SocketException) {
if ((e as SocketException).osError.errorCode == 8)
print('***** Exception Caught *****');
}
}
}
拋出異常后,HttpClient 無法從陳舊的 state 中恢復,所有其他 API 請求開始失敗並出現相同的錯誤。
通過強制關閉所有先前的連接並打開一個新的 HttpClient,我們能夠從陳舊的 state 中恢復。
HttpClient userAgent = new HttpClient();
bool run = true;
while (run) {
try {
await userAgent.getUrl(Uri.parse('https://www.google.com'));
print('Number of api executed');
} catch (e) {
print(e);
if (e is SocketException) {
if ((e as SocketException).osError.errorCode == 8)
print('***** Exception Caught *****');
}
userAgent.close(force: true);
print('Force closing previous connections');
userAgent = HttpClient();
print('Creating new HttpClient instance');
}
}
一個有趣的事實是在每 236 個請求之后引發異常。 這可能是因為文件描述符過度使用,但 iOS 的限制為 256。
有了穩定的互聯網連接,這個問題每次都可以在 iOS 模擬器中重現。
雖然我無法重現 Dio 客戶端的問題,但在生產中它正在發生。 因此,我正在尋求幫助以了解此問題的根本原因,以及我們如何預防它?
任何遇到過這種情況以及如何克服它的人,請幫助我。
提前致謝。
我用這段代碼解決了同樣的問題:-
示例
//Add This Class
class MyHttpOverrides extends HttpOverrides{
@override
HttpClient createHttpClient(SecurityContext? context){
return super.createHttpClient(context)
..badCertificateCallback = (X509Certificate cert, String host, int port)=> true;
}
}
Future<void> main() async {
HttpOverrides.global = MyHttpOverrides(); //call here
runApp(const MyApp());
}
這是一個奇怪的錯誤。
這可能無法回答您的問題,但可能會促使我們弄清楚發生了什么。
代碼片段(從問題中復制)將在每個.getUrl()
調用中打開一個新的stream
並且不會關閉它們。 (我假設這是故意創建套接字異常?)
HttpClient userAgent = new HttpClient();
bool run = true;
while (run) {
try {
await userAgent.getUrl(Uri.parse('https://www.google.com'));
print('Number of api executed');
} catch (e) {
print(e);
if (e is SocketException) {
if ((e as SocketException).osError.errorCode == 8)
print('***** Exception Caught *****');
}
}
}
在某些時候,達到了(開放流的)限制。 我想在你的情況下這個幻數是 236。
那么在這一點上,當您看到nodename or servname provided
的異常時?
(順便說一句,我認為錯誤來自底層主機操作系統的 DNS 服務,盡管我不確定這是否是由於請求垃圾郵件、打開的連接數等。這可能不是相關信息.)
因此,如果您以典型的方式使用HttpClient
,發出請求並關閉那些打開的流,例如:
var request = await userAgent.getUrl(Uri.parse('http://example.com/'));
var response = await request.close(); // ← close the stream
var body = await response.transform(utf8.decoder).join();
// ↑ convert results to text
// rinse, repeat...
...您是否仍然看到相同的nodename or servname provided
的錯誤彈出?
使用上面的“典型用法”代碼,可以重用userAgent
,直到調用userAgent.close()
(並且 HttpClient 永久關閉。再次嘗試使用它會引發Bad State
異常)。
我很想知道這個修改后的代碼是否仍然出現節點名錯誤。
回復:問題的第二個代碼片段。
在 catch 塊中, HttpClient
被關閉,然后創建一個新的HttpClient
。 這有效地關閉了在try
塊中打開的所有打開流(我假設,重置打開流的限制。)
如果您調整第二個代碼示例以使用:
var req = await userAgent.getUrl(Uri.parse('https://www.google.com'));
userAgent.close(force: true);
userAgent = HttpClient();
print('Number of api executed');
你能無限期地運行它嗎?
1:獲取文件描述符的當前限制
ulimit -n 示例 output:“256”或“10032”。
提示:在 MacOS 上,可以指定的最大數量為 12288。
獲取當前進程限制
ulimit -u 示例 output:“1418”。
sudo launchctl 限制 maxfiles 65536 200000
我在生產中遇到了完全相同的錯誤,它間歇性地發生。 就像貝克所說,關閉連接:
import 'package:http/http.dart' as http;
Future<http.Response> get(String url) async {
var httpClient = http.Client() as http.BaseClient;
Map<String, String> headers = {};
headers['Content-Type'] = 'application/json; charset=UTF-8';
var result = await httpClient
.get(Uri.parse(url), headers: headers)
.timeout(
const Duration(seconds: 60),
onTimeout: () => http.Response('Request Timeout', 408),
);
httpClient.close();
return result;
}
我做了 10 Future.Delayeds
,每次循環執行 300 個get
請求,但沒有發現任何問題。
未來的延遲是這樣完成的:
Future.delayed(const Duration(milliseconds: 10), () async {
for (var i = 0; i < 300; i++) {
var pingResult = await Api.instance.ping();
print('Delayed 1 Result (${i}): ${pingResult.success}');
}
});
Future.delayed(const Duration(milliseconds: 10), () async {
for (var i = 0; i < 300; i++) {
var pingResult = await Api.instance.ping();
print('Delayed 2 Result (${i}): ${pingResult.success}');
}
});
//..
我也發現了同樣的問題,試了各種方法都找不到原因。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.