我正在尝试让两个应用程序通过 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 即可。构建Reader没有任何好处,而且速度稍微慢一些。不确定这是否有助于解决问题本身,但 jackson 肯定会在必要时阻止读取。
但是,最有可能发生的情况是,由于底层 JsonParser
会进行缓冲(出于性能原因),因此不会返回缓冲的数据(因为无法将数据“返回”到输入流或读取器)。
JsonParser
确实有方法来访问此类额外的缓冲数据,但解决此问题的最简单方法是显式创建 JsonParser
(通过 JsonFactory
),并将其传递给 ObjectReader
,而不是要求 ObjectReader
创建一个。这样,将使用相同的解析器,并使用它缓冲的数据。这也可能会稍微快一些,因为没有每个解析器的创建开销。
还有一种替代方法:查看 ObjectReader.readValues()
(请注意其中的 -s),这很方便,并且与手动创建和传递解析器的方式几乎相同。
关于java - 与 Jackson 通过 Socket 进行 Json,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9267669/