ASP.NET Core 1.1.4下ApnsStream.AuthenticateAsClientAsync无返回,连接呈CLOSE_WAIT状态
结合你描述的情况(证书已通过Pusher验证可用、修改SSL协议无效果、连接处于CLOSE_WAIT状态),给你几个具体的排查和解决方向:
检查异步调用是否存在死锁
ASP.NET Core的同步上下文很容易因不当的异步调用触发死锁,比如你在同步方法里调用OpenSslStreamAsync时用了.Wait()或者.Result,这会阻塞上下文,导致AuthenticateAsClientAsync()无法完成回调。一定要确保所有异步方法都通过await调用,避免同步阻塞异步操作。强制指定TLS 1.2协议版本
APNs早已不再支持TLS 1.0/1.1,你之前尝试修改SSL协议可能没指定到正确版本。在创建SslStream并调用认证方法时,明确指定SslProtocols.Tls12,代码示例:private async Task<bool> OpenSslStreamAsync(string host, X509CertificateCollection certificates) { Logger.Info("Creating SSL connection..."); using (var tcpClient = new TcpClient(host, 443)) // 或APNs对应的5223端口 using (var networkStream = tcpClient.GetStream()) using (var sslStream = new SslStream(networkStream, false)) { try { // 明确指定TLS 1.2,禁用旧版本 await sslStream.AuthenticateAsClientAsync( host, certificates, SslProtocols.Tls12, checkCertificateRevocation: false); Logger.Info("SSL认证成功"); return true; } catch (Exception ex) { Logger.Error($"SSL认证失败: {ex.Message}", ex); return false; } } }添加超时机制避免无限等待
给异步认证操作加上超时限制,这样即使卡住也能及时终止并排查原因,用Task.WhenAny实现:var authTask = sslStream.AuthenticateAsClientAsync(host, certificates, SslProtocols.Tls12, false); var timeoutTask = Task.Delay(TimeSpan.FromSeconds(15)); var completedTask = await Task.WhenAny(authTask, timeoutTask); if (completedTask == timeoutTask) { Logger.Error("APNs SSL认证超时,强制关闭连接"); // 主动关闭流,释放资源,避免CLOSE_WAIT堆积 networkStream?.Close(); return false; } // 等待认证完成,若有异常会在此抛出 await authTask;处理CLOSE_WAIT:确保流资源被正确释放
CLOSE_WAIT状态说明连接已收到对方的关闭请求,但你的应用没有主动关闭连接。一定要用using语句包裹TcpClient、NetworkStream和SslStream,确保即使认证失败或超时,资源也能被自动释放,避免连接泄漏。验证证书私钥完整性
虽然Pusher能正常发送,但代码中加载的证书可能缺失私钥。可以在代码中加入检查:foreach (var cert in certificates) { if (!cert.HasPrivateKey) { Logger.Error("加载的证书缺少私钥,请检查Pfx文件是否包含私钥"); return false; } }抓包排查SSL握手细节
如果以上方法都没效果,用Wireshark抓包分析APNs服务器和你的应用之间的SSL握手过程,看是否有握手失败、异常包的情况,这能帮你定位是协议协商问题还是网络层面的拦截。
内容的提问来源于stack exchange,提问作者user6728767

