Gniazda
Flash Player 9 i nowsze wersje, Adobe AIR 1.0 i nowsze wersje
Gniazdo to typ połączenia sieciowego ustanowionego między dwoma procesami komputera. Zazwyczaj procesy są uruchamiane na dwóch różnych komputerach podłączonych do tej samej sieci IP (Internet Protocol). Jednak połączone procesy mogą być uruchamiane na tym samym komputerze za pomocą specjalnego adresu IP: „hosta lokalnego”.
Aplikacja Adobe Flash Player obsługuje gniazda klienckie TCP (Transport Control Protocol). Aplikacja Flash Player może połączyć się z innym procesem, działając jako serwer gniazd, ale nie może akceptować przychodzących żądań połączenia z innych procesów. Innymi słowy aplikacja Flash Player może połączyć się z serwerem TCP, ale nie może działać jako serwer.
Interfejs API Flash Player obejmuje także klasę XMLSocket. Klasa XMLSocket używa protokołu specyficznego dla programu Flash Player, który umożliwia wymianę komunikatów XML z serwerem, który obsługuje ten protokół. Klasa XMLSocket została wprowadzona w języku ActionScript 1 i z uwagi na zgodność z tą wersją nadal jest obsługiwana. Co do zasady w nowych aplikacjach powinna być używana klasa Socket, chyba że użytkownik łączy się z serwerem utworzonym specjalnie do komunikacji z obiektami Flash XMLSocket.
Środowisko Adobe AIR zapewnia kilka dodatkowych klas do programowania sieciowego opartego na gniazdach. Aplikacje AIR mogą działać jako serwery gniazd TCP dzięki klasie ServerSocket oraz łączyć się z serwerami gniazd wymagającymi zabezpieczeń SSL lub TSL za pomocą klasy SecureSocket. Aplikacje AIR mogą także wysyłać i odbierać komunikaty UDP (Universal Datagram Protocol) za pomocą klasy DatagramSocket.
Gniazda TCP
Protokół TCP (Transmission Control Protocol) umożliwia wymianę komunikatów za pośrednictwem trwałego połączenia sieciowego. Protokół TCP gwarantuje odbieranie wysłanych komunikatów w określonej, prawidłowej kolejności (z wyjątkiem sytuacji, gdy wystąpi poważny problem z siecią). W przypadku połączeń TCP wymagane jest określenie „klienta” oraz „serwera”. Utworzenie gniazd klienckich jest możliwe za pomocą odtwarzacza Flash Player. W środowisku Adobe AIR można ponadto tworzyć również gniazda serwerowe.
Poniższe elementy interfejsu API języka ActionScript udostępniają połączenia TCP:
-
Socket — umożliwia nawiązanie połączenia z serwerem przez aplikację kliencką. Klasa Socket nie może nasłuchiwać połączeń przychodzących.
-
SecureSocket (AIR) — umożliwia nawiązanie przez aplikację kliencką połączenia z zaufanym serwerem i udział w szyfrowanej komunikacji.
-
ServerSocket (AIR) — umożliwia nasłuchiwanie przez aplikację połączeń przychodzących oraz pełnienie roli serwera.
-
XMLSocket — umożliwia nawiązanie przez aplikację kliencką połączenia z serwerem XMLSocket.
Gniazda binarne na kliencie
Połączenie z gniazdem binarnym jest podobne do gniazda XML, z tym że klient i serwer mogą wymieniać między sobą dowolne dane, a nie tylko komunikaty XML. Zamiast tego połączenie może przekazywać dane jako informacje binarne. To zaś umożliwia nawiązanie połączenia z szerszą gamą usług, między innymi serwerami poczty (POP3, SMTP i IMAP) oraz serwerami wiadomości (NNTP).
Klasa Socket
Klasa Socket pozwala na nawiązywanie połączeń przez gniazda, a także na czytanie i zapisywanie surowych danych binarnych. Klasa Socket jest użyteczna podczas pracy z serwerami, które korzystają z protokołów binarnych. Za pomocą połączeń gniazd binarnych można zapisywać kod, który umożliwia interakcję z kilkoma różnymi protokołami internetowymi, takimi jak POP3, SMTP, IMAP i NNTP. Takie interakcje z kolei umożliwiają aplikacjom użytkownika nawiązywanie połączeń z serwerem poczty i wiadomości.
Program Flash Player może łączyć się bezpośrednio z serwerem za pomocą protokołu binarnego tego serwera. W niektórych serwerach stosowana jest kolejność bajtów big-endian, a w niektórych little-endian. W większości serwerów internetowych stosowana jest kolejność big-endian, ponieważ w sieci obowiązuje kolejność bajtów big-endian. Kolejność bajtów little-endian jest popularna, ponieważ jest stosowana w architekturze Intel® x86. Należy stosować kolejność bajtów endian, która jest zgodna z protokołem serwera wysyłającego lub odbierającego dane. Wszystkie operacje wykonywane przez interfejsy IDataInput i IDataOutput, a także klasy, które implementują te interfejsy (ByteArray, Socket i URLStream), są domyślnie zakodowane w formacie big-endian; to znaczy, że bajt najważniejszy jest pierwszy. Ta domyślna kolejność bajtów została wybrana w celu zachowania zgodności z językiem Java oraz oficjalną kolejnością bajtów w sieci. Aby zmienić kolejność big-endian na little-endian lub odwrotnie, należy dla właściwości
endian
ustawić wartość
Endian.BIG_ENDIAN
lub
Endian.LITTLE_ENDIAN
.
Klasa Socket dziedziczy wszystkie metody zdefiniowane przez interfejsy IDataInput i IDataOutput (które znajdują się w pakiecie flash.utils). Zapis i odczyt do/z obiektu Socket musi odbywać się za pośrednictwem tych metod.
Więcej informacji:
Bezpieczne gniazda klienckie (AIR)
Klasa SecureSocket umożliwia nawiązywanie połączeń z serwerami gniazd, które korzystają z protokołu SSLv4 (Secure Sockets Layer version 4) lub TLSv1 (Transport Layer Security version 1). Korzystanie z gniazd zabezpieczonych przynosi trojakie korzyści: uwierzytelnianie serwera, integralność danych i poufność komunikatów. Środowisko wykonawcze uwierzytelnia serwer na podstawie certyfikatu serwera i jego relacji z certyfikatem głównym bądź certyfikatami pośrednimi ośrodków certyfikacji (CA). Środowisko wykonawcze zapewnia integralność danych i poufność komunikatów, wykorzystując algorytmy szyfrowania zastosowane w implementacjach protokołów SSL i TLS.
Przy próbie nawiązania połączenia z serwerem za pomocą obiektu SecureSocket środowisko wykonawcze sprawdza ważność certyfikatu klienta, używając magazynu certyfikatów zaufanych. Systemy operacyjne Windows i Mac zapewniają magazyn certyfikatów zaufanych. W systemie Linux środowisko wykonawcze udostępnia własny magazyn certyfikatów zaufanych.
Jeśli certyfikat serwera nie jest ważny lub nie jest zaufany, środowisko wykonawcze wywołuje zdarzenie
ioError
. Aby określić przyczynę negatywnego wyniku sprawdzania certyfikatu, można odczytać właściwość
serverCertificateStatus
obiektu SecureSocket. Nie są dostępne żadne środki komunikacji z serwerem, który nie ma ważnego i zaufanego certyfikatu.
Klasa CertificateStatus definiuje stałe ciągi znaków, które reprezentują możliwe wyniki sprawdzania ważności:
-
Expired — minął termin ważności certyfikatu.
-
Invalid — certyfikat jest nieważny i istnieje kilka możliwych przyczyn tego stanu rzeczy. Możliwe, że certyfikat został zmieniony, uszkodzony lub jest certyfikatem niewłaściwego typu.
-
Invalid chain — co najmniej jeden certyfikat w łańcuchu certyfikatów serwera jest niepoprawny.
-
Principal mismatch — nazwa hosta serwera i nazwa zwykła certyfikatu są różne. Innymi słowy, serwer korzysta z niewłaściwego certyfikatu.
-
Revoked — certyfikat został unieważniony przez ośrodek certyfikacji, który go wystawił.
-
Trusted — certyfikat jest ważny i zaufany. Obiekt SecureSocket umożliwia nawiązywanie połączeń tylko z serwerami, które mają ważne, zaufane certyfikaty.
-
Unknown — obiekt SecureSocket nie sprawdził jeszcze ważności certyfikatu. Właściwość
serverCertificateStatus
ma tę wartość przed wywołaniem metody
connect()
i zanim zostanie wywołane zdarzenie
connect
lub
ioError
.
-
Untrusted signers — certyfikat nie jest połączony łańcuchem z zaufanym certyfikatem głównym w magazynie certyfikatów zaufanych na komputerze klienckim.
Aby możliwa była komunikacja za pośrednictwem obiektu SecureSocket, serwer musi korzystać z bezpiecznego protokołu i mieć ważny, zaufany certyfikat. Pod innymi względami obiekt SecureSocket nie różni się od obiektu Socket.
Obiekt SecureSocket nie jest obsługiwany na wszystkich platformach. Właściwość
isSupported
klasy SecureSocket umożliwia sprawdzenie, czy środowisko wykonawcze pozwala na korzystanie z obiektu SecureSocket na bieżącym komputerze klienckim.
Więcej informacji:
Przykład z gniazdem TCP: budowanie klienta Telnet
Przykład Telnet prezentuje technikę łączenia ze zdalnym serwerem i przesyłania danych za pomocą klasy Socket. Przykład prezentuje następujące techniki:
-
Tworzenie niestandardowego klienta telnet za pomocą klasy Socket
-
Wysyłanie tekstu do serwera zdalnego za pomocą obiektu ByteArray
-
Obsługa danych odebranych z serwera zdalnego
Aby pobrać pliki tej przykładowej aplikacji, należy przejść na stronę
www.adobe.com/go/learn_programmingAS3samples_flash_pl
. Pliki aplikacji Telnet można znaleźć w folderze Samples/Telnet. Aplikacja składa się z następujących plików:
File
|
Opis
|
TelnetSocket.fla
lub
TelnetSocket.mxml
|
Główny plik aplikacji zawierający interfejs użytkownika dla programów Flex (MXML) lub Flash (FLA).
|
TelnetSocket.as
|
Klasa dokumentu udostępniająca logikę interfejsu użytkownika (tylko dla programu Flash).
|
com/example/programmingas3/Telnet/Telnet.as
|
Udostępnia funkcje klienta Telnet dla aplikacji, np. funkcje łączenia ze zdalnym serwerem oraz wysyłania, odbierania i wyświetlania danych.
|
Aplikacja gniazda Telnet - przegląd
Główny plik TelnetSocket.mxml jest odpowiedzialny za utworzenie interfejsu użytkownika dla całej aplikacji.
Oprócz interfejsu użytkownika plik definiuje również dwie metody:
login()
i
sendCommand()
, w celu nawiązania połączenia użytkownika z określonym serwerem.
Poniżej przedstawiono kod ActionScript w głównym pliku aplikacji:
import com.example.programmingas3.socket.Telnet;
private var telnetClient:Telnet;
private function connect():void
{
telnetClient = new Telnet(serverName.text, int(portNumber.text), output);
console.title = "Connecting to " + serverName.text + ":" + portNumber.text;
console.enabled = true;
}
private function sendCommand():void
{
var ba:ByteArray = new ByteArray();
ba.writeMultiByte(command.text + "\n", "UTF-8");
telnetClient.writeBytesToSocket(ba);
command.text = "";
}
Pierwsza linia kodu importuje klasę Telnet z pakietu com.example.programmingas.socket. Drugi wiersz kodu zawiera deklarację instancji klasy Telnet,
telnetClient
, która zostanie zainicjowana później przez metodę
connect()
. Następnie metoda
connect()
zostaje zadeklarowana i inicjuje zmienną
telnetClient
deklarowaną później. Ta metoda przekazuje nazwę serwera telnet określoną przez użytkownika, port serwera telnet oraz odwołanie do składnika TextArea na liście wyświetlania, która służy do wyświetlania odpowiedzi tekstowych z serwera gniazda. Ostatnie dwie linie metody
connect()
ustawiają właściwość
title
dla składnika Panel i włączają składnik Panel, dzięki czemu użytkownik może wysyłać dane do serwera zdalnego. Ostatnia metoda w pliku aplikacji,
sendCommand()
, służy do wysyłania poleceń użytkownika do serwera zdalnego w postaci obiektu ByteArray.
Przegląd klasy Telnet
Klasa Telnet jest odpowiedzialna za połączenie ze zdalnym serwerem Telnet oraz wysyłanie/odbieranie danych.
Klasa Telnet deklaruje następujące zmienne prywatne:
private var serverURL:String;
private var portNumber:int;
private var socket:Socket;
private var ta:TextArea;
private var state:int = 0;
Pierwsza zmienna,
serverURL
, zawiera adres serwera (określony przez użytkownika), z którym następuje połączenie.
Druga zmienna,
portNumber
, jest numerem portu, na którym aktualnie działa serwer Telnet. Domyślnie usługa Telnet działa na porcie 23.
Trzecia zmienna,
socket
, jest instancją klasy Socket, która będzie podejmowała próby połączenia z serwerem zdefiniowanym przez zmienne
serverURL
i
portNumber
.
Czwarte zmienna,
ta
, jest odwołaniem do instancji składnika TextArea na stole montażowym. Ten składnik jest używany do wyświetlania odpowiedzi ze zdalnego serwera Telnet lub do wyświetlania dowolnych komunikatów o błędach.
Ostatnia zmienna,
state
, jest wartością liczbową, która służy do określania opcji, jakie obsługuje klient Telnet.
Jak przedstawiono wcześniej — funkcja konstruktora klasy Telnet jest wywoływana przez metodę
connect()
w głównym pliku aplikacji.
Konstruktor Telnet przyjmuje trzy parametry:
server
,
port
i
output
. Parametry
server
o
port
określają nazwę serwera i numer portu, na którym działa serwer Telnet. Ostatni parametr,
output
, jest odwołaniem do instancji składnika TextArea na stole montażowym, na którym są wyświetlane dane z serwera.
public function Telnet(server:String, port:int, output:TextArea)
{
serverURL = server;
portNumber = port;
ta = output;
socket = new Socket();
socket.addEventListener(Event.CONNECT, connectHandler);
socket.addEventListener(Event.CLOSE, closeHandler);
socket.addEventListener(ErrorEvent.ERROR, errorHandler);
socket.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
socket.addEventListener(ProgressEvent.SOCKET_DATA, dataHandler);
Security.loadPolicyFile("http://" + serverURL + "/crossdomain.xml");
try
{
msg("Trying to connect to " + serverURL + ":" + portNumber + "\n");
socket.connect(serverURL, portNumber);
}
catch (error:Error)
{
msg(error.message + "\n");
socket.close();
}
}
Zapisywanie danych do gniazda
Aby zapisać dane w połączeniu przez gniazdo, należy wywołać wybraną metodę zapisu w klasie Socket. Do metod zapisu należą metody
writeBoolean()
,
writeByte()
,
writeBytes()
,
writeDouble()
i inne. Następnie należy opróżnić bufor wyjściowy za pomocą metody
flush()
. Na serwerze Telnet dane są zapisywane do połączenia gniazda za pomocą metody
writeBytes()
, która przyjmuje tablicę bajtów jako parametr i wysyła go do buforu wyjściowego. Metodę
writeBytesToSocket()
przedstawiono poniżej:
public function writeBytesToSocket(ba:ByteArray):void
{
socket.writeBytes(ba);
socket.flush();
}
Ta metoda jest wywoływana przez metodę
sendCommand()
głównego pliku aplikacji.
Wyświetlanie komunikatów z serwera gniazda
Gdy komunikat zostanie odebrany z serwera gniazd lub wystąpi zdarzenie, nastąpi wywołanie własnej metody
msg()
. Ta metoda dołącza ciąg znaków do składnika TextArea na stole montażowym i wywołuje niestandardową metodę
setScroll()
, co powoduje przewinięcie składnika TextArea do dołu. Metodę
msg()
przedstawiono poniżej:
private function msg(value:String):void
{
ta.text += value;
setScroll();
}
Jeśli treść składnika TextArea nie została automatycznie przewinięta, użytkownik będzie musiał ręcznie przesunąć paski przewijania w obszarze tekstowym, aby wyświetlić ostatnia odpowiedź z serwera.
Przewijanie składnika TextArea
Metoda
setScroll()
zawiera pojedynczą linię kodu ActionScript, która powoduje przewinięcie treści składnika TextArea w pionie, dzięki czemu użytkownik może wyświetlić ostatnią linię zwróconego tekstu. Poniższy urywek prezentuje metodę
setScroll()
:
public function setScroll():void
{
ta.verticalScrollPosition = ta.maxVerticalScrollPosition;
}
Ta metoda ustawia właściwość
verticalScrollPosition
, która jest numerem najwyższego, aktualnie wyświetlanego wiersza znaków. Właściwości tej przypisywana jest wartość właściwości
maxVerticalScrollPosition
.
Gniazda XML
Gniazdo XML umożliwia utworzenie połączenia ze zdalnym serwerem, który pozostaje otwarty aż do jego jawnego zamknięcia. Możliwa jest wymiana ciągów znaków, takich jak XML, między serwerem a klientem. Zaletą stosowania serwera gniazda XML jest to, że klient nie musi jawnie żądać danych. Serwer może przesyłać dane bez oczekiwania na żądanie i może przesyłać dane do każdego podłączonego klienta.
W programie Flash Player, a także w środowisku Adobe AIR (w treści AIR, która nie znajduje się w obszarze izolowanym aplikacji) połączenia gniazda XML wymagają obecności pliku strategii gniazda na serwerze docelowym. Więcej informacji zawierają sekcje
Internetowe elementy sterujące (pliki zasad)
i
Nawiązywanie połączeń z gniazdami
.
Klasa XMLSocket nie może bezpośrednio tunelować przez zapory. Klasa XMLSocket — w przeciwieństwie do protokołu RTMP (Real-Time Messaging Protocol) nie umożliwia tunelowania HTTP. Jeśli wymagane jest użycie tunelowania HTTP, należy rozważyć użycie serwera Flash Remoting lub serwera Flash Media Server (który obsługuje RTMP).
Poniższe ograniczenia dotyczą sposobu i miejsca w programie Flash Player lub środowisku AIR, w których treść poza bezpiecznym obszarem izolowanym aplikacji może korzystać z obiektu XMLSocket w celu nawiązania połączenia z serwerem:
-
W przypadku treści poza bezpiecznym obszarem izolowanym aplikacji metoda
XMLSocket.connect()
może łączyć się z portami TCP o numerach większych lub równych 1024. Jedną z konsekwencji tego ograniczenia jest to, że demony serwera, które komunikują się z obiektami
XMLSocket
muszą również być przypisane do portów o numerach większych lub równych 1024. Porty o numerach niższych niż 1024 są często używane przez usługi systemowe, takie jak FTP (21), Telnet (23), SMTP (25), HTTP (80) i POP3 (110), dlatego ze względów bezpieczeństwa uniemożliwiono obiektom XMLSocket korzystanie z tych portów. Zabezpieczenia dotyczące numerów portów ograniczają możliwość uzyskania do tych zasobów nieuprawnionego dostępu i ich nadużycia.
-
W przypadku treści poza bezpiecznym obszarem izolowanym aplikacji metoda
XMLSocket.connect()
może łączyć się tylko z komputerami w tych samych domenach, na których znajduje się treść. (To ograniczenie jest identyczne z regułami bezpieczeństwa dla metody
URLLoader.load()
). W celu nawiązania połączenia z demonem serwera, który działa na domenie innej niż domena, w której znajduje się plik treść, można utworzyć plik strategii międzydomenowej na serwerze, który umożliwi dostęp z określonych domen. Szczegółowe informacje na temat plików zasad dotyczących obszarów spoza domeny zawiera sekcja
Zabezpieczenia w środowisku AIR
.
Uwaga:
Ustawienie serwera do komunikowania się z obiektem XMLSocket może stanowić wyzwanie. Jeśli aplikacja użytkownika nie wymaga interakcyjności w czasie rzeczywistym, należy skorzystać z klasy URLLoader zamiast klasy XMLSocket.
W celu przesyłania danych XML do serwera i z serwera przez połączenie gniazda można korzystać z metod
XMLSocket.connect()
i
XMLSocket.send()
klasy XMLSocket. Metoda
XMLSocket.connect()
nawiązuje połączenie przez gniazdo z portem serwera sieci Web. Metoda
XMLSocket.send()
przekazuje obiekt XML do serwera określonego w połączeniu gniazda.
Po wywołaniu metody
XMLSocket.connect()
aplikacja otwiera połączenie TCP/IP z serwerem i utrzymuje połączenie otwarte do czasu wystąpienia jednego z poniższych zdarzeń:
-
Wywołanie metody
XMLSocket.close()
klasy XMLSocket.
-
Brak odwołań do obiektu XMLSocket.
-
Istnieje program Flash Player.
-
Połączenie zostało przerwane (na przykład przez odłączenie modemu).
Łączenie się z serwerem za pomocą klasy XMLSocket
W celu utworzenia połączenia z gniazdem należy utworzyć aplikację serwerową w celu oczekiwania na żądanie połączenia z gniazdem i wysłania odpowiedzi do programu Flash Player lub aplikacji AIR. Ten typ aplikacji serwerowej może zostać napisany w środowisku AIR lub w dowolnym języku programowania, takim jak Java, Python lub Perl. Aby można było skorzystać z klasy XMLSocket, na komputerze serwera musi być uruchomiony demon, który obsłuży prosty protokół używany przez klasę XMLSocket:
-
Wiadomości XML są przesyłane pełnodupleksowym połączeniem gniazda strumienia TCP/IP.
-
Każda wiadomość XML jest kompletnym dokumentem XML zakończonym bajtem zerowym (0).
-
Za pomocą pojedynczego połączenia XMLSocket może zostać przesłana i odebrana nieograniczona liczba wiadomości XML.
Tworzenie serwera gniazd Java XML i nawiązywanie połączenia z takim serwerem
Poniższy kod prezentuje prosty serwer XMLSocket napisany w języku Java, który akceptuje połączenia przychodzące i wyświetla odebrane komunikaty w oknie poleceń. Domyślnie nowy serwer jest tworzony na porcie 8080 komputera lokalnego, ale możliwe jest określenie innego numeru portu w przypadku uruchamiania serwera z wiersza poleceń.
Utwórz nowy dokument tekstowy i dodaj do niego poniższy kod:
import java.io.*;
import java.net.*;
class SimpleServer
{
private static SimpleServer server;
ServerSocket socket;
Socket incoming;
BufferedReader readerIn;
PrintStream printOut;
public static void main(String[] args)
{
int port = 8080;
try
{
port = Integer.parseInt(args[0]);
}
catch (ArrayIndexOutOfBoundsException e)
{
// Catch exception and keep going.
}
server = new SimpleServer(port);
}
private SimpleServer(int port)
{
System.out.println(">> Starting SimpleServer");
try
{
socket = new ServerSocket(port);
incoming = socket.accept();
readerIn = new BufferedReader(new InputStreamReader(incoming.getInputStream()));
printOut = new PrintStream(incoming.getOutputStream());
printOut.println("Enter EXIT to exit.\r");
out("Enter EXIT to exit.\r");
boolean done = false;
while (!done)
{
String str = readerIn.readLine();
if (str == null)
{
done = true;
}
else
{
out("Echo: " + str + "\r");
if(str.trim().equals("EXIT"))
{
done = true;
}
}
incoming.close();
}
}
catch (Exception e)
{
System.out.println(e);
}
}
private void out(String str)
{
printOut.println(str);
System.out.println(str);
}
}
Zapisz dokument na dysku jako SimpleServer.java i skompiluj go za pomocą kompilatora Java, który utworzy plik klasy Java o nazwie SimpleServer.class.
Serwer XMLSocket można otworzyć poprzez otwarcie okna poleceń i wpisanie polecenia
java SimpleServer
. Plik SimpleServer.class może znajdować się w dowolnym miejscu na dysku twardym w komputerze lokalnym lub w sieci; nie musi być umieszczany w katalogu głównym serwera sieci Web.
Jeśli nie można uruchomić serwera, ponieważ pliki nie znajdują się w ścieżce klasy Java, należy podjąć próbę uruchomienia serwera za pomocą ścieżki
java -classpath . SimpleServer
.
W celu nawiązania połączenia z serwerem XMLSocket z poziomu aplikacji należy utworzyć nowe wystąpienie klasy XMLSocket, a następnie wywołać metodę
XMLSocket.connect()
, wprowadzając nazwę hosta i numer portu, tak jak w poniższym przykładzie.
var xmlsock:XMLSocket = new XMLSocket();
xmlsock.connect("127.0.0.1", 8080);
Zawsze po odebraniu danych z serwera wywoływane jest zdarzenie
data
(
flash.events.DataEvent.DATA
):
xmlsock.addEventListener(DataEvent.DATA, onData);
private function onData(event:DataEvent):void
{
trace("[" + event.type + "] " + event.data);
}
W celu wysłania danych do serwera XMLSocket należy użyć metody
XMLSocket.send()
i przekazać obiekt XML lub ciąg znaków. Program Flash Player konwertuje dostarczony parametr na obiekt String i wywyła treść do serwera XMLSocket (na końcu umieszczany jest bajt zerowy (0)):
xmlsock.send(xmlFormattedData);
Metoda
XMLSocket.send()
nie zwraca wartości, która wskazywałaby, czy przesyłanie danych zakończyło się pomyślnie. Jeśli podczas próby wysyłania danych wystąpił błąd, zwracany jest błąd IOError.
Każdy komunikat wysłany do serwera gniazda XML musi być zakończony znakiem nowej linii (
\n
).
Aby znaleźć więcej informacji na ten temat, zobacz:
Obiekt XMLSocket
.
Gniazda serwerowe
Korzystając z klasy ServerSocket, można umożliwić innym procesom nawiązanie połączenia z aplikacją za pośrednictwem gniazda protokołu TCP (Transport Control Protocol). Proces nawiązujący połączenie może działać na komputerze lokalnym lub na innym komputerze podłączonym do sieci. Gdy obiekt ServerSocket odbierze żądanie połączenia, wywołuje zdarzenie
connect
. Obiekt ServerSocketConnectEvent wywoływany razem ze zdarzeniem zawiera obiekt Socket. Tego obiektu Socket można używać do dalszej komunikacji z procesem.
Aby nasłuchiwać połączeń przychodzących przez gniazdo:
-
Utwórz obiekt ServerSocket i powiąż go z portem lokalnym.
-
Dodaj detektory zdarzenia
connect
.
-
Wywołaj metodę
listen()
.
-
Reaguj na zdarzenie
connect
, które zawiera obiekt Socket dla każdego połączenia przychodzącego.
Obiekt ServerSocket nadal nasłuchuje nowych połączeń, dopóki nie zostanie wywołana metoda
close()
.
Poniższy przykładowy kod ilustruje sposób utworzenia aplikacji pełniącej rolę serwera gniazd. W tym przypadku kod nasłuchuje połączeń przychodzących w porcie 8087. Po odebraniu żądania połączenia wysyłany jest odpowiedni komunikat (ciąg znaków "Connected.") do gniazda na kliencie. Od tej chwili serwer odsyła (echo) wszelkie odebrane komunikaty z powrotem do klienta.
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.events.ProgressEvent;
import flash.events.ServerSocketConnectEvent;
import flash.net.ServerSocket;
import flash.net.Socket;
public class ServerSocketExample extends Sprite
{
private var serverSocket:ServerSocket;
private var clientSockets:Array = new Array();
public function ServerSocketExample()
{
try
{
// Create the server socket
serverSocket = new ServerSocket();
// Add the event listener
serverSocket.addEventListener( Event.CONNECT, connectHandler );
serverSocket.addEventListener( Event.CLOSE, onClose );
// Bind to local port 8087
serverSocket.bind( 8087, "127.0.0.1" );
// Listen for connections
serverSocket.listen();
trace( "Listening on " + serverSocket.localPort );
}
catch(e:SecurityError)
{
trace(e);
}
}
public function connectHandler(event:ServerSocketConnectEvent):void
{
//The socket is provided by the event object
var socket:Socket = event.socket as Socket;
clientSockets.push( socket );
socket.addEventListener( ProgressEvent.SOCKET_DATA, socketDataHandler);
socket.addEventListener( Event.CLOSE, onClientClose );
socket.addEventListener( IOErrorEvent.IO_ERROR, onIOError );
//Send a connect message
socket.writeUTFBytes("Connected.");
socket.flush();
trace( "Sending connect message" );
}
public function socketDataHandler(event:ProgressEvent):void
{
var socket:Socket = event.target as Socket
//Read the message from the socket
var message:String = socket.readUTFBytes( socket.bytesAvailable );
trace( "Received: " + message);
// Echo the received message back to the sender
message = "Echo -- " + message;
socket.writeUTFBytes( message );
socket.flush();
trace( "Sending: " + message );
}
private function onClientClose( event:Event ):void
{
trace( "Connection to client closed." );
//Should also remove from clientSockets array...
}
private function onIOError( errorEvent:IOErrorEvent ):void
{
trace( "IOError: " + errorEvent.text );
}
private function onClose( event:Event ):void
{
trace( "Server socket closed by OS." );
}
}}
Więcej informacji:
Gniazda UDP (AIR)
Protokół UDP (Universal Datagram Protocol) umożliwia wymianę komunikatów za pośrednictwem bezstanowego połączenia sieciowego. Protokół UDP nie daje żadnej gwarancji, że komunikaty zostaną dostarczone w kolejności, w jakiej zostały wysłane, ani że w ogóle zostaną dostarczone. W przypadku użycia protokołu UDP oprogramowanie sieciowe systemu operacyjnego poświęca mniej czasu na zestawianie, śledzenie i potwierdzanie komunikatów. Dlatego komunikaty UDP zwykle docierają do aplikacji docelowej z mniejszymi opóźnieniami niż komunikaty TCP.
Komunikacja przez gniazda UDP jest przydatnym rozwiązaniem, gdy zachodzi konieczność przesyłania informacji w czasie rzeczywistym — np. uaktualnień pozycji w grze lub pakietów dźwiękowych w aplikacji do rozmowy głosowej. W takich zastosowaniach utrata części danych jest dopuszczalna, a małe opóźnienia transmisji są ważniejsze niż gwarancja dotarcia danych do celu. Praktycznie we wszystkich innych zastosowaniach lepszym rozwiązaniem jest użycie gniazd TCP.
Aplikacja AIR może wysyłać i odbierać komunikaty UDP za pośrednictwem klas DatagramSocket i DatagramSocketDataEvent. Aby wysłać lub odebrać komunikat UDP:
-
Utwórz obiekt DatagramSocket.
-
Dodaj detektor zdarzenia
data
.
-
Powiąż lokalny adres IP i port za pomocą metody
bind()
.
-
W celu wysłania komunikatu wywołaj metodę
send()
, przekazując adres IP i numer portu komputera docelowego.
-
Aby odbierać komunikaty, należy reagować na zdarzenie
data
. Obiekt DatagramSocketDataEvent wywoływany w związku z tym zdarzeniem zawiera obiekt ByteArray z danymi komunikatu.
Poniższy przykładowy kod ilustruje wysyłanie i odbieranie komunikatów UDP. W przykładzie do komputera docelowego wysyłany jest jeden komunikat zawierający ciąg znaków "Hello". Ponadto wyświetlana jest treść wszelkich odbieranych komunikatów.
package
{
import flash.display.Sprite;
import flash.events.DatagramSocketDataEvent;
import flash.events.Event;
import flash.net.DatagramSocket;
import flash.utils.ByteArray;
public class DatagramSocketExample extends Sprite
{
private var datagramSocket:DatagramSocket;
//The IP and port for this computer
private var localIP:String = "192.168.0.1";
private var localPort:int = 55555;
//The IP and port for the target computer
private var targetIP:String = "192.168.0.2";
private var targetPort:int = 55555;
public function DatagramSocketExample()
{
//Create the socket
datagramSocket = new DatagramSocket();
datagramSocket.addEventListener( DatagramSocketDataEvent.DATA, dataReceived );
//Bind the socket to the local network interface and port
datagramSocket.bind( localPort, localIP );
//Listen for incoming datagrams
datagramSocket.receive();
//Create a message in a ByteArray
var data:ByteArray = new ByteArray();
data.writeUTFBytes("Hello.");
//Send the datagram message
datagramSocket.send( data, 0, 0, targetIP, targetPort);
}
private function dataReceived( event:DatagramSocketDataEvent ):void
{
//Read the data from the datagram
trace("Received from " + event.srcAddress + ":" + event.srcPort + "> " +
event.data.readUTFBytes( event.data.bytesAvailable ) );
}
}}
Korzystając z gniazd UDP, należy brać pod uwagę następujące uwarunkowania:
-
Pojedynczy pakiet danych nie może być większy od maksymalnej jednostki transmisji (MTU) interfejsu sieciowego i węzłów sieciowych między nadawcą a odbiorcą. Wszystkie dane z obiektu ByteArray przekazanego do metody send() są wysyłane jako pojedynczy pakiet. (W przypadku protokołu TCP duże komunikaty są dzielone na mniejsze pakiety.)
-
Nie odbywa się uzgadnianie protokołu między nadawcą a węzłem docelowym. Jeśli węzeł docelowy nie istnieje lub nie nasłuchuje aktywnie w określonym porcie, komunikaty są odrzucane bez zgłaszania błędu.
-
W wypadku użycia metody
connect()
komunikaty wysyłane z innych źródeł są ignorowane. Połączenie UDP pełni jedynie rolę filtru pakietów. Nawiązanie go nie oznacza, że pod docelowym adresem i numerem portu istnieje poprawny, nasłuchujący proces.
-
Ruch UDP może nadmiernie obciążyć sieć. W razie występowania natłoku komunikatów w sieci administratorzy mogą być zmuszeni do wprowadzenia mechanizmów wymuszania jakości usług (QoS). (Protokół TCP ma wbudowany mechanizm kontroli ruchu, który ogranicza ryzyko nadmiernego obciążenia sieci.)
Więcej informacji:
Adresy IPv6
Program Flash Player 9.0.115.0 i jego późniejsze wersje obsługują protokół IPv6 (Internet Protocol, wersja 6). IPv6 jest wersją protokołu internetowego obsługującą adresy 128-bitowe (wcześniejsza wersja protokołu IPv4 obsługuje adresy 32-bitowe). Może zaistnieć potrzeba aktywowania protokołu IPv6 w interfejsach sieciowych użytkownika. Aby uzyskać więcej informacji, należy zapoznać się z pomocą systemu operacyjnego przechowującego dane.
Jeśli protokół IPv6 jest obsługiwany przez system operacyjny, wówczas numeryczną wartość adresów protokołu IPv6 objętych nawiasami kwadratowymi ([]) można określić w adresach URL tak, jak w poniższym przykładzie:
[2001:db8:ccc3:ffff:0:444d:555e:666f]
Program Flash Player zwraca literałowe wartości IPv6 zgodnie z następującymi regułami:
-
Program Flash Player zwraca długą formę ciągu znaków dla adresów IPv6.
-
Wartość IP nie zawiera skrótów z dwoma dwukropkami.
-
Wartości szesnastkowe występują tylko w postaci małych liter.
-
Adresy IPv6 są zawarte w nawiasach kwadratowych ([]).
-
Każdy kwartet adresu jest wysyłany w postaci znaków szesnastkowych (od 0 do 4), a zera początkowe są pomijane.
-
Kwartet adresu zawierający same zera jest wysyłany jako pojedyncze zero (nie podwójny dwukropek) z wyjątkiem sytuacji z poniższej listy.
Dla wartości IPv6, które są zwracane przez program Flash Player, obowiązują następujące wyjątki:
-
Nieokreślony adres IPv6 (same zera) jest wyświetlany jako [::].
-
Adres IPv6 pętli zwrotnej lub hosta lokalnego jest wyświetlany jako [::1].
-
Odwzorowane adresy IPv4 (po konwersji na IPv6) są wyświetlane jako [::ffff:a.b.c.d], gdzie a.b.c.d jest typową notacją IPv4 w postaci dziesiętnej z kropkami.
-
Kompatybilne adresy IPv4 są wyświetlane jako [::a.b.c.d], gdzie a.b.c.d jest typową notacją IPv w postaci dziesiętnej z kropkami.
|
|
|
|
|