发送大量数据时,“连接被远程主机强制关闭”

4

我在一个C#多线程Windows服务中发送推送通知时遇到了一些问题。
当我向APNS发送大量通知时,一些线程会抛出异常:

Unable to write data to the transport connection: An existing connection was forcibly closed by the remote host.
   at System.Net.Sockets.NetworkStream.Write(Byte[] buffer, Int32 offset, Int32 size)
   at System.Net.Security._SslStream.StartWriting(Byte[] buffer, Int32 offset, Int32 count, AsyncProtocolRequest asyncRequest)
   at System.Net.Security._SslStream.ProcessWrite(Byte[] buffer, Int32 offset, Int32 count, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslStream.Write(Byte[] buffer) ...

我有一个线程池,其中包含16个线程,每个线程都会打开一个到Apple的连接。 不是超时问题,因为我已经尝试使用sslStream.WriteTimeout = 60000; 我还尝试了这个:Client.SetSocketOption(SocketOptionLevel.Socket,SocketOptionName.KeepAlive, false); 发送开始时连接未关闭。 编辑:我认为所有数据都已发送,但Apple突然关闭了连接。
你有想法关于这个异常出现的原因吗? 该如何解决?
如果需要,我可以提供一些代码。
非常感谢您的回答!
5个回答

4

异常 "An existing connection was forcibly closed by the remote host" 通常意味着您连接的另一个主机决定不再与您通信。为此,它发送带有RST设置的FIN来关闭其端口的连接。

由于在发送大量通知时会发生这种情况,所以可能服务正在故意限制您以防止过载。


我认为这不是限流问题,因为苹果通知服务管理着大量的通知。而且并非每个线程都会出现这种情况,即使其他线程发送相同数量的通知也不会发生。 - Michaël
1
好的,如果不是因为流量控制,那就是其他原因了。无论什么原因,APNS决定不想再与您交谈了。APNS正在关闭连接,当您的程序尝试使用不再打开的连接时,您的程序会遇到异常。 - Frank Boyne
如果线程抛出异常,写操作就没有完成,是吗? - Michaël
当然,传递到写操作中的数据尚未被传送。之前发送的写操作中的数据也有可能尚未被传送。我们无法确定,因为我们不知道APNS何时发送RESET,也不知道它选择在发送RESET之前读取了多少数据(如果有的话)。 - Frank Boyne
所以,没有办法知道有多少字节已经被发送。 - Michaël
仅使用套接字API是没有解决方案的。如果APNS发送了某种确认,那么您就知道它接收了任何字节,但否则,即使写入成功,您也不知道字节是否传递。 - Frank Boyne

1

从APNS-Sharp中我看到用户在传入错误的设备令牌时会看到此错误- http://code.google.com/p/apns-sharp/issues/detail?id=35

如果这不是答案,那么您能否确认当您打开较少的线程时,您的代码是否无法工作?或者当您发送较小数量的数据时它是否可以工作?

顺便说一下,同时打开16个连接真的有必要吗?这似乎相当高。


谢谢,但我已经阅读了这篇文章。他的问题是通过使用更高的超时时间来解决的。我已经编写了自己的实现方式,用于发送大量通知(每个消息500k)。因此,我打开了16个连接(ax 20)。在发送之前,会删除错误的设备令牌,并使用反馈服务禁用令牌。 - Michaël

1

这与推送通知无关,但我最近在一个多线程应用程序中遇到了这个问题,因为我有一个套接字在两个线程之间共享(一个用于发送数据,一个用于接收)。当接收线程在socket.ReceiveFrom()中阻塞时,发送线程正在尝试在同一套接字上发送数据。这导致我的应用程序出现“远程主机强制关闭连接”的错误。这可能是您需要考虑的问题。

最终,我通过添加一些WaitHandles来使套接字连接线程安全来解决了我的问题。


但是我在发送后不读取响应,只是在write之后关闭连接。我使用线程池,并在每个线程中声明一个ssl流,因此我认为套接字不是共享的。 - Michaël

1

可能你打开了太多的连接,而苹果服务器由于某种原因关闭了它们。尝试减少连接数量,看看问题是否仍然存在。


苹果允许20个连接。为了防止过多的连接问题,我已将其限制为16个。有没有办法知道同时打开了多少个连接? - Michaël

0

没有解决方案,但我认为这是苹果关闭连接以便重用套接字,当不再发送数据时。

为了避免错误,我现在使用增强通知。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接