我正在尝试使两个应用程序通过TCP与基于JSON的消息进行通信。为此我正在使用杰克逊图书馆(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
正在默默地丢弃一些东西,而不会抛出任何异常。
有没有人知道可能发生的事情?欢迎任何想法! :)
答案 0 :(得分:1)
一个建议:不要制作一个Reader,只是按原样传递InputStream。构建Reader没有任何好处,而且速度稍慢。不确定这对问题本身是否有帮助,但杰克逊绝对会在必要时阻止读取。
然而,最有可能发生的是,由于底层JsonParser
进行缓冲(出于性能原因),因此不会返回缓冲数据(因为无法将数据“返回”到输入流或读取器)
JsonParser
确实有访问此类额外缓冲数据的方法,但解决此问题的最简单方法是显式创建JsonParser
(通过JsonFactory
),并将其传递给{{ 1}},而不是要求ObjectReader
创建一个。这样就可以使用相同的解析器,并使用它缓冲的数据。这也可能稍微快一点,因为没有每个解析器创建开销。
另一种替代方法:查看ObjectReader
(注意那里的-s),这很方便,其工作方式与手动创建和传递解析器的方式非常相似。
答案 1 :(得分:0)
找到了它。
readValue()
方法只有在对内联Reader
的每次调用读取时都能正常工作,他才能获得完整的JSON消息。
由于我是从套接字读取的,有时候read()
方法返回的内容少于完整的消息而ObjectReader
无法正确处理它。这很奇怪,因为ReaderBasedParser
类在阅读之前有一个while()
,所以它应该只在整个消息出现时返回。
当我有时间的时候会仔细看看。