(Flex) Flex (2011 год)

Сокеты во Flash

Я начал активно писать сетевые приложения более 10 лет назад (еще до появления в 2002-м году .NET Framework). Тогда я делал ActiveX-компоненты на VB6 и иногда даже запускал их в SQL2000. 10 лет назад у меня уже в SQL2000 был свой собственный полноценный Nitification Server (который в отличии от микрософтовского прекрасно работал). Позднее я сделал на базе этих наработок полноценный товарный продукт - Notification Server, который работал в компании digitalshop.ru. Кое какие фрагменты этой моей старинной проги нашли отражение у меня на сайте. А в 2006-м году я написал (на шестом бейсике) для этой же компании еще один сетевой продукт - весьма специфический крученый клон ICQ.

Я также увлекся терминальными сетями - которые представляют собой сплошное взаимодействие по сети Remote SQL execute for PostgreSQL on GSM/GPRS channel with extreme compress and cryptography. Я также продолжил писать разнообразнейшие SQL CLR сборки, которые работали с сетью, например SQL-Client_for_remote_XML-WebService - клиент meteonova.ru.

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

Я писал всевозможные сетевые пауки и парсеры в несметных количествах, всевозможные импортеры прайсов с автоматической скачкой, автоопределением форматов и укладкой прайса в базу и в конце концов написал даже собственную поисковую машину (некий клон Гугла или Яндекса), который однако работал по иным алгоритмам - WebDownloader_UltraLite - ваш личный поисковик по рунету с особыми возможностями поиска.

Я написал и оформил как OpenSource SNMP-тестер сетевых устройств. GUI-программа на Windows.Forms для Linux, Xping - утилита контроля качества связи. Вот еще моя заметка о сетевом программировании от 2005-го года.

Как видите, библиотеки сетевого обмена - это ключевой компонент любой современной системы. Просто десктопные приложения, которые что-то там сами в себе ковыряются и никому ничего в сеть не сообщают - это нонсенс. Таких приложений можно придумать крайне мало. Практически все приложения, которые вы видите у меня на сайте - так или иначе работают в TCP/IP сети.

Даже Web-cервера, на которых хостятся сайты - как правило, тоже помимо движка, который выплевывает в сеть по запросам браузеров html-странички, содержат множество разнообразных web-сервисов. Например сервисы, к которым можно приконнектится и получить AJAX подсказка/автозаполнение на jQuery.

Я не только показывал как работать с такими web-сервисами из JavaScript - например Мой первый сайт на MVC 3 Razor или из ASP.NET Этюды на ASP2. Обращение к Whois-сервису - но я даже написал свой собственный, альтернативный OpenSource клиент к такому стандартному микрософтофтовскому WCF-серверу - WCF_CLIENT - клиент Web-сервиса (первая версия).

Как видите, .NET Framework - это одно сплошное сетевое взаимодействие.


Поэтому, первое чем я занялся при освоении Flex - это сетевым взаимодействием FLEX-AIR приложений с внешним миром. Я отработал для себя (и показал всем остальным) :

Как видите, Adobe Framework - это тоже сплошные сетевые взаимодействия. Так же как и на .NET Framework. Хотя в Adobe Framework доминирует, возможно, все-таки мультимедиа, анимация и графика. Но графика довольно активно присутствует и в .NET - Наложение копирайта на рисунки, но в меньших масштабах и всегда только на сервере.Так в чем же разница между этими виртуальными машинами?


Хотя Adobe Framework проигрывает возможностям NET Framework по многим позициям - например он не дает возможностей многопоточного программирования, на нем невозможно даже создать полноценный WSDL/SOAP вебсервис, сам язык ActionScript на порядок более ограниченный по выразительности чем бейсик. И возможности объектного программирования у него по сравнению с современным бейсиком - (Практическое применение наследования, полиморфизма, интерфейсов, дженериков и делегатов на примерах в Visual Basic .NET) - в самом зародыше. Напоминают обьектные возможности шестого бейсика. Но... этот фреймворк чрезвычайно легкий. Легкий до такой степени, что даже может работать в браузере. И плюс у него есть нечто такое, чего вовсе нет в .NET Framework - анимация, звук, видео.

Если бы у меня спросили чекисты, чем отличаются эти фреймворки - то я бы обьяснил им так на понятном для них языке: Adobe Framework - это ампулка с полонием или таблетка диоксина. А бейсик - это уже грузовик с гексогеном. И для каждой задачи - свой инструмент. Одно дело - отравить Ющенко или Литвиненко, а другое дело - взорвать жилой дом на окраине Москвы или Рязани. Одна задача - просто одноразово убить в тюрьме Магницкого за 6 миллионов долларов взятки, другое дело - добиться чтобы вообще правосудия не было во всей стране в принципе и не для кого, а все решалось бы исключительно по волеизъявлению чекистов и только в их интересах. Одно дело - произвести ковровые бомбометания по всей Чечне, другое дело - подорвать в Катаре Яндарбиева и его сына на выходе из мечети. Одно дело - добиться чтобы собственность чекистов на Абхазию признали папуасы из Науру, Умумбы и Вануату, другое дело чтобы это же сделали США и Евросоюз. Одно дело - красиво отглумиться только над одной партией Яблоко - чтобы даже на участке где лично живет Митрохин - не оказалось при подсчете конторой Чурова ни единого бюллетеня за Яблоко, другое дело дело - красиво отглумиться над всей 140-миллионной страной, раскинувшейся от Балтики до Тихого океана и назначить ее презиком слабоумного и с детства недоразвитого блоггера. Одно дело - сгноить в ГУЛАГе десятки миллионов несогласных, другое дело - тихонько и точно в толпе уколоть отравленным зонтиком несогласного Маркова. Одно дело - полномасштабная война с Грузией, другое дело - просто случайно погиб Качинский со всем своим генеральным штабом. Эти ведь разные задачи - и решаются они различным инструментарием. И даже самые мелкие задачи - типа Магницкого, Троцкого, Качинского, Ющенко, Литвиненко, Яндарбиева, Маркова - тоже могут быть решены исключительно эффективно, красиво и показательно. Примерно такое же различие существует и у Adobe Fremework и NET Framework - ActionScript и Adobe Framework это исключительно точный, мощный и изящный инструмент - такой же как ампулка с полонием, карманный постановщик помех высотомеру самолета, таблеточка с диоксином, укол зонтиком, удар топором-ледорубом точно в макушку.


Итак, в Adobe Framework предусмотрено несколько классов для сетевого взаимодействия:


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

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

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

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

Вот как выглядит сетевой обмен с помощью этой библиотеки:



Итак, вот собственно тот самый код работы с сокетами по простейшему собственному протоколу. Именно с этой точки данный образец моего ActionScript кода вы можете начинать гнуть в любую сторону.


   1:  //минимальный вариант вызова сокетного сервера - слушает порт LocalTextPort.text
   2:  //
   3:  //import ru.net.asp.socket.*;
   4:  //private var LocalTextListener:Network_Listener = new Network_Listener( LocalTextPort.text );
   5:  //LocalTextListener.addEventListener(Network_Listener.DATA_RECEIVED, DATA_RECEIVED_handler);
   6:  //LocalTextListener.addEventListener(Network_Listener.DATA_ERROR, Error_handler);
   7:  //LocalTextListener.addEventListener(Network_Listener.CONNECT, Error_handler);
   8:  //LocalTextListener.addEventListener(Network_Listener.OPEN_ERROR, Error_handler);
   9:  //LocalTextListener.addEventListener(Network_Listener.CLOSE_ERROR, Error_handler);
  10:  //LocalTextListener.addEventListener(Network_Listener.PORT_OPEN, Error_handler);
  11:  //LocalTextListener.addEventListener(Network_Listener.PORT_CLOSE, Error_handler);
  12:  //LocalTextListener.addEventListener(Network_Listener.PROTOCOL_ERROR, Error_handler);
  13:  //LocalTextListener.addEventListener(Network_Listener.STRING_ERROR, Error_handler);
  14:  //LocalTextListener.Network_Open();
  15:  //
  16:  //обработчик ошибок
  17:  //protected function Error_handler(e:Event):void{
  18:  //    ErrorMessage.text += e.type + " on port " + e.currentTarget.PortNumber +"\n";
  19:  //}
  20:  //
  21:  //прием строки
  22:  //protected function DATA_RECEIVED_handler(e:Event):void{
  23:  //    Message.text += "<=" + e.currentTarget.ReadString() + "\n";
  24:  //}
  25:  //
  26:  //прием потока байтов
  27:  //protected function DATA_RECEIVED_handler(e:Event):void{
  28:  //     var Arr1:ByteArray=e.currentTarget.ReceivedBytes;
  29:  //}
  30:  //
  31:  //при приеме кроме данных приходит еще два дополнительных параметра - номер пакета и номер клиента
  32:  //   e.currentTarget.ClientNumber  = 1001;
  33:  //   e.currentTarget.PacketNumber += 1;
  34:  package ru.net.asp.socket
  35:  {
  36:      import flash.events.*;
  37:      import flash.events.IEventDispatcher;
  38:      import flash.net.ServerSocket;
  39:      import flash.net.Socket;
  40:      import flash.utils.ByteArray;
  41:      
  42:      public class Network_Listener extends EventDispatcher
  43:      {
  44:          public var ReceivedBytes:ByteArray; //принятые сервером данные
  45:          public var ClientNumber:int;        //номер, который передал клиент
  46:          public var PacketNumber:int;        //порядковый номер пакета
  47:          
  48:          //события сокетного сервера
  49:          public static const DATA_RECEIVED:String="DATA_RECEIVED";
  50:          public static const DATA_ERROR:String="DATA_ERROR";
  51:          public static const CLOSE_ERROR:String="CLOSE_ERROR";
  52:          public static const OPEN_ERROR:String="OPEN_ERROR";
  53:          public static const CONNECT:String="CONNECT";
  54:          public static const PORT_OPEN:String="PORT_OPEN";
  55:          public static const PORT_CLOSE:String="PORT_CLOSE";
  56:          public static const PROTOCOL_ERROR:String="PROTOCOL_ERROR";
  57:          public static const STRING_ERROR:String="STRING_ERROR";
  58:          
  59:          public function get PortNumber():int{
  60:              return portNumber;
  61:          }
  62:          private var portNumber:int;
  63:          
  64:          public function get Server_Socket():ServerSocket{
  65:              return ServerSocket1;
  66:          }
  67:          private var ServerSocket1:ServerSocket;
  68:          
  69:          public function Network_Listener(LocalPortNumber:String)
  70:          {
  71:              super();
  72:              portNumber=Number(LocalPortNumber);
  73:              ServerSocket1 = new ServerSocket();
  74:          }
  75:          
  76:          public function Network_Open():void
  77:          {
  78:              try
  79:              {
  80:                  ServerSocket1.addEventListener(Event.CONNECT, socketConnectHandler);
  81:                  ServerSocket1.addEventListener(Event.CLOSE,socketCloseHandler);
  82:                  ServerSocket1.bind(portNumber);
  83:                  ServerSocket1.listen();   
  84:                  dispatchEvent(new Event(Network_Listener.PORT_OPEN));
  85:              }
  86:              catch (error:Error)
  87:              {
  88:                  dispatchEvent(new Event(Network_Listener.OPEN_ERROR));
  89:              }
  90:          }
  91:          
  92:          
  93:          private function socketConnectHandler(event:ServerSocketConnectEvent):void
  94:          {
  95:              var socket:Socket = event.socket;
  96:              dispatchEvent(new Event(Network_Listener.CONNECT));
  97:              socket.addEventListener(ProgressEvent.SOCKET_DATA, socketDataHandler);
  98:          }
  99:          
 100:          //после приема байтовых данных - они в массиве ReceivedBytes
 101:          private function socketDataHandler(event:ProgressEvent):void
 102:          {
 103:              try
 104:              {
 105:                  var Socket1:Socket = event.target as Socket;
 106:                  //первые три числа - протокольная обвязка
 107:                  var PacketLength:int;
 108:                  ClientNumber = Socket1.readInt();
 109:                  PacketNumber = Socket1.readInt();
 110:                  PacketLength = Socket1.readInt();
 111:                  //вычитали данные
 112:                  ReceivedBytes = new ByteArray();
 113:                  Socket1.readBytes(ReceivedBytes);
 114:                  dispatchEvent(new Event(Network_Listener.DATA_RECEIVED));
 115:                  
 116:                  Socket1.flush();
 117:                  //заголовок возвращаем обратно в сеть
 118:                  Socket1.writeInt(ClientNumber);
 119:                  Socket1.writeInt(PacketNumber);
 120:                  Socket1.writeInt(ReceivedBytes.length);
 121:                  Socket1.flush();
 122:                  if (ReceivedBytes.length!=PacketLength){
 123:                      dispatchEvent(new Event(Network_Listener.PROTOCOL_ERROR));
 124:                  }
 125:              }
 126:              catch (error:Error)
 127:              {
 128:                  dispatchEvent(new Event(Network_Listener.DATA_ERROR));
 129:              }
 130:          }
 131:          
 132:          public function ReadString():String{
 133:              try {
 134:                  ReceivedBytes.position=0;
 135:                  return (ReceivedBytes.readUTFBytes(ReceivedBytes.length));
 136:              }
 137:              catch (error:Error)
 138:              {
 139:                  dispatchEvent(new Event(Network_Listener.STRING_ERROR));
 140:                  
 141:              }
 142:              return "";
 143:          }
 144:          
 145:          public function Network_Close():void
 146:          {
 147:              try {
 148:                  ServerSocket1.close();
 149:              }
 150:              catch (error:Error)
 151:              {
 152:                  dispatchEvent(new Event(Network_Listener.CLOSE_ERROR));
 153:              }
 154:          }
 155:          
 156:          private function socketCloseHandler(e:Event):void
 157:          {
 158:              dispatchEvent(new Event(Network_Listener.PORT_CLOSE));
 159:          }
 160:      }
 161:  }

   1:  //минимальный вариант отправки данных сокетному серверу на адресе RemoteIP.text и порту RemotePort.text
   2:  //
   3:  //import ru.net.asp.socket.*;
   4:  //private var RemoteTextSender:Network_Sender = new Network_Sender( RemoteIP.text, RemotePort.text );
   5:  //RemoteTextSender.addEventListener(Network_Sender.DATA_SENDED, ERROR_handler);
   6:  //RemoteTextSender.addEventListener(Network_Sender.DATA_ERROR, ERROR_handler);
   7:  //RemoteTextSender.addEventListener(Network_Sender.CONNECT, ERROR_handler);
   8:  //RemoteTextSender.addEventListener(Network_Sender.OPEN_ERROR, ERROR_handler;
   9:  //RemoteTextSender.addEventListener(Network_Sender.CLOSE_ERROR, ERROR_handler);
  10:  //RemoteTextSender.addEventListener(Network_Sender.PORT_OPEN, ERROR_handler;
  11:  //RemoteTextSender.addEventListener(Network_Sender.PORT_CLOSE, ERROR_handler);
  12:  //RemoteTextSender.addEventListener(Network_Sender.PROTOCOL_ERROR, ERROR_handler);
  13:  //RemoteTextSender.addEventListener(Network_Sender.SECURITY_ERROR, ERROR_handler);
  14:  //RemoteTextSender.Network_Open();
  15:  //
  16:  //обработчик ошибок
  17:  //protected function ERROR_handler(e:Event):void{
  18:  //    ErrorMessage.text += e.type + " on " + e.currentTarget.ipAddress + ":" +  e.currentTarget.PortNumber +"\n";
  19:  //}
  20:  //
  21:  //посылка в сеть строки
  22:  //if (RemoteTextSender !== null){
  23:  //    RemoteTextSender.SendString(SendMessage.text);
  24:  //}
  25:  //
  26:  //посылка в сеть байтового массива
  27:  //if (RemoteTextSender !== null){
  28:  //  var Buf1:ByteArray=new ByteArray;
  29:  //  Buf1.writeDouble(Math.PI);
  30:  //  Buf1.position=0;
  31:  //    RemoteTextSender.Send(SendMessage.text);
  32:  //}
  33:  //
  34:  //при передаче можно еще задать два параметра - номер пакета и номер клиента
  35:  //  RemoteTextSender.ClientNumber  = 1001;
  36:  //  RemoteTextSender.PacketNumber += 1;
  37:   
  38:  package ru.net.asp.socket
  39:  {
  40:      import flash.events.*;
  41:      import flash.events.IEventDispatcher;
  42:      import flash.net.Socket;
  43:      import flash.utils.ByteArray;
  44:      
  45:      public class Network_Sender extends EventDispatcher
  46:      {
  47:          
  48:          public var SendBytes:ByteArray; //данные для передачи
  49:          public var ClientNumber:int;    //идентификационный номер клиента
  50:          public var PacketNumber:int;    //номер пакета
  51:          
  52:          //протокол клиента, передающего данные на сокетный сервер
  53:          public static const OPEN_ERROR:String="OPEN_ERROR";
  54:          public static const PORT_OPEN:String="PORT_OPEN";
  55:          public static const CONNECT:String="CONNECT";
  56:          public static const DATA_SENDED:String="DATA_SENDED";
  57:          public static const DATA_ERROR:String="DATA_ERROR";
  58:          public static const PROTOCOL_ERROR:String="PROTOCOL_ERROR";
  59:          public static const PROTOCOL_OK:String="PROTOCOL_OK";
  60:          public static const SECURITY_ERROR:String="SECURITY_ERROR";
  61:          public static const CLOSE_ERROR:String="CLOSE_ERROR";
  62:          public static const PORT_CLOSE:String="PORT_CLOSE";
  63:          
  64:          
  65:          public function get PortNumber():int{
  66:              return portNumber;
  67:          }
  68:          private var portNumber:int;
  69:          public function get IpAddress():String{
  70:              return ipAddress;
  71:          }
  72:          private var ipAddress:String;
  73:          
  74:          public function get Sender_Socket():Socket{
  75:              return SenderSocket1;
  76:          }
  77:          private var SenderSocket1:Socket;
  78:          
  79:          public function Network_Sender(RemoteIPaddr:String, RemotePortNumber:Object):void
  80:          {
  81:              super();
  82:              portNumber = Number(RemotePortNumber);
  83:              ipAddress = RemoteIPaddr;
  84:              SendBytes=new ByteArray;
  85:              SenderSocket1 = new Socket();
  86:          }
  87:          
  88:          public function Network_Open():void
  89:          {
  90:              try
  91:              {
  92:                  SenderSocket1.addEventListener(Event.CLOSE, SocketCloseHandler);
  93:                  SenderSocket1.addEventListener(Event.CONNECT, SocketConnectHandler);
  94:                  SenderSocket1.addEventListener(IOErrorEvent.IO_ERROR, SocketIoErrorHandler);
  95:                  SenderSocket1.addEventListener(SecurityErrorEvent.SECURITY_ERROR, SocketSecurityErrorHandler);
  96:                  SenderSocket1.addEventListener(ProgressEvent.SOCKET_DATA, socketSocketDataHandler);
  97:                  SenderSocket1.connect(ipAddress, portNumber);
  98:                  dispatchEvent(new Event(Network_Sender.PORT_OPEN));
  99:              }
 100:              catch (error:Error)
 101:              {
 102:                  dispatchEvent(new Event(Network_Sender.OPEN_ERROR));
 103:              }
 104:          }
 105:          
 106:          private function SocketConnectHandler(event:Event):void {
 107:              dispatchEvent(new Event(Network_Sender.CONNECT));
 108:          }
 109:          
 110:          //все что передавать побайтово - задается глобальными переменными отдельно
 111:          public function Send():void{
 112:              try
 113:              {
 114:                  //пишем в сеть сначала заголовок
 115:                  SenderSocket1.writeInt(ClientNumber);
 116:                  SenderSocket1.writeInt(PacketNumber);
 117:                  SenderSocket1.writeInt(SendBytes.length);
 118:                  //пишем данные
 119:                  SenderSocket1.writeBytes(SendBytes,0,SendBytes.length);
 120:                  SenderSocket1.flush();
 121:                  dispatchEvent(new Event(Network_Sender.DATA_SENDED));
 122:              }
 123:              catch (error:Error)
 124:              {
 125:                  dispatchEvent(new Event(Network_Sender.DATA_ERROR));
 126:              }
 127:          }
 128:          
 129:          //упрощенный вариант передачи - только текст
 130:          public function SendString(Str1:String):void{
 131:              SendBytes=new ByteArray;
 132:              SendBytes.writeUTFBytes(Str1);
 133:              SendBytes.position=0;
 134:              Send();
 135:          }
 136:          
 137:          private function socketSocketDataHandler(e:ProgressEvent):void {
 138:              try            
 139:              {
 140:                  var Sicket1:Socket=e.currentTarget as Socket;            //читаем ответ, по протокоду - просто возвращается заголовок
 141:                  var RequestClientNumber:int= SenderSocket1.readInt();
 142:                  var RequestPacketNumber:int= SenderSocket1.readInt();
 143:                  var RequestSendBytes:int= SenderSocket1.readInt();
 144:                  SenderSocket1.flush();
 145:                  if (RequestClientNumber!=ClientNumber || RequestPacketNumber!=PacketNumber || RequestSendBytes!=SendBytes.length){
 146:                      dispatchEvent(new Event(Network_Sender.PROTOCOL_ERROR));
 147:                  }
 148:                  else {
 149:                      dispatchEvent(new Event(Network_Sender.PROTOCOL_OK));
 150:                  }
 151:              }
 152:              catch (error:Error)
 153:              {
 154:                  dispatchEvent(new Event(Network_Sender.DATA_ERROR));
 155:              }
 156:          }
 157:          
 158:          private function SocketCloseHandler(event:Event):void {
 159:              try
 160:              {
 161:                  dispatchEvent(new Event(Network_Sender.PORT_CLOSE));
 162:              }
 163:              catch (error:Error)
 164:              {
 165:                  dispatchEvent(new Event(Network_Sender.CLOSE_ERROR));
 166:              }
 167:          }
 168:          
 169:          private function SocketIoErrorHandler(event:IOErrorEvent):void {
 170:              dispatchEvent(new Event(Network_Sender.DATA_ERROR));
 171:          }
 172:          
 173:          private function SocketSecurityErrorHandler(event:SecurityErrorEvent):void {
 174:              dispatchEvent(new Event(Network_Sender.SECURITY_ERROR));
 175:          }
 176:          
 177:          public function Network_Close():void
 178:          {
 179:              try {
 180:                  SenderSocket1.close();
 181:              }
 182:              catch (error:Error)
 183:              {
 184:                  dispatchEvent(new Event(Network_Listener.CLOSE_ERROR));
 185:              }
 186:          }
 187:      }
 188:  }

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

Итак, для простейшего текстового чата разместим на форме кнопку отправки текстового сообщения и форму отображения текстового сообщения:


   1:      <s:TileGroup horizontalGap="12" verticalGap="12" left="10" right="10" top="10" bottom="10">
   2:          <mx:Form dropShadowVisible="true" borderAlpha="1.0" borderVisible="true" borderStyle="solid" width="300" height="132">
   3:              <mx:FormHeading label="Message:"/>
   4:              <mx:FormItem>
   5:                  <s:RichText id="AllMessage" />
   6:              </mx:FormItem>
   7:              <mx:FormItem >
   8:                  <s:TextInput id="SendMessage" width="100%" enter="SendMessage_enterHandler(event)"/>
   9:              </mx:FormItem>
  10:              <mx:FormItem>
  11:                  <s:Button label="Send" id="MessageSend" click="MessageSend_clickHandler(event)"/>
  12:              </mx:FormItem>
  13:              </mx:Form>
  14:          <mx:Form width="300" dropShadowVisible="true" borderStyle="solid" borderVisible="true">
  15:              <mx:FormHeading label="SERVER"/>
  16:              <mx:FormItem label="Local IP" id="LocalIP">
  17:                  <s:Label text="127.0.0.1"/>
  18:              </mx:FormItem>
  19:              <mx:FormItem label="Local Audio Port">
  20:                  <s:TextInput text="101" id="LocalAudioPort"/>
  21:              </mx:FormItem>
  22:              <mx:FormItem label="Local Video Port">
  23:                  <s:TextInput text="102" id="LocalVideoPort"/>
  24:              </mx:FormItem>
  25:              <mx:FormItem label="Local Text Port">
  26:                  <s:TextInput text="103" id="LocalTextPort"/>
  27:              </mx:FormItem>
  28:              <mx:FormItem>
  29:                  <s:Button label="Start" id="StartLocalNetwork" click="StartLocalNetwork_clickHandler(event)"/>
  30:              </mx:FormItem>
  31:              <mx:FormItem>
  32:                  <s:Button label="Stop" id="StopLocalNetwork" click="StopLocalNetwork_clickHandler(event)"/>
  33:              </mx:FormItem>
  34:          </mx:Form>
  35:          <mx:Form width="300" dropShadowVisible="true" borderStyle="solid" borderVisible="true">
  36:              <mx:FormHeading label="SENDER:"/>
  37:              <mx:FormItem label="Remote IP">
  38:                  <s:TextInput text="127.0.0.1" id="RemoteIP"/>
  39:              </mx:FormItem>
  40:              <mx:FormItem label="Remote Audio Port">
  41:                  <s:TextInput text="101" id="RemoteAudioPort"/>
  42:              </mx:FormItem>
  43:              <mx:FormItem label="Remote Video Port">
  44:                  <s:TextInput text="102" id="RemoteVideoPort"/>
  45:              </mx:FormItem>
  46:              <mx:FormItem label="Remote Text Port">
  47:                  <s:TextInput text="103" id="RemoteTextPort"/>
  48:              </mx:FormItem>
  49:              <mx:FormItem>
  50:                  <s:Button label="Start" id="StartRemoteNetwork" click="StartRemoteNetwork_clickHandler(event)"/>
  51:              </mx:FormItem>
  52:              <mx:FormItem>
  53:                  <s:Button label="Stop" id="StopRemoteNetwork" click="StopRemoteNetwork_clickHandler(event)"/>
  54:              </mx:FormItem>
  55:          </mx:Form>
  56:          <mx:Form dropShadowVisible="true" borderAlpha="1.0" borderVisible="true" borderStyle="solid" width="300" height="132">
  57:              <mx:FormHeading label="System message:"/>
  58:              <mx:FormItem >
  59:                  <s:RichText id="ErrorMessage" text="" />
  60:              </mx:FormItem>
  61:          </mx:Form>
  62:      </s:TileGroup>

А далее нужно добавить вызов этого класса, например так:


   1:      <fx:Script>
   2:      <![CDATA[
   3:          import flash.events.*;
   4:          import mx.controls.Alert;
   5:          import mx.events.FlexEvent;
   6:          import mx.graphics.codec.JPEGEncoder;
   7:          import ru.net.asp.socket.*;
   8:      
   9:          protected function windowedapplication1_contentCreationCompleteHandler(event:FlexEvent):void
  10:          {
  11:              var Sender1:Network_Sender=new Network_Sender("127.0.0.1",101);
  12:          }
  13:   
  14:  ...
  15:          //***********************************************************************
  16:  ...
  17:   
  18:          private var ServerAudioListener:Network_Listener;
  19:          private var ServerVideoListener:Network_Listener;
  20:          private var ServerTextListener:Network_Listener;
  21:          private var Loader1:Loader;
  22:          
  23:          protected function StartLocalNetwork_clickHandler(event:MouseEvent):void
  24:          {
  25:              try {
  26:                  ServerAudioListener = NetworkServerPrepare(ServerAudioListener,LocalAudioPort.text);
  27:                  ServerVideoListener = NetworkServerPrepare(ServerVideoListener,LocalVideoPort.text);
  28:                  ServerTextListener  = NetworkServerPrepare(ServerTextListener, LocalTextPort.text);
  29:                  ServerAudioListener.addEventListener(Network_Listener.DATA_RECEIVED, Server_Audio_DATA_RECEIVED_handler);
  30:                  ServerVideoListener.addEventListener(Network_Listener.DATA_RECEIVED, Server_Video_DATA_RECEIVED_handler);
  31:                  ServerTextListener.addEventListener(Network_Listener.DATA_RECEIVED, Server_Text_DATA_RECEIVED_handler);
  32:              }
  33:              catch (error:Error)
  34:              {
  35:                  ErrorMessage.text += "Server Error: " + error.message + "\n";
  36:              }
  37:          }
  38:   
  39:          private function NetworkServerPrepare(X:Network_Listener, LocalPort:String):Network_Listener{
  40:                  X = new Network_Listener(LocalPort);
  41:                  X.addEventListener(Network_Listener.DATA_ERROR, ServerInfo_handler);
  42:                  X.addEventListener(Network_Listener.CONNECT, ServerInfo_handler);
  43:                  X.addEventListener(Network_Listener.OPEN_ERROR, Server_OPEN_ERROR_handler);
  44:                  X.addEventListener(Network_Listener.CLOSE_ERROR, ServerInfo_handler);
  45:                  X.addEventListener(Network_Listener.PORT_OPEN, ServerInfo_handler);
  46:                  X.addEventListener(Network_Listener.PORT_CLOSE, ServerInfo_handler);
  47:                  X.addEventListener(Network_Listener.PROTOCOL_ERROR, ServerInfo_handler);
  48:                  X.addEventListener(Network_Listener.STRING_ERROR, ServerInfo_handler);
  49:                  X.Network_Open();
  50:                  return X;
  51:          }
  52:          
  53:          protected function StopLocalNetwork_clickHandler(event:MouseEvent):void
  54:          {
  55:              try {
  56:                  ServerAudioListener.Network_Close();
  57:                  ServerVideoListener.Network_Close();
  58:                  ServerTextListener.Network_Close();
  59:              }
  60:              catch (error:Error)
  61:              {
  62:                  ErrorMessage.text += "Local error: " + error.message + "\n";
  63:              }
  64:          }
  65:          
  66:          protected function ServerInfo_handler(e:Event):void{
  67:              ErrorMessage.text += "Server: " + e.type + " on local port " +  e.currentTarget.PortNumber +"\n";
  68:          }
  69:          protected function Server_OPEN_ERROR_handler(e:Event):void{
  70:              ErrorMessage.text += "Server local port " + e.currentTarget.PortNumber + " in use. Select another port. \n";
  71:          }
  72:   
  73:          protected function Server_Text_DATA_RECEIVED_handler(e:Event):void{
  74:              ErrorMessage.text += "Server: " + e.type + " on local port " +  e.currentTarget.PortNumber +"\n";
  75:              AllMessage.text += "<=" + e.currentTarget.ReadString() + "\n";
  76:          }
  77:   
  78:  ...
  79:          //***********************************************************************
  80:  ...
  81:          
  82:          private var SenderAudioSender:Network_Sender;
  83:          private var SenderVideoSender:Network_Sender;
  84:          private var SenderTextSender:Network_Sender;
  85:   
  86:          protected function StartRemoteNetwork_clickHandler(event:MouseEvent):void
  87:          {
  88:              try {
  89:                  SenderTextSender  = NetworkSenderPrepare(SenderTextSender, RemoteIP.text, RemoteTextPort.text);
  90:  ...
  91:              } 
  92:              catch (error:Error)
  93:              {
  94:                  ErrorMessage.text += "Sender Error: " + error.message + "\n";
  95:              }
  96:          }
  97:   
  98:          private function NetworkSenderPrepare(X:Network_Sender,RemoteIpAddr:String, RemotePort:String):Network_Sender{
  99:                  X = new Network_Sender(RemoteIpAddr, RemotePort);
 100:                  X.addEventListener(Network_Sender.DATA_SENDED, SenderInfo_handler);
 101:                  X.addEventListener(Network_Sender.DATA_ERROR, SenderInfo_handler);
 102:                  X.addEventListener(Network_Sender.CONNECT, SenderInfo_handler);
 103:                  X.addEventListener(Network_Sender.OPEN_ERROR, SenderInfo_handler);
 104:                  X.addEventListener(Network_Sender.CLOSE_ERROR, SenderInfo_handler);
 105:                  X.addEventListener(Network_Sender.PORT_OPEN, SenderInfo_handler);
 106:                  X.addEventListener(Network_Sender.PORT_CLOSE, SenderInfo_handler);
 107:                  X.addEventListener(Network_Sender.PROTOCOL_ERROR, SenderInfo_handler);
 108:                  X.addEventListener(Network_Sender.PROTOCOL_OK, SenderInfo_handler);
 109:                  X.addEventListener(Network_Sender.SECURITY_ERROR, SenderInfo_handler);
 110:                  X.Network_Open();
 111:                  return X;
 112:          }
 113:   
 114:          protected function StopRemoteNetwork_clickHandler(event:MouseEvent):void
 115:          {
 116:              try {
 117:                  SenderAudioSender.Network_Close();
 118:                  SenderVideoSender.Network_Close();
 119:                  SenderTextSender.Network_Close();
 120:              }
 121:              catch (error:Error)
 122:              {
 123:                  ErrorMessage.text += "Sender Error: " + error.message + "\n";
 124:              }
 125:          }
 126:   
 127:          protected function SenderInfo_handler(e:Event):void{
 128:              ErrorMessage.text += "Sender: " + e.type + " on " + e.currentTarget.IpAddress + ":" +  e.currentTarget.PortNumber +"\n";
 129:          }
 130:          
 131:          protected function MessageSend_clickHandler(event:MouseEvent):void
 132:          {
 133:              AllMessage.text += "=>" + SendMessage.text + "\n";
 134:              if (SenderTextSender !== null){
 135:                  SenderTextSender.SendString(SendMessage.text);
 136:              }
 137:              SendMessage.text="";
 138:          }
 139:      ]]>
 140:      </fx:Script>

Одновременно эта страничка получилась прекрасной демонстрацией обьектных возможностей ActionScript - в продолжение топика Реклама в видеоплеере (возможности объектного программирования ActionScript).



Comments ( )
<00>  <01>  <02>  <03>  <04>  <05>  <06>  <07>  <08>  <09>  <10>  <11>  <12>  <13>  <14>  <15>  <16>  <17>  <18>  <19>  <20>  <21>  <22>  <23
Link to this page: //www.vb-net.com/Flex_Socket/index.htm
<SITEMAP>  <MVC>  <ASP>  <NET>  <DATA>  <KIOSK>  <FLEX>  <SQL>  <NOTES>  <LINUX>  <MONO>  <FREEWARE>  <DOCS>  <ENG>  <CHAT ME>  <ABOUT ME>  < THANKS ME>