1

我正在尝试使用 Genson 库在服务器和客户端之间进行通信。我检测到以下问题:尝试向服务器发送消息时,当服务器上的 genson 尝试读取消息时,我的应用程序停止。

同时,如果我关闭客户端,消息将被完美读取和处理。我认为这是僵局,但不确定。

原生 Java 序列化不存在这样的问题。

这是我的服务器:

import com.owlike.genson.Genson;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Arrays;

public class Server {
    public static void main(String[] args) throws IOException {
        Genson genson = new Genson();

        try (ServerSocket server = new ServerSocket(9991)) {
            try (Socket socket = server.accept()) {
                int[] loc = genson.deserialize(socket.getInputStream(), int[].class);
                System.out.println("Server: " + Arrays.toString(loc));
                genson.serialize(loc, socket.getOutputStream());
            }
        }
    }
}

这是客户端:

import com.owlike.genson.Genson;

import java.io.IOException;
import java.net.Socket;
import java.util.Arrays;

public class Client {
    public static void main(String[] args) throws IOException {
        Genson genson = new Genson();

        try (Socket socket = new Socket("localhost", 9991)) {
            genson.serialize(new int[] {1, 2, 3}, socket.getOutputStream());
            int[] loc = genson.deserialize(socket.getInputStream(), int[].class);
            System.out.println("Client: " + Arrays.toString(loc));
        }
    }
}

我非常感谢对这个问题的任何帮助。提前致谢。


编辑:这真的很奇怪。我做了一些额外的测试,这就是我得到的:

附加类:

import com.owlike.genson.annotation.JsonProperty;

import java.io.Serializable;

public class Tester implements Serializable {
    public static final Tester TEST = new Tester(Math.E);

    private double val = Math.PI;

    public Tester(@JsonProperty("val") double val) {
        this.val = val;
    }

    public Tester() {}

    public String toString() {
        return "" + val;
    }
}

genson.serialize(Tester.TEST, socket.getOutputStream())在客户端请求中后,我得到了同样奇怪的结果。但是写完genson.serialize(new Tester(Double.NaN), socket.getOutputStream())结果是expexted的。

此外,如果我将 Tester 类中的唯一字段定义为 type int[],可以说,它仅适用于nullor的值new int[0]

除此之外,如果我尝试序列化和传输int0..9 范围内的整数,我观察到以下行为:同样奇怪的事情,除了当我关闭客户端时,服务器总是显示0值。

Double.NaN此外,对于像,和类似的常量Double.POSITIVE_INFINITYInteger.MAX_VALUE一点也不奇怪(一切都按预期工作)。

对于那些额外的测试Genson类定义如下:

Genson genson = new GensonBuilder()
        .useMethods(false)
        .setFieldFilter(VisibilityFilter.PRIVATE)
        .create();

请注意,当 ser/deser 使用流向/从文件传输时没有这样的问题:

import com.owlike.genson.Genson;
import com.owlike.genson.GensonBuilder;
import com.owlike.genson.reflect.VisibilityFilter;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class FileTest {
    private static final String FILENAME = "test.json";

    public static void main(String[] args) throws IOException {
        Genson genson = new GensonBuilder()
                .useMethods(false)
                .setFieldFilter(VisibilityFilter.PRIVATE)
                .useIndentation(true)
                .create();

        try (OutputStream stream = new FileOutputStream(FILENAME)) {
            genson.serialize(Tester.TEST, stream);
        }

        try (InputStream stream = new FileInputStream(FILENAME)) {
            System.out.println(genson.deserialize(stream, Tester.class));
        }
    }
}
4

2 回答 2

1

看来这一直是我的错误。我忘记了套接字的流不能关闭(除非你也想关闭套接字)。因此,在这种情况下Server,尝试从尽可能多的数据中获取数据,InputStream但它不能消耗所有流(因为它始终处于打开状态,并且可以随时从客户端发送数据)。所以Server基本上冻结等待数据,但没有更多的数据来。结果,我们遇到了上述情况。

一种解决方案是指定某种协议来表示查询大小,以便Server知道它应该消耗多少数据。有关更多详细信息,请参阅答案。

于 2018-12-11T21:14:47.270 回答
0

读取 API 中的一些代码路径将尝试急切地确保至少有 N 个字节可用或已达到 EOF。正如您所指出的,在解析数字(不是常数)时,这种情况总是会发生。

一个选项可能是实现一个小层,该层序列化为字节数组或字符串,获取消息长度并将其写入输出,然后是有效负载。在读取方面,您将首先读取长度,然后在 while 循环中从流中读取,直到达到该长度或 EOF。

然后你只需传递给 Genson.deseralize 这个内存消息。

于 2018-12-25T03:34:48.293 回答