Программирование сокетов Java - PullRequest
1 голос
/ 05 февраля 2009

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

Я пытаюсь создать многопользовательскую версию PacMan.

Простой обзор того, как я сделал свое приложение, состоит в том, что у меня есть сервер с ServerSocket, который постоянно прослушивает определенный порт. Как только клиент подключается, он создает поток, в котором происходит вся передача данных. Сначала он прослушивает направление, в котором клиент хочет переместиться, а затем отправляет обновления обратно клиенту. На клиентской стороне происходит обратная отправка направления, а затем ожидание получения обновления. Это делается с помощью ObjectOutput / Input Streams. Существует также игровой класс, который имеет всю игровую логику, и в нем есть игровой цикл, каждый цикл которого вызывает каждый из подключенных игроков метод serverThread.exchangeDatas ().

Моя игра работает нормально с одним подключенным клиентом, но как только другой клиент присоединяется (локально - это все, что я тестировал, но это должно работать правильно?). Моя игра вылетела в потоке сервера, выдав следующую ошибку java.io.StreamCorruptedException: недопустимый код типа: 00.

Код, который отключает это исключение

        Object o = in.readObject();
        if (o instanceof Direction)
        {
            // Get new location
            player.setDirection((Direction) o);
        //System.out.println("Got: " + (Direction)o + " new location: " + player.getNextLocation());
        }

        // Send gameState

        //System.out.println("Sending data");
        Data data = new Data(game.getGameState(), game.getScared(), game.getScareLeft(), player.getLives(), player.getScore());
        out.flush();
        out.writeObject(data);
        out.flush();
        out.reset();

Код сервера

Код ServerThread (тот, который падает в методе exchangeData

Код клиентского контроллера

Код игрового цикла - строка 42 - это то, что вызывает метод обмена данными

Любая помощь была бы удивительной с этими.

http://www.mediafire.com/download.php?nwwqmzywfom

вот загрузка как для клиента, так и для сервера (это проекты NetBeans)

Извините за мой грязный код = [

Ответы [ 4 ]

2 голосов
/ 05 февраля 2009

Это сложно отладить без остальной части кода, поэтому я собираюсь опубликовать свой первый и немного поэкспериментировать. Почему вы вызываете .reset () в своих потоках? Это переместит позицию чтения в потоке обратно в начало, а это не то, что вы хотите, я бы подумал (никогда не использовал ObjectInputStream).


ОК, я взял ваш код и взломал некоторые мелочи, чтобы он скомпилировался, и он работал для меня с помощью .reset (). Похоже, то, что вы делали, правильно.

Не думаю, что смогу помочь больше без остального кода. К сожалению.

PS: Я предполагаю, что у вас есть вещи Serializable, реализующие Runnable и т. Д., Которых у кода, который вы опубликовали, не было. Но если бы вы не настроили эти вещи, то ваш код не скомпилировался бы в первую очередь.


После 45 минут работы с вашим кодом, я не могу допустить ошибку. Мне пришлось взломать несколько вещей здесь и там, чтобы заставить его работать (так как в нем отсутствовал один или два класса и часть кода выше), но я не думаю, что изменил это (сильно). Я не уверен, что мои изменения повлияют на что-либо, это немного сложно понять.

У меня есть два предположения о том, что происходит. Первым снова будет объект .reset (). Если вы не прокомментировали это и посмотрите, имеет ли это какое-то значение.

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

java.io.StreamCorruptedException: invalid type code: 00

Я собираюсь догадаться, что 00 может быть подсказкой. Насколько я понимаю, должен быть отправлен байт сигнатуры (как доказательство того, что объект - это то, что вы говорите, поэтому строки не интерпретируются как double или PacManGameUIs), и, очевидно, Java недоволен, потому что это неправильно.

Но почему 00? Это интересная ценность. Мое предположение (и это большое предположение) состоит в том, что это первый байт целого числа (то есть 4 байта при отправке с ObjectOutputStream.writeInt ()). Возможно, вам отправляется целое число, которое не читается до вызова .readObject во входном потоке? Я не уверен, что это может привести к ошибке, но это было бы моим лучшим предположением.

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

Другой способ (и это будет более поучительно, если вы осмелитесь) - прослушать разговор между двумя половинками программы, используя что-то вроде WireShark или tcpdump . Это позволит вам увидеть необработанные байты, через которые вы отправляете. Хотя это может быть запутанным и трудным для интерпретации, оно должно помочь понять, отправляете ли вы неправильный объект легко. Отправка int, вероятно, займет около 4 байтов, но отправка большой структуры потребует больше. Экспериментируя, вы сможете понять это. Это боль, но она даст вам знать точно что отправляется.

Может быть трудно отследить интерфейс обратной связи (когда компьютер общается с самим собой), по крайней мере, в Windows с WireShark (я не помню, чтобы это было так просто), поэтому часто проще всего сделать это с двумя компьютеры (один как сервер, один как клиент), так что вы можете легко заглядывать в пакеты.

Снова извините, что не могу быть более полезным.

1 голос
/ 05 февраля 2009

Возможно, немного не по теме, но javagaming.org имеет раздел «Разработка и сетевые игры для OnLine». Возможно, вы захотите это проверить.

1 голос
/ 05 февраля 2009

Многопоточность требует синхронизации. Используете ли вы синхронизированный поток (или синхронизируете доступ к потоку самостоятельно)?

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

Предлагаю взглянуть на http://java.sun.com/docs/books/tutorial/essential/concurrency/sync.html.

Помечая метод / класс синхронизированным, среда выполнения гарантирует, что этот метод / класс будет активен не более чем в 1 потоке одновременно. На самом деле это обширная и сложная тема, поэтому потратьте некоторое время на изучение основ и убедитесь, что вы понимаете основную проблему. :)

0 голосов
/ 06 февраля 2009

Могу ли я просто спросить, что вы ожидаете, если бы второй клиент мог присоединиться? Вы не сохраняете ссылку на объект Thread, когда происходит другая итерация, у объекта больше нет ссылки, поэтому JRE уничтожит объект, не так ли?

while (true)
{
    System.out.println("Waiting for conneciton on port " + port);
    Socket client = listener.accept();
    System.out.println("Accepted a connection from: " + client.getInetAddress());
    Thread t = new Thread(new PacManServerThread(client, game));
    t.start();
}

Конечно, вам нужно сделать что-то вроде

myGenericArray.add(t);

в конце вашего цикла, иначе, как только объект потеряет область видимости в цикле, он будет уничтожен?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...