杰森在杰克逊的插座上

时间:2012-02-13 20:39:25

标签: java json sockets jackson

我正在尝试使两个应用程序通过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)
}

因此,读者会阻止并等待消息完成以解析并处理它。 我的问题是,有时阅读时会跳过一些消息。如果服务器发送msg1msgmsg3,则msg2可能会丢失,但msg3会被正确读取。

为了使它更奇怪,这不会一直发生,但大约50%。客户端和服务器都是单线程的,因此没有其他人可以访问套接字。而且我知道消息到达的事实,我尝试用nc模拟客户端,并且传入的消息总是正确的,所以我知道这是在阅读时。

由于它是一个TCP套接字,它们到达的顺序是有保证的,所以我怀疑ObjectReader正在默默地丢弃一些东西,而不会抛出任何异常。

有没有人知道可能发生的事情?欢迎任何想法! :)

2 个答案:

答案 0 :(得分:1)

一个建议:不要制作一个Reader,只是按原样传递InputStream。构建Reader没有任何好处,而且速度稍慢。不确定这对问题本身是否有帮助,但杰克逊绝对会在必要时阻止读取。

然而,最有可能发生的是,由于底层JsonParser进行缓冲(出于性能原因),因此不会返回缓冲数据(因为无法将数据“返回”到输入流或读取器)

JsonParser确实有访问此类额外缓冲数据的方法,但解决此问题的最简单方法是显式创建JsonParser(通过JsonFactory),并将其传递给{{ 1}},而不是要求ObjectReader创建一个。这样就可以使用相同的解析器,并使用它缓冲的数据。这也可能稍微快一点,因为没有每个解析器创建开销。

另一种替代方法:查看ObjectReader(注意那里的-s),这很方便,其工作方式与手动创建和传递解析器的方式非常相似。

答案 1 :(得分:0)

找到了它。

readValue()方法只有在对内联Reader的每次调用读取时都能正常工作,他才能获得完整的JSON消息。

由于我是从套接字读取的,有时候read()方法返回的内容少于完整的消息而ObjectReader无法正确处理它。这很奇怪,因为ReaderBasedParser类在阅读之前有一个while(),所以它应该只在整个消息出现时返回。

当我有时间的时候会仔细看看。