Создание своего Java Socket Server. Теория. Из ActionScript3 в Java.

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

Я флеш-программист, и мой опыт работы с явой исчисляется где-то месяцем. Эта статья типа «написание Java Socket сервера глазами флеш-программиста».

Предыстория.

До того, как мы написали свой сервер в нашем проекте Doom Forge Game мы использовали готовое решение для мультиплеерных игр — Smart Fox Server. Сервер сделан хорошо, в нем много возможностей, но нам пришлось столкнуться с некоторыми проблемами в его работе, которые решались тяжелым общением с безинициативной службой поддержки и решение проблемы могло занимать не меньше месяца (если проблема вообще решалась). Так что опыт использования Smart Fox Server у меня был печальный.

Из ActionScript3 в Java

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

Отличие 1. Переменные. Java — сначала тип, потом имя.

AS3:

var str:String = “Hello”;

Java:

String str =  “Hello”;

Отличие 2. В Java есть перегрузка методов, а во флеше нет.

В Java можно сделать так (и это круто):

<br />
public class MyClass{<br />
	public void find(int id){…};<br />
	public void find(String name){…};<br />
}<br />

В AS3 приходится делать приблизительно так:

<br />
public class MyClass{<br />
	public function findById(int id):void{…};<br />
	public function findByName(String name):void{…};<br />
}<br />

Отличие 3. В Java нельзя сделать ссылку на функцию, а в AS3 можно.

В AS3 мы пишем так (и это круто):

<br />
public function connect():void{<br />
	target.addEventListener(Event.CONNECT, handleConnect)<br />
}<br />
public function handleConnect(event:Event):void {<br />
	…<br />
}<br />

В java приходится для каждого слушателя создавать отдельный класс:

<br />
IRequestHandler handler = new Handler();<br />
addRequestHandler(Request.PUBLIC_MESSAGE, handler);<br />

А dispatcher, зная интерфейс хенжлера, знает какую функцию нужно вызвать и что в неё передать:

<br />
public interface IRequestHandler {<br />
	void handleRequest(String command, Object data, Session session);<br />
}<br />

Отличие 4. В Java можно указать какое исключение может сгенерировать метод:

void handleRequest(String command, Object data, Session session) throws Exception;

И нам прийдется обязательно обработать это исключение. И это круто. В AS3 мыможем либо прочитать документацию/asdoc либо только догадываться о наличии исключения.

Отличие 5. Многопоточность.

Конечно, вписывать это отличие в один ряд с предыдущими отличиями равносильно списку дел

«1) подписать контракт слияния компаний. 2) купить корм для рыбок».

На самом деле, это Огромное отличие. Суть его очень проста. Это выполнение кода в несколько параллельных потоков. Представьте, дорогие флешеры, что у вас в памяти не одна несколько запущенных флешек, только отисовуют они одну флешку и память у них общая. Т.е. в тот момент, пока в одном потоке вы перебираете список соперников, другой поток в это время добавляет или удаляет что-то из этого списка.

Если ещё проще – это как несколько людей в одной комнате(где люди это потоки, а предметы — это данные): пока Лена считает яблоки на столе, Ира в это время съедает парочку, и к моменту когда Лена досчитает яблоки, полученное значение не будет соответствовать реальности. Есть масса методов избежать проблем в подобных ситуациях — запретить Ире есть яблоки, пока они считаются; сделать так, чтобы яблоки, которые считает Лена и яблоки, которые есть Ира – это были разные яблоки и так далее. Также это может поразить кучу других проблем, к примеру deadlock: Ира ждет пока Лена досчитает яблоки, а Лена ждет пока Ира наестся в конце-то концов — и получается, что они блокируют друг-друга и никто ничего не делают. Но это очень обширная тема и её нужно изучать отдельно.

Начнем.

Итак, нам нужно сделать socket-сервер для чата. Первым делом я начал искать в просторах интернета и натолкнулся на ряд старей:

http://www.broculos.net/en/article/how-make-multi-client-flash-java-server

http://habrahabr.ru/blogs/java/69136/

— Супер! Как все просто! Это то что нужно, — подумал я и внедрил это в жизнь. Вроде все предельно просто. Эти статьи полезно изучить для того чтобы знать основы. Делаем. Все работает, работает отлично… до тех пор пока вы живете в мире без ошибок сети, без зла и насилия, и у вас только 2 подключенных пользователея. Как я понял позже, это пример сфирического коня в вакууме…

Что взять в дорогу. Мой выбор библиотек.

NIO

Первое, что я понял для себя — не стоит напрямую работать с сокетами. Если использовать готовое решение для работы с сокетами можно избежать кучи проблем с многопоточностью, deadlock, избавит от необходимости писать уже давно написанные вещи. Я выбрал Netty по рекомендации одного хорошего java-программиста, но не берусь утверждать, что это самый лучший вариант.

Логирование

Для логирования я использовал готовое и распространенное решение  - loj4g.

База данных

Работа с базой данных является тривиальной задачей для явы. Хотелось бы лишь посоветовать использовать пул соединений. Я использовал DBCP.

Протокол

Для простоты будем использовать JSON формат.

Статистика сервера

RRD4j — это простая библиотека для работы с rrd-базой.

Суть работы с сокетами — элементарное объяснение (вдруг кто не знает).

Итак, что такое сокеты. Я думаю, тут можно применить метафору телефонных разговоров. Клиент «звонит» по номеру (ip) серверу. Между ними устанавливается связь и они могут обмениваться информацией. Но все что они могут передавать друг-другу это звук (В случае компьютера — текст, а точнее нолики и единички). По «телефону» может говорить как клиент так и сервер и каждый будет слышать другого. Если кто-то положит трубку или связь оборвется где-то на линии — столько не кричи — твой собеседник тебя не услышит. Сокеты работают точно также.

В чем отличие от http-протокола? На самом деле, когда вы открываете веб-страницу ваш браузер создает сокет-соединение и посылает серверу команду «дай мне такую-то страницу» (Делает он это в http формате). Сервер в ответ посылает текст страницы и по окончании закрывает соединение («кладет трубку»). Что увидеть это воочию можно открыть telnet, подсоединиться к любому сайту и послать комманду «GET /» . Именно так и работает ваш браузер.

2011.08.13