繁体   English   中英

由于服务器关闭套接字而导致写入失败时,Netty无法从服务器读取字节

[英]Netty failing to read bytes from server when write fails due to socket close by server

网络版本: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实现的协议。

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

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

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

那将遇到刚才提到的管道破裂错误。

此过程在单独的线程中发生。

为什么? NIO和Netty的全部要点是您不需要额外的线程。

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

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

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

就像我说的。

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

正确。

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

由于连接重置。 重置后,挂起数据的传送将停止。

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

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

但是,您的离奇的系统设计/协议使这种情况变得不可预知,即使不是不可能。 您正在写一条错误消息,它将导致重置,然后写出您已经知道不会通过的好消息,并尝试读取可能已被丢弃的响应。 这对我来说毫无意义。 您要在这里证明什么?

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

APN协议似乎很笨拙,因为它没有确认成功接收到通知。 相反,它只会告诉您遇到错误时已成功接收到哪些通知。 该协议假设您通常会发送格式正确的通知。

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

每次生成APN

  • 将其标识符设置为下一个序列号
  • 发送
  • 将其放置在LinkedHashMap中,并将其序列号与当前时间串联在一起(例如,字符串键= sequenceNumber +“-” + System.currentTimeMillis())

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

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

我会捕获任何由写入引起的IOException,并将您尝试写入的APN放置在映射中并重新发送。

您无法解决的是真正的网络错误,由此您不知道APN服务是否收到了通知(或一堆通知)。 您是否要立即或在一段时间后重新发送受影响的APN,就必须根据服务的内容来做出决定。 如果您在一段时间后发送邮件,则需要在发送时给他们新的序列号。 这样,您就可以同时发送新的APN。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM