0

Netty 版本:4.0.10.Final

我已经使用 Netty 编写了一个客户端和服务器。这是客户端和服务器所做的。

服务器:

  1. 等待来自客户端的连接
  2. 接收来自客户端的消息
  3. 如果消息是错误的,则写入错误消息(6 个字节),刷新它,关闭套接字并且不要读取套接字中的任何未读消息。否则继续阅读消息。对好消息什么都不做。

客户:

  1. 连接到服务器。
  2. 写完 N 条好消息后,写一条坏消息,然后继续写 M 条好消息。这个过程发生在一个单独的线程中。该线程在通道处于活动状态后启动。
  3. 如果服务器有任何响应,请记录并关闭套接字。(请注意,服务器仅在出现错误时才响应)

我已经跟踪了客户端和服务器。我发现服务器在写入错误消息后正在关闭连接。在坏消息之后写好消息时,客户端开始看到损坏的管道错误。这是因为服务器检测到错误消息并以错误消息和关闭套接字进行响应。只有在使用侦听器完成写入操作后才会关闭连接。客户端不总是从服务器读取错误消息。客户端中较早的步骤 (2) 在 I/O 线程中执行。这导致在 K 次实验中收到的错误消息的百分比非常低(<10%)。将步骤 (2) 移至分离线程后,% 变为 (70%)。无论如何,它是不准确的。如果由于管道损坏而导致写入失败,netty 是否会触发通道读取?

更新 1:我正在澄清和回答这里提出的任何问题,所以每个人都可以在一个地方找到提出的问题/澄清。“你正在写一条会导致重置的坏消息,然后是你已经知道不会通过的好消息,并试图阅读可能已被丢弃的回复。这对我来说没有任何意义无论如何”——来自 EJP

-- 在现实世界中,服务器可能会因为客户端无法提前知道的任何原因而将某些事情视为坏事。为简单起见,我说客户端故意发送导致服务器重置的错误消息。即使总消息中有坏消息,我也想发送所有好的消息。

我正在做的类似于Apple Push Notification Service实现的协议。

4

2 回答 2

1

如果消息是错误的,则写入错误消息(6 个字节),刷新它,关闭套接字并且不要读取套接字中的任何未读消息。否则继续阅读消息。

这将导致连接重置,客户端将在 Unix、Linux 等中将其视为损坏的管道。

写完 N 条好消息后,写一条坏消息,然后继续写 M 条好消息。

那会遇到刚才提到的断管错误。

这个过程发生在一个单独的线程中。

为什么?NIO 以及 Netty 的全部意义在于您不需要额外的线程。

我发现服务器在写入错误消息后正在关闭连接。

嗯,这就是你所说的,所以它做到了。

在坏消息之后写好消息时,客户端开始看到损坏的管道错误。

就像我说的。

这是因为服务器检测到错误消息并以错误消息和关闭套接字进行响应。

正确的。

客户端不总是从服务器读取错误消息。

由于连接重置。复位后停止传送未决数据。

如果由于管道损坏而导致写入失败,netty 是否会触发通道读取?

不,它在数据或 EOS 到达时触发读取

但是,您奇怪的系统设计/协议使这种情况变得不可预测,如果不是不可能的话。您正在编写会导致重置的错误消息,然后是您已经知道无法通过的好消息,并尝试读取可能已被丢弃的响应。这对我来说没有任何意义。你想在这里证明什么?

像其他人一样尝试请求-响应协议。

于 2013-10-14T23:12:37.903 回答
0

APN 协议似乎很尴尬,因为它不承认成功收到通知。相反,它只是告诉您在遇到错误时它已成功接收到哪些通知。该协议假设您通常会发送格式良好的通知。

我建议您需要某种过期缓存(LinkedHashMap 可能在这里工作),并且您需要将通知中的不透明标识符字段用作全局唯一的有序值。序列号将起作用(但如果您的客户端可以重新启动,您需要保留)。

每次生成 APN

  • 将其标识符设置为下一个序列号
  • 发送
  • 将它放在 LinkedHashMap 中,将序列号的字符串键与当前时间连接起来(例如 String key = sequenceNumber + "-" + System.currentTimeMillis() )

如果您收到错误,您需要重新打开连接并重新发送映射中的所有 APN,其序列号高于错误中报告的标识符。这相对容易。只需遍历地图,删除任何序列号低于报告的 APN。然后按顺序重新发送剩余的APN,将它们在地图中替换为当前时间(即您在重新发送时删除了一个APN,然后使用新的当前时间重新插入到地图中)。

您需要定期清除旧条目的映射。如果您发送格式错误的 APN,您需要根据 APN 服务返回错误所需的时间来确定合理的时间长度。我怀疑这将是几秒钟的事情(如果不是更快的话)。例如,如果您每秒发送 10 个 APN,并且您知道 APN 服务器肯定会在 30 秒内响应,那么 30 秒的到期时间(每秒清除一次)可能是合适的。只需沿地图迭代,删除其键的时间部分小于 System.currentTimeMillis() - 30000(30 秒到期时间)的任何元素。您需要适当地同步线程。

我会捕获由写入引起的任何 IOExceptions,并将您尝试写入的 APN 放在地图中并重新发送。

您无法应对的是真正的网络错误,您不知道 APN 服务是否收到了通知(或一堆通知)。您必须根据您的服务来决定是立即重新发送受影响的 APN,还是在一段时间后重新发送,或者根本不重新发送。如果您在一段时间后发送,您将希望在发送时给他们新的序列号。这将允许您同时发送新的 APN。

于 2013-10-16T17:38:52.660 回答