Апплет Slick2D KryoNet

Я использую Kryonet с Slick2d для создания java-игры.

Он отлично работает при запуске в качестве приложения Java, однако при запуске в качестве апплета я получаю следующую ошибку:

00:00  INFO: [kryonet] Server opened.
00:04 DEBUG: [kryonet] Port 9991/TCP connected to: /(ip):55801
00:04 DEBUG: [kryo] Write: RegisterTCP
00:04  INFO: [kryonet] Connection 1 connected: /(ip)
00:04  INFO: [SERVER] Someone has connected.
00:04 ERROR: [kryonet] Error reading TCP from connection: Connection 1
com.esotericsoftware.kryonet.KryoNetException: Error during deserialization.
    at com.esotericsoftware.kryonet.TcpConnection.readObject(TcpConnection.java:141)

    at com.esotericsoftware.kryonet.Server.update(Server.java:192)
    at com.esotericsoftware.kryonet.Server.run(Server.java:350)
    at java.lang.Thread.run(Unknown Source)
Caused by: com.esotericsoftware.kryo.KryoException: Buffer underflow.
    at com.esotericsoftware.kryo.io.Input.require(Input.java:162)
    at com.esotericsoftware.kryo.io.Input.readLong(Input.java:621)
    at com.esotericsoftware.kryo.io.Input.readDouble(Input.java:745)
    at com.esotericsoftware.kryo.serializers.DefaultSerializers$DoubleSerializer.read(DefaultSerializers.java:141)
    at com.esotericsoftware.kryo.serializers.DefaultSerializers$DoubleSerializer.read(DefaultSerializers.java:131)
    at com.esotericsoftware.kryo.Kryo.readClassAndObject(Kryo.java:735)
    at com.esotericsoftware.kryonet.KryoSerialization.read(KryoSerialization.java:57)
    at com.esotericsoftware.kryonet.TcpConnection.readObject(TcpConnection.java:139)
    ... 3 more
00:04  INFO: [SERVER] Someone has disconnected.
00:04  INFO: [kryonet] Connection 1 disconnected.

Сервер работает локально как исполняемый jar-файл, а клиентский апплет также локально в HTML-файле, который запускает xampp для работы в качестве веб-сервера.

Я пробовал разные сериализаторы, размеры буфера и отправлял только одиночные строки/логические значения и т. д., мне просто ничего не нравится. Клиент прекрасно подключается к серверу, однако, когда дело доходит до отправки любых пакетов, я получаю указанную выше ошибку, независимо от того, какой пакет отправляется.

Любая помощь/совет будет очень признательна - я некоторое время был в тупике! Спасибо


person sro    schedule 27.02.2013    source источник


Ответы (2)


Я считаю, что у меня такая же проблема или, по крайней мере, похожая. Я использую Kryonet для сервера и клиента. Клиент представляет собой апплет, и когда я запускаю его через средство просмотра апплетов Eclipse, он работает нормально. Когда я запускаю его через веб-сервер, я получаю аналогичные ошибки. Клиент и сервер соединяются, сервер получает пакеты клиента, но клиент выдает ошибку при любой попытке десериализации. Я обнаружил, что виноваты разрешения апплета. Если вы измените разрешения средства просмотра апплетов (если вы используете Eclipse), чтобы они были такими же, как у веб-страницы, вы получите те же ошибки. Преимущество в том, что вы можете отладить проблему.

Чтобы изменить разрешения для Eclipse: Перейдите в папку проекта \bin\ и откройте "java.policy.applet". Внутри у вас должно быть:

grant {
  permission java.security.AllPermission;
};

Измените это на:

grant {
    permission java.io.FilePermission "<<ALL FILES>>", "read, write, execute, delete";  
    permission java.net.SocketPermission "*", "accept, connect, listen, resolve";  
    permission java.util.PropertyPermission "*", "read, write";  
    permission java.lang.RuntimePermission "*";  
    permission java.awt.AWTPermission "showWindowWithoutWarningBanner";  
};

С этим изменением у меня было то же поведение для Applet Viewer, что и со встроенным апплетом. Это не полное решение, но может помочь найти причину проблемы.

Обновление: я нашел, в чем проблема в моем случае. Проблема в FieldSerializer и других сериализаторах, использующих его. Когда класс зарегистрирован, FieldSerializer просматривает его поля и делает их доступными. Эта операция не разрешена для апплета. Результат - неправильная регистрация и сериализация/десериализация. Я нашел 2 обходных пути:

1) Использование другого сериализатора. По умолчанию используется FieldSerializer, и его можно изменить с помощью

public void setDefaultSerializer (Class<? extends Serializer> serializer)

другой вариант — установить сериализатор при регистрации каждого класса. Не используйте сериализаторы на основе FieldSerializer.

2) Попробуйте исправить FieldSerializer. То, что я делаю, не совсем правильно, но в моем случае это работает. Мы заставим FieldSerializer продолжить регистрацию, если настройка доступности вызывает исключение. Еще одна вещь, которую нам нужно сделать, это сделать все поля классов, которые мы регистрируем, общедоступными. Чтобы изменить FieldSerializer, вам нужны исходники Kryo. Перейдите к FieldSerializer.java, выполните процедуру перестроенияCachedFields(). Там вы найдете следующий код:

    if (!field.isAccessible()) {
        if (!setFieldsAsAccessible) continue;
        try {
            field.setAccessible(true);
        } catch (AccessControlException ex) {
            continue;
        }
    }

Вам нужно изменить это на:

    if (!field.isAccessible()) {
        if (setFieldsAsAccessible)
        try {
            field.setAccessible(true);
        } catch (AccessControlException ex) {
        }
    }

Еще одна вещь, которую необходимо изменить, это то, что все зарегистрированные классы имеют только общедоступные поля.

person Ivo Bonev    schedule 08.03.2013

У меня похожая проблема в сборке gradle. Возможно, вам нужно просто увеличить память (кучу или PermSize) для апплета JVM.

person Pavel Bernshtam    schedule 07.03.2013