使用 App Engine 受信任的测试器套接字连接到 APNS。写入套接字工作正常。
但问题是 Socket 在 2 分钟不活动后被回收。它在 Trusted Tester 网站上说,任何套接字操作都会使套接字继续存活 2 分钟。在 APNS 决定关闭连接之前保持套接字打开会更好。
在尝试了几乎所有没有写入输出流的 Socket API 方法之后,无论如何 2 分钟后 Socket 都会关闭。我错过了什么?
部署在java后端。
使用 App Engine 受信任的测试器套接字连接到 APNS。写入套接字工作正常。
但问题是 Socket 在 2 分钟不活动后被回收。它在 Trusted Tester 网站上说,任何套接字操作都会使套接字继续存活 2 分钟。在 APNS 决定关闭连接之前保持套接字打开会更好。
在尝试了几乎所有没有写入输出流的 Socket API 方法之后,无论如何 2 分钟后 Socket 都会关闭。我错过了什么?
部署在java后端。
您不能人为地打开连接到 APNS 的套接字;无需发送实际的推送通知。保持它打开的唯一方法是发送一些任意数据/字节,但这会导致套接字立即关闭;一旦检测到不符合协议的内容,即不是实际推送通知的内容,APNS 就会立即关闭连接。
SO_KEEPALIVE
怎么样SO_KEEPALIVE
?App Engine 明确表示支持。我认为这只是意味着它不会在您调用时抛出异常Socket.setKeepAlive(true)
;调用想要设置套接字选项之前引发了未实现的异常。即使您启用 keep-alive,如果您超过 2 分钟不发送任何内容,您的套接字也会被回收(关闭);至少到目前为止在 App Engine 上。
其实,这并不是什么大惊喜。指定 TCP Keep Alive 的RFC1122明确指出 TCP Keep Alive 不能每两个小时发送一次以上,然后,只有在没有其他流量时才需要。虽然它还说这个间隔也必须是可配置的,但没有 APIjava.net.Socket
可以用来配置它(很可能是因为它高度依赖于操作系统),我怀疑它会在 App Engine 上设置为 2 分钟。
SO_TIMEOUT
怎么样SO_TIMEOUT
?这是为了完全不同的东西。状态的javadoc Socket.setSoTimeout()
:
使用指定的超时启用/禁用 SO_TIMEOUT,以毫秒为单位。将此选项设置为非零超时,对与此 Socket 关联的 InputStream 的 read() 调用将仅阻塞此时间量。如果超时到期,则会引发 java.net.SocketTimeoutException,尽管 Socket 仍然有效。必须在进入阻塞操作之前启用该选项才能生效。超时必须 > 0。超时为零被解释为无限超时。
也就是说,当read()
因为没有什么可阅读的内容而阻塞太久时,您可以说“好的,我不想再等待(阻塞);让我们做点别的吧”。这对我们的“2 分钟”问题没有帮助。
What then?
解决此问题的唯一方法是:检测连接何时被回收/关闭,然后将其丢弃并打开一个新连接。并且有一个完全支持该功能的库。
退房java-apns-gae
。
它是一个开源 Java APNS 库,专为在 Google App Engine 上工作(和使用)而设计。
您是否尝试过 getSoLinger()?这可能是当前(某种)有效的 getSocketOpt,它可能会重置 2 分钟超时。从理论上讲,也可以进行零字节读取,但我不确定如果您尝试这样做,是否会在输入流上使用此方法。
公共 int 读取(字节 b [],int 关闭,int len)
如果这些建议不起作用,请向 App Engine 问题跟踪器提出问题。
将会有一些其他的修复,例如使用套接字选项等。
使用getpeername()
.
来自https://developers.google.com/appengine/docs/java/sockets/overview ...
套接字可以在 2 分钟不活动后回收;任何套接字操作(例如 getpeername)使套接字再保持活动 2 分钟。(请注意,您不能在多个可用套接字之间进行选择,因为这需要当前不支持的 java.nio.SocketChannel。)