Итак, что же вообще из себя представляет Peer-to-Peer во Flash? Обмениваться сообщениями экземплярам Flash Player позволяет RTMFP — Real-Time Media Flow Protocol. Суть его в том, что клиент лишь раз обращается к серверу за помощью в соединении с остальными клиентами, после чего, получив уникальный Peer ID, может начинать пересылать любые данные напрямую.
Сервер
Для организации пиринговой сети между Flash Player существует бесплатный сервис Adobe Cirrus. Подробнее о нем можно почитать на странице Adobe Labs.
Он предназначен, скорее, для демонстрации возможностей RTMFP, поэтому нам не удастся выполнять какой-либо свой код или что-то изменять на стороне сервера. Конечно же, ничто не мешает поднять собственный сервер, совместимый с протоколом RTMFP, но сейчас для наших целей подходит Cirrus.
Для доступа к возможностям сервиса нам необходимо получить ключ разработчика, который привязывается к аккаунту Adobe. Ключ понадобится при подключении.
План действий
Я считаю, что лучшим способом познать P2P является написание собственного класса для подключения к Cirrus.
Процесс работы с Cirrus, выглядит в нашем случае следующим образом:
1. Подключаемся к Cirrus, используя наш ключ.
2. Подключаемся к группе (NetGroup).
NetGroup — класс, который предоставляет информацию о группе, в которой находится клиент. Чтобы обмениваться сообщениями, нам понадобится объединить всех наших клиентов в одну группу.
3. Обрабатываем необходимые события NetStatusEvent.NET_STATUS.
NetStatusEvent.NET_STATUS — события, связанные с удачным/неудачным подключением, получением сообщений и действиями членов группы.
4. Предоставляем клиентам возможность обмениваться сообщениями.
Написание класса
1. Подключаемся к Cirrus
Для этого нам нужен класс flash.net.NetConnection, создающий соединение между клиентом и сервером.
Функцию connect(), инициализирующую подключение я реализовал так:
// Подключение
public function connect()
{
netConnection = new NetConnection(); // переменная netConnection объявлена в теле класса
// Событие NET_STATUS нужно для отслеживания состояния подключения к серверу
netConnection.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
// Пример: "rtmfp://p2p.rtmfp.net/abcdefghijklmnopqrstu-ads12asfv"
netConnection.connect("rtmfp://p2p.rtmfp.net/" + "Ваш ключ разработчика");
}// Функция прослушивания событий NetStatusEvent
private function netStatusHandler( e:NetStatusEvent ):void
{
switch ( e.info.code )
{
case "NetConnection.Connect.Success":
trace ("Успешное подключение к серверу!")
// Подключились к Cirrus'у - переходим к настройке нашей группы
setupNetGroup();
break;
case "NetGroup.Posting.Notify":
// Событие получения сообщения
messageReceived(e.info.message);
break;
}
}// Настройка группы
private function setupNetGroup ():void
{
}// Обработка входящих сообщений
private function messageReceived (message:Object):void
{
}* This source code was highlighted with Source Code Highlighter.
Так же я заранее объявил еще три функции:
netStatusHandler — прослушивание событий от NetConnection,
setupNetGroup — вызывается при успешном подключении к серверу для настройки группы,
messageReceived — вызывается при получении сообщения от другого клиента.
2. Настраиваем класс NetGroup
Для отправки сообщений другим пользователям нам нужно создать группу, в которую эти сообщения и будут отправляться.
В нашем классе за настройку группы отвечает функция setupNetGroup().
Класс GroupSpecifier позволяет задать параметры группы для ее создания. Так как и netConnection и netGroup для оповещения о своем состоянии используют события NetStatusEvent, то для прослушивания событий будет использоваться та же функция, что и для netConnection — netStatusHandler:
// Настройка группы
private function setupNetGroup ():void
{
var groupSpecifier:GroupSpecifier = new GroupSpecifier("НазваниеГруппы");
groupSpecifier.serverChannelEnabled = true; // Для обмена с сервером
groupSpecifier.postingEnabled = true; // Разрешаем отправку сообщений в группе// переменная netGroup объявлена в теле класса
netGroup = new NetGroup(netConnection, groupSpecifier.groupspecWithAuthorizations() );
netGroup.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler); // Прослушка событий группы
}* This source code was highlighted with Source Code Highlighter.
3. Обрабатываем NetStatusEvent
Теперь нам необходимо разобраться, для чего нужны события NetStatusEvent. Рассмотрим функцию netStatusHandler:
// Функция прослушивания событий NetStatusEvent
private function netStatusHandler( e:NetStatusEvent ):void
{
trace(e.info.code);
switch ( e.info.code )
{
case "NetConnection.Connect.Success":
trace ("Успешное подключение к серверу!")
// Подключились к Cirrus'у - переходим к настройке нашей группы
setupNetGroup();
break;
case "NetGroup.Posting.Notify":
// Событие получения сообщения
messageReceived(e.info.message);
break;
}
}* This source code was highlighted with Source Code Highlighter.
Событие NetStatusEvent.NET_STATUS возвращает в e.info.code строку, представляющую событие NET_STATUS. NetStatusEvent.NET_STATUS вызывается при любых изменениях в группе.
Нам понадобились только два события NET_STATUS (на самом деле их намного больше, можно посмотреть здесь):
«NetConnection.Connect.Success» — успешное подключение netConnection к серверу Cirrus.
«NetGroup.Posting.Notify» — получение входящих сообщений, обработку которых мы рассмотрим далее.
4. Обмен сообщениями.
При получении нового сообщения вызывается функция messageRecieved, в которую передается объект сообщения, полученный из e.info.message. Так как мы пишем абстрактный класс, то при получении сообщения просто вызовем внешнюю функцию, в которую и передадим его, чтобы дальше можно было легко его обработать.
// Обработка входящих сообщений
public var callback_messageReceived:Function; // callback
private function messageReceived (message:Object):void
{
if (callback_messageReceived)
callback_messageReceived ( message );
}* This source code was highlighted with Source Code Highlighter.
Осталось написать функцию отправки сообщения. Всё, что она должна делать, — вызывать netGroup.post():
public function sendMessage( message:Object ):void
{
if (!message)
return;
netGroup.post(message); // Отправляем сообщение в группу
}* This source code was highlighted with Source Code Highlighter.
Заключение
Класс, который получился в результате, умеет лишь подключаться к группе, отправлять и получать сообщения, но, несмотря на это, используя его, можно сделать небольшой чат.
Я считаю, что эта технология обязательно найдет своё применение. Скорее всего — в играх. Ведь серверу не придется контролировать игровые сессии и синхронизировать игроков, да и пинг при прямом подключении ниже (зависит от расстояния между игроками).
Спасибо за прочтение моей статьи! Надеюсь, вы найдете что-то полезное для себя.
Источник полезной информации по теме P2P во Flash: FlashRealtime.com.
Класс, который получился в результате
Автор: drcra