我试图使两个应用程序通过TCP与基于JSON的消息进行通信。为此,我正在使用Jackson库(1.9.4)。客户端只打开一个套接字,然后监听来自服务器的所有传入消息。看起来像这样:
ObjectMapper mapper = new ObjectMapper().configure(
Feature.AUTO_CLOSE_SOURCE, false);
final ObjectReader reader = mapper.reader(Message.class);
Socket s = new Socket("192.168.1.102", 32000);
final Reader in = new InputStreamReader(socket.getInputStream());
while (true) {
Message message = reader.readValue(in);
process(message)
}
因此,阅读器将阻塞并等待消息完成以对其进行解析和处理。
我的问题是,有时阅读时会跳过某些消息。如果服务器发送
msg1
,msg
和msg3
,则可能会丢失msg2
,但读取msg3
不会出现问题。更奇怪的是,这种情况并非一直发生,而是大约50%。客户端和服务器都是单线程的,因此没有其他人可以访问套接字。而且我知道消息到达的事实,因此我尝试使用
nc
模拟客户端,并且传入消息始终正确,因此我知道它是在读取时。由于它是一个TCP套接字,因此可以保证它们到达的顺序,因此我怀疑
ObjectReader
是在不引发任何异常的情况下静默丢弃某些内容。有人知道会发生什么吗?任何想法都欢迎! :)
最佳答案
一个建议:不要做成Reader,只按原样传递InputStream。构建阅读器没有任何好处,而且速度稍慢。不确定这是否对解决问题本身有帮助,但是 jackson 肯定会在必要时阻止阅读。
但是,最有可能发生的事情是,由于底层JsonParser
确实进行了缓冲(出于性能原因),因此不会返回缓冲的数据(因为无法将数据“返回”至输入流或读取器)。JsonParser
确实具有访问此类额外缓冲数据的方法,但是解决此问题的最简单方法是显式创建JsonParser
(通过JsonFactory
),并将其传递给ObjectReader
,而不是让ObjectReader
创建一个。这样,将使用相同的解析器,并使用其缓冲的数据。由于没有每个解析器的创建开销,这可能还会稍快一些。
另一种替代方法: check out ObjectReader.readValues()
(注意其中的-s),它很方便,并且与手动创建和传递解析器的方式几乎相同。