Очень странное поведение Дженсона при чтении из потока сокетов - PullRequest
0 голосов
/ 11 декабря 2018

Я пытаюсь установить связь между сервером и клиентом, используя библиотеку 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()), вы получите результат с исключением.

Более того, если я определю единственное поле в классе Tester для типа int[], скажем, оно работает только со значениями nullили new int[0].

В дополнение к этому, если я пытаюсь сериализовать и передать int для целых чисел в диапазоне 0..9 Я наблюдаю следующее поведение: то же самое странное, за исключением того, что когда язавершение работы клиента, сервер всегда показывает значение 0.

Кроме того, для констант типа Double.NaN, Double.POSITIVE_INFINITY, Integer.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));
        }
    }
}

Ответы [ 2 ]

0 голосов
/ 25 декабря 2018

Некоторые пути кода в API чтения будут пытаться с готовностью убедиться, что доступно по крайней мере N байтов или достигнут EOF.Это происходит все время при разборе числа (которое не является константой), как вы заметили.

Можно было бы реализовать небольшой слой, который сериализуется в байтовый массив или строку, получает длину сообщения и записываетэто к выходу, сопровождаемому полезной нагрузкой.На стороне чтения вы сначала читаете длину, а затем читаете из потока в цикле while, пока не достигнете этой длины или EOF.

Затем вы просто перейдете к Genson.deseralize в сообщении памяти.

0 голосов
/ 12 декабря 2018

Похоже, это была моя ошибка все время.Я забыл, что поток сокета не может быть закрыт (если вы не хотите закрывать сокет тоже).Таким образом, в этом случае Server пытается получить столько данных от InputStream, сколько может, но не может использовать весь поток (потому что он всегда открыт и данные могут быть отправлены в любое время с клиента).Таким образом, Server в основном замирает в ожидании данных, но данных больше нет.В результате мы имеем ситуацию, описанную выше.

Решением было бы указать какой-нибудь протокол для обозначения размера запроса, чтобы Server мог знать, сколько данных он должен потреблять.См. этот ответ для более подробной информации.

...