从套接字流读取时 Genson 的行为非常奇怪
Very weird Genson's behaviour while reading from socket stream
我正在尝试使用 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));
}
}
}
我非常感谢对这个问题的任何帮助。提前致谢。
编辑:这真的很奇怪。我做了一些额外的测试,这是我得到的:
额外class:
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())
结果是扩展的。
此外,如果我将 Tester class 中的唯一字段定义为 int[]
类型,可以说,它仅适用于 null
或 new int[0]
的值.
除此之外,如果我尝试为 0..9 范围内的整数序列化和传输 int
,我会观察到以下行为:同样奇怪的事情,除了当我关闭客户端时,服务器始终显示 0
值。
此外,对于像 Double.NaN
、Double.POSITIVE_INFINITY
、Integer.MAX_VALUE
和类似的常量,一点也不奇怪(一切都按预期工作)。
对于那些额外的测试 Genson
class 定义如下:
Genson genson = new GensonBuilder()
.useMethods(false)
.setFieldFilter(VisibilityFilter.PRIVATE)
.create();
注意 ser/deser to/from 文件使用流时没有这样的问题:
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));
}
}
}
看来这一直是我的错误。我忘记了套接字的流无法关闭(除非你也想关闭套接字)。所以在这种情况下 Server
尝试从 InputStream
获取尽可能多的数据,但它不能消耗所有流(因为它始终打开并且可以随时从客户端发送数据).所以 Server
基本上冻结等待数据,但没有更多数据到来。结果,我们遇到了上述情况。
一种解决方案是指定某种协议来表示查询大小,以便 Server
可以知道它应该消耗多少数据。有关详细信息,请参阅 this 答案。
阅读API中的一些代码路径会尝试急切地确保至少有 N 个字节可用或已达到 EOF。如您所述,在解析数字(不是常量)时,这种情况一直发生。
一个选项可以是实现一个小层,该层序列化为字节数组或字符串,获取消息长度并将其写入输出,然后写入有效负载。在读取方面,您将首先读取长度,然后在 while 循环中从流中读取,直到达到该长度或 EOF。
然后您只需将此内存消息传递给 Genson.deseralize。
我正在尝试使用 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));
}
}
}
我非常感谢对这个问题的任何帮助。提前致谢。
编辑:这真的很奇怪。我做了一些额外的测试,这是我得到的:
额外class:
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())
结果是扩展的。
此外,如果我将 Tester class 中的唯一字段定义为 int[]
类型,可以说,它仅适用于 null
或 new int[0]
的值.
除此之外,如果我尝试为 0..9 范围内的整数序列化和传输 int
,我会观察到以下行为:同样奇怪的事情,除了当我关闭客户端时,服务器始终显示 0
值。
此外,对于像 Double.NaN
、Double.POSITIVE_INFINITY
、Integer.MAX_VALUE
和类似的常量,一点也不奇怪(一切都按预期工作)。
对于那些额外的测试 Genson
class 定义如下:
Genson genson = new GensonBuilder()
.useMethods(false)
.setFieldFilter(VisibilityFilter.PRIVATE)
.create();
注意 ser/deser to/from 文件使用流时没有这样的问题:
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));
}
}
}
看来这一直是我的错误。我忘记了套接字的流无法关闭(除非你也想关闭套接字)。所以在这种情况下 Server
尝试从 InputStream
获取尽可能多的数据,但它不能消耗所有流(因为它始终打开并且可以随时从客户端发送数据).所以 Server
基本上冻结等待数据,但没有更多数据到来。结果,我们遇到了上述情况。
一种解决方案是指定某种协议来表示查询大小,以便 Server
可以知道它应该消耗多少数据。有关详细信息,请参阅 this 答案。
阅读API中的一些代码路径会尝试急切地确保至少有 N 个字节可用或已达到 EOF。如您所述,在解析数字(不是常量)时,这种情况一直发生。
一个选项可以是实现一个小层,该层序列化为字节数组或字符串,获取消息长度并将其写入输出,然后写入有效负载。在读取方面,您将首先读取长度,然后在 while 循环中从流中读取,直到达到该长度或 EOF。
然后您只需将此内存消息传递给 Genson.deseralize。