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

因此,阅读器将阻塞并等待消息完成以对其进行解析和处理。
我的问题是,有时阅读时会跳过某些消息。如果服务器发送msg1msgmsg3,则可能会丢失msg2,但读取msg3不会出现问题。

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

由于它是一个TCP套接字,因此可以保证它们到达的顺序,因此我怀疑ObjectReader是在不引发任何异常的情况下静默丢弃某些内容。

有人知道会发生什么吗?任何想法都欢迎! :)

最佳答案

一个建议:不要做成Reader,只按原样传递InputStream。构建阅读器没有任何好处,而且速度稍慢。不确定这是否对解决问题本身有帮助,但是 jackson 肯定会在必要时阻止阅读。

但是,最有可能发生的事情是,由于底层JsonParser确实进行了缓冲(出于性能原因),因此不会返回缓冲的数据(因为无法将数据“返回”至输入流或读取器)。
JsonParser确实具有访问此类额外缓冲数据的方法,但是解决此问题的最简单方法是显式创建JsonParser(通过JsonFactory),并将其传递给ObjectReader,而不是让ObjectReader创建一个。这样,将使用相同的解析器,并使用其缓冲的数据。由于没有每个解析器的创建开销,这可能还会稍快一些。

另一种替代方法: check out ObjectReader.readValues()(注意其中的-s),它很方便,并且与手动创建和传递解析器的方式几乎相同。

10-02 10:25