« Мультимедиа-программирование вместе с Red 5 server. Часть 5 | Мультимедиа-программирование вместе с Red 5 server. Часть 7 » |
Мультимедиа-программирование вместе с Red 5 server. Часть 6
Прошлые статьи были посвящены рассмотрению простейшей схемы взаимодействия между пользователями и приложением, исполняющимся в среде red5. Т.е. я показывал то, как flash-клиент может вызвать любой метод на сервере, и то, как сервер может вызвать метод на стороне клиента. Однако подобное двунаправленное общение между клиентом и сервером - это еще не самое "вкусное", что мы можем сделать с помощью red5. Существует целый класс приложений, в которых ставка сделана на организацию взаимодействия между самими клиентами: это организация видеоконференций, многопользовательские игры и т.д. Давайте посмотрим, чем нам может помочь red5 в этом случае.Предыдущая статья завершилась на том, что я показал, как сервер может вызвать любой метод, расположенный на стороне клиента. И сделать это сервер может в любой момент времени благодаря тому, что подключение клиента к серверу выполняется по протоколу rtmp. Соединение в этом случае является постоянным и сохраняется до тех пор, пока клиент не явно не решит отключиться от сервера. Вы можете легко создать такое red5-приложение, которое сохраняет все клиентские подключения в виде какого-то списка или массива. Затем можно выполнять рассылку по всем этим подключениям извещений о событиях, произошедших с одним из клиентов. Например, для чата, после того как один пользователь ввел текст сообщения и нажал кнопку "отправить на сервер", то сервер выполняет рассылку этого текстового сообщения всем остальным зарегистрированным клиентам. Несмотря на то, что подобное "сделанное" на коленке решение будет вполне работоспособным, мы пойдем другим путем. Дело в том, что задача организации коллективного общения возникла далеко не вчера и в среде red5 есть специальные механизмы для этого (SharedObjects). Понятие SharedObject-ов имеет несколько значений в flash и actionscript и наверняка знакомо любому, даже начинающему, flash-разработчику. Даже если вы никогда ничего не слышали о red5 или flash media server, да и вообще никогда не сталкивались с задачами общения flash-клиента с сервером, то все равно мы могли столкнуться с SharedObject. Дело в том, что существует два вида SharedObject-ов: локальные (local) и распределенные (remote). В соответствии с этим есть три основных сценария использования SharedObject-ов. Во-первых, вы можете использовать SharedObject-ы без red5 сервера только для того, чтобы сохранять некоторую информацию на локальном компьютере клиента между несколькими сеансами работы с приложением. Эти, так называемые "локальные", SharedObject-ы чем-то похожи на доступные во всех браузерах cookie. Технически, для создания локального SharedObject-а вы делаете вызов метода SharedObject.getLocal():
var so:SharedObject = SharedObject.getLocal("some-path");
so.data.username = "My User Name";
// а теперь сохраним информацию на диск
so.flush();
Естественно, что идея "общих удаленных объектов" появилась задолго до red5 - еще в версии flash mx (flash 6). Тогда на стороне сервера RemoteObjects поддерживались единственным на тот момент времени медиа-сервером от macromedia|adobe (Adobe Flash Media Server). Итак, подводя итог SharedObjects - это механизм синхронизации информации между несколькими клиентами, а также способ для сохранения информации между несколькими сеансами либо на сервере, либо на локальном компьютере клиента. SharedObjects являются "общими" не для всех клиентов нашего приложения вообще, а для тех из них, кто подключен к одной "области" (room или scope). Давайте вернемся немного назад к тому моменту времени, когда я приводил пример адреса, по которому flash-клиент может подключиться к red5-серверу. Вот пример подобного URL-а - "rtmp://localhost/warmodule". Здесь "warmodule" - это имя веб-приложения. Но приложение может быть очень большим, предоставлять различные наборы функционала и различным группам пользователей. Например, приложение для онлайн-игр в шашки может предоставлять возможность создать игровую комнату, затем присоединить к этой комнате пару игроков и изолировать эту комнату от всех остальных комнат. Игроки, зашедшие в одну и ту же комнату, получают возможность совместно играть, обмениваться аудио-сообщениями, картинками и т.д. Вот пример еще одного адреса для подключения к red5 приложению: "rtmp://localhost/warmodule/games/chess/room12". Здесь говорится, что внутри приложения "warmodule" есть иерархия "комнат" (они же области видимости). Комната "games" содержит внутри себя комнату "chess", внутри которой находится уже конкретная комната с игроками "room12". Т.е. комнаты могут быть организованы в виде иерархического дерева; и создание всей этой иерархии не требует никаких дополнительных настроек на стороне red5-сервера. Далее, в каждой комнате может находиться отдельный SharedObject, доступный всем клиентам, зашедшим в эту комнату и пославшим запрос на подключение к "общему объекту". Для демонстрации того, как работать с SharedObject я попробую создать простенький чат. Визуально чат будет выглядеть как текстовое поле с кнопкой, по нажатию на которую выполняется модификация SharedObject-а "история сообщений". Затем работает магия red5, которая отправит извещения всем остальным участникам чата о добавлении сообщения. Это сообщение будет "поймано" и сам текст сообщения будет добавлен к табличке (grid-у) размещенной внизу формы приложения. То, что должно у нас получиться, показано на рис. 1.
Пример я начну с рассмотрения mxml-разметки создающей каркас внешнего вида формы:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
<mx:Script><![CDATA[
import flash.events.MouseEvent;
import mx.collections.ArrayCollection;
import mx.controls.Alert;
[Bindable]
private var localHistory: ArrayCollection = new ArrayCollection ();
]]></mx:Script>
<mx:VBox paddingTop="10" paddingLeft="10">
<mx:HBox>
<mx:TextInput id="txtUser"/>
<mx:Button click="doConnect(event)" label="connect to Red5"/>
</mx:HBox>
<mx:HBox>
<mx:TextInput id="txtMessage"/>
<mx:Button click="say(event)" label="Send"/>
</mx:HBox>
<mx:DataGrid id="gridMessages" height="275" editable="false" dataProvider="{localHistory}">
<mx:columns>
<mx:DataGridColumn dataField="user" width="50" headerText="User"/>
<mx:DataGridColumn dataField="date" width="50" headerText="Date"/>
<mx:DataGridColumn dataField="message" width="600" headerText="Message"/>
</mx:columns>
</mx:DataGrid>
</mx:VBox>
</mx:Application>
private var nc:NetConnection;
private function doConnect(event:MouseEvent):void {
if (! txtUser.text){
Alert.show ("Сначала нужно указать ваше имя");
return;
}
var context : String = application.parent.loaderInfo.parameters['contextName'];
nc = new NetConnection();
nc.objectEncoding = ObjectEncoding.AMF0;
nc.addEventListener(NetStatusEvent.NET_STATUS, netStatus);
nc.connect('rtmp://192.168.1.2/warmodule/chat');
txtUser.enabled = false;
}
private var chat : SharedObject;
private function netStatus(event:NetStatusEvent):void {
if (event.info.code == 'NetConnection.Connect.Success'){
chat = SharedObject.getRemote("chat", nc.uri);
chat.addEventListener(SyncEvent.SYNC, onSync)
chat.connect(nc);
}
}
private var chatIsReady: Boolean = false;
private function onSync(event : SyncEvent):void {
if (chatIsReady == false){
chatIsReady = true;
if (!chat.data.remoteHistory)
chat.data.remoteHistory = [];
chat.data.remoteHistory.push ({user: txtUser.text, date: new Date(), message : 'Зашел в чат'});
chat.setDirty("remoteHistory");
}
localHistory.source = chat.data.remoteHistory;
}
private function say(e: MouseEvent):void {
if (! chatIsReady){
mx.controls.Alert.show("Сначала нужно подключиться к серверу");
return;
}
chat.data.remoteHistory.push (
{
user: txtUser.text,
date: new Date(),
message: txtMessage.text
}
);
chat.setDirty("remoteHistory");
}
<mx:Button click="doExit(event)" label="Exit " />
private function doExit (e: MouseEvent):void{
if (! chatIsReady){
mx.controls.Alert.show("Сначала нужно подключиться к серверу");
return;
}
chat.send("onExit", txtUser.text);
}
private function onExit (...userName):void{
mx.controls.Alert.show("Получено сообщение о том, что пользователь "+ userName + " покинул чат");
}
chat = SharedObject.getRemote("chat", nc.uri);
chat.addEventListener(SyncEvent.SYNC, onSync)
chat.client = this;// вот она привязка
chat.connect(nc);
На сегодня все. В следующий раз я расскажу о том, как можно создавать "сохраняемые на сервере" SharedObject-ы, как можно изменять свойства SharedObject-ов с сервера и как написать такой java-код, который будет реагировать на сообщения, рассылаемые из flash-клиента.
« Мультимедиа-программирование вместе с Red 5 server. Часть 5 | Мультимедиа-программирование вместе с Red 5 server. Часть 7 » |