środa, 31 sierpnia 2011

Packet Tracer: Network Address Translation

 NAT czyli Network Address Translation tak naprawdę umożliwia większości z nas dostęp do Internetu. To właśnie dzięki niemu nasz lokalny adres IP (np. 192.168.1.111) jest tłumaczony na adres globalny, który to widzą np. serwery sieciowe. Jednak to co jest ważniejsze to fakt, że NAT (a raczej PAT) umożliwia wielu urządzeniom jednoczesną komunikację z "zewnętrznym światem" przy użyciu pojedynczego globalnego adresu IP.

Jednak nic tak nie wspomaga nauki jak bodźce wizualne :) Dlatego też przygotowałem taki mały projekt sieci wykorzystującej różne odmiany mechanizmu NAT:

A jak sama translacja działa w praktyce? Router przy wykorzystaniu tablicy translacji podmienia docelowy/źródłowy (w zależności od kierunku przesyłania) adres IP w nagłówku pakietu, dzięki czemu odzwierciedla on aktualną "przestrzeń adresów". By lepiej zrozumieć polecam krótką prezentację w formie filmiku.



A jak taka tablica translacji wygląda? Cóż możemy ją obejrzeć wpisując w konsoli w trybie uprzywilejowanym (#) polecenie:
show ip nat translations



Nim jednak przejdziemy do omówienia tych różnych odmian translacji to słów parę o ogólnej konfiguracji routera. Otóż by NAT w ogóle chciał działać konieczne jest określenie, który interfejs jest "wewnątrz" (inside), a który "na zewnątrz" (outside) sieci, której adresy chcemy tłumaczyć. Informację tą przekazujemy routerowi wpisując w konfiguracji interfejsów kolejno
ip nat inside
dla interfejsu wewnętrznego oraz
ip nat outside
dla interfejsu zewnętrznego.

Po ustawieniu tej podstawowej informacji możemy zacząć konfigurację sposobu translacji.

Statyczna translacja adresów sieciowych
Jest to odmiana translacji, w której każdy wpis musi zostać ustawiony ręcznie. Z tego też powodu w zastosowaniach życia codziennego metoda ta nadaje się jedynie do udostępnienia "na zewnątrz" serwerów lub innych urządzeń, z którymi chcemy nawiązywać łączność z maszyn znajdujących się poza naszą siecią.

Konfiguracja:
ip nat inside source static (IP wewnętrzny) (IP zewnętrzny)
ip nat inside source static (tcp/udp) (IP wewnętrzny) (port wewnętrzny) (IP zewnętrzny) (port zewnętrzny)

Wydruk z tablicy translacji:
Warte zauważenia jest to, że komunikaty pochodzące z jednego komputera używają tego samego adresu IP globalnego. Dodatkowo na końcu wydruku pojawia się de facto lista zdefiniowanych translacji statycznych (zaznaczona na zielono).

NAT z PAT
NAT z PAT to domyślny sposób translacji umożliwiający łączenie się przez jeden adres IP przez wiele maszyn.

Konfiguracja składa się z dwóch etapów. Napoczątku należy utworzyć listę dostępu, która będzie mówić routerowi, które adresy należy tłumaczyć (oczywiście można użyć rozszerzonych list ACL):
access-list (numer listy) permit any
Po jej utworzeniu możemy już ustawić samą translację:
ip nat inside source list (numer list) interface (nazwa interfejsu) overload
Warto zauważyć, że jeśli nie podamy słówka "overload" to Packet Tracer i tak je automatycznie doda do konfiguracji (dotyczy to jednak tylko definiowania NAT z wykorzystaniem interfejsu).

Wydruk z tablicy translacji:
 Jak widać wszystkie maszyny lokalne używają tego samego adresu IP (czerwony kolor), ale różnych numerów portów (zielony).

NAT z PAT przy użyciu wielu adresów IP
Podobnie jak w powyższej metodzie tak i tu wiele maszyn może korzystać z jednego zewnętrznego adresu IP. To co jest "nowego" to właśnie mnogość adresów, które są wykorzystywane, gdy pierwszemu zabranie wolnych portów.

Konfiguracja składa się z trzech etapów.  Poza omówioną powyżej konfiguracją listy dostępu musimy jeszcze utworzyć pulę adresów IP, które router będzie mógł przydzielać:
ip nat pool (nazwa puli) (początkowy adres IP) (końcowy adres IP) netmask (maska podsieci)
Samą translację zaś konfigurujemy następująco:

ip nat inside source list (numer listy) pool (nazwa puli) overload

Wydruk z tablicy translacji jest praktycznie taki sam jak przy NAT z PAT. Jedyna różnica polega na tym, że gdy skończą się wolne porty na pierwszym adresie IP to router zaczyna używanie kolejnego adresu z puli.

NAT przy użyciu wielu adresów IP
Ta metoda jest w zasadzie podobna do poprzednich, z tą różnicą, że tutaj każda maszyna używa tylko jednego adresu IP. Można zatem powiedzieć, że jest to taki dynamiczny odpowiednik zwykłej statycznej translacji.

Konfiguracja wygląda identycznie jak w przypadku powyższym (NAT z PAT z wieloma adresami). Jedyna zmiana to brak słówka "overload":
ip nat inside source list (numer listy) pool (nazwa puli)

Wydruk z tablicy translacji:
 Tablica translacji jak widać jest bardzo podobna do tej ze statycznego tłumaczenia adresów i różni się jedynie tym, że przed wykonaniem translacji nie mamy możliwości stwierdzenia, który adres globalny zostanie przypisany do danego adresu lokalnego.


Chcących przetestować działanie NAT na "żywym" organizmie zapraszam do pobrania pliku z konfiguracją sieci: link (PT wersja 5.3)

wtorek, 30 sierpnia 2011

Dithering

Tak się jakoś złożyło, że przez ostatnie dni zagłębiłem się w tematykę ditheringu. Cóż implementacja algorytmów sama w sobie nie jest ciężka i po prawdzie przynosi ogrom radości, gdy w końcu udaje się wygenerować w miarę podobny do pierwowzoru obraz :P
Tak czy inaczej w celu uproszczenia programu używałem plików PGM/PBM.

Ale czym jest sam dithering? W skrócie to jest to taka transformacja obrazu by przy mniejszej palecie kolorów dawał złudzenie większej palety, czy jak kto woli - najbardziej przypominał on pierwowzór.
Innymi słowy chodzi o to by np. taki 8 bitowy/px obraz (256 kolorów)
Orginal grayscale picture
Po redukcji do 1 bita na piksel (2 kolory) nie wyglądał tak:
Threshold dithering
ale np. tak:
Ordered dithering
Floyd-Steinberg combined with ordered dithering
Floyd-Steinberg combined with ordered dithering and negative error propagation
Prawda, że widać różnicę? Algorytmów do ditheringu jest cała masa i mimo iż niegdyś używano ich prawie jedynie do przełamywania technologicznych ograniczeń (np. wyświetlacze o małej gamie barw) to obecnie używa się ich również w artystycznym ujęciu. Ot choćby obraz wektorowy poddany ditheringowi może okazać się ciekawszy dla widza niż przed taką obróbką (ludzie to takie dziwne stworzenia co nie lubią wyraźnych konturów i jednolitych powierzchni).

niedziela, 28 sierpnia 2011

Łączenie ciągów tekstowych

Chyba jednym z najpowszechniejszych działań w PHP jest łączenie różnej maści ciągów. Czy to przy budowaniu zapytań do bazy, czy też przy generowaniu treści do wyświetlenia. Jednak czy zastanawialiście się nad różnicami w sposobie łączenia ciągów? W tym wpisie porównam metodę doklejania kolejnych elementów za pomocą ".", dołączania wartości zmiennych przy pomocy "{$var}" oraz działanie funkcji sprintf. A na koniec porównam wydajność rzutowań bezpośrednich oraz konwersji z użyciem sprintfa.

Na początek mały test pokazujący różnice pomiędzy pustymi sprintf, "" oraz ''.

Sprintf:	    5.5083110332
" ":		    1.8283259869
' ':		    1.7890319824

oraz sam test dla "" i '':

" ":	    1.1731438637
' ':	    1.1480429173
" ":	    1.1413729191
' ':	    1.1829788685

Jak widać różnice w wydajności pomiędzy "" a '' są praktycznie nieistniejące, natomiast sprintf wykonuje się 3 razy dłużej.
Porównajmy zatem wydajność przy dołączaniu tekstu zapisanego w zmiennej pomiędzy inne elementy.

Sprintf:	7.5031311511993
" "." ":	2.9455320835114
" ":		3.1112060546875
{ }:		3.1566998958588

Wyniki te kolejno odnoszą się do kodu:
$temp = sprintf("prefix %s postfix",$text);
$temp = "prefix ".$text." postfix";
$temp = "prefix $text postfix";
$temp = "prefix {$text} postfix";

Okazuje się, że najszybciej działa łączenie kolejnych niezależnych ciągów, następnie w szeregu wydajności znajdują się metody "na skróty", a na końcu wywołanie funkcji sprintf.

Na sam koniec zostawiłem porównanie wydajności rzutowań na typy liczbowe - integer i float. Wyniki prezentują się następująco:
Sprintf %d:	    0.7861609459	666
Sprintf %u:	    0.7842721939	666
Sprintf %f:	    1.2757029533	666.999000
(int):		    0.2504780293	666
(float):	    0.2895848751	666.999

Funkcja sprintf znowu jest trzykrotnie, a w przypadku rzutowania na float ponad czterokrotnie wolniejszy. Jednak sytuacja ta zmienia się diametralnie gdy zaczynamy tworzyć ciąg składający się z wielu zmiennych:
Sprintf %d %f:		    6.8353290558
Sprintf %1$d %2$f:	    7.3985271454
(int), (float)		    8.1965639591

Wyniki te odpowiadają kodowi:
$temp = sprintf("%d %f %d",$numeric, $float, $int);
$temp = sprintf('%1$d %2$f %3$d',$numeric, $float, $int);
$temp = (int)$numeric." ".(float)$float." ".(int)$int;

Przy tworzeniu rozbudowanych ciągów tekstowych jednak warto użyć funkcji sprintf. Jednak z drugiej strony przy pojedynczych zmiennych o wiele lepiej używać bezpośredniego rzutowania. To na co również warto zwrócić uwagę to fakt, że odnoszenie się do zmiennych poprzez %1$, %2$ itd. mimo iż jest z pewnością szybsze do napisania to jednak działa nieco wolniej od bezpośredniego podawania każdego z parametrów (nawet jeśli musimy je podawać wielokrotnie w jednym wywołaniu funkcji).

Wykorzystany kod do testowania można pobrać jak zwykle z mojego chomika (link).

piątek, 5 sierpnia 2011

Dostęp do prywatnych pól klas przodków w PHP

Ten wpis jest w zasadzie rozszerzeniem poprzedniego wpisu. To co tutaj zostanie omówione to stricte dostęp do pól prywatnych danej klasy, jak i również troszkę bardziej rozbudowany przykład wykorzystania klas z rodziny Reflection.

Jak można było zauważyć w poprzednim wpisie funkcja get_object_vars() realizuje de facto zadanie pobrania wartości i nazw pól klas. Jej wadą jest jednak niemożność dojścia do metod prywatnych przodków naszej klasy i właśnie w celu dodania tej funkcjonalności niezbędne okażą się klasy Reflection.

Na początek przypomnijmy jednak sobie naszą hierarchię klas...
class First
{
    private $firstPrivate;
    protected $firstProtected;
    public $firstPublic="DEFAULT";
}

class Second extends First
{
    private $secondPrivate;
    protected $secondProtected;
    public $secondPublic;
}

class Third extends Second
{
    private $thirdPrivate;
    protected $thirdProtected;
    public $thirdPublic;
}

Aby dobrać się do metod prywatnych potrzebujemy o wiele bardziej rozbudowanego kodu niż ten umieszczony w poprzednim wpisie, oraz rekurencji koniecznej do przejścia po grafu dziedziczenia klas.
Takim chyba najprostszym przykładem pobrania wartości wszystkich parametrów jest funkcja:
function getAllFields($object)
{
    $globalFields = array();
    $reflectionClass = new ReflectionClass($object);
    do
    {
        $reflections = $reflectionClass->getProperties();

        foreach($reflections as $reflectionProperty)
        {
            $reflectionProperty->setAccessible(true);
            $globalFields[$reflectionProperty->name] = $reflectionProperty->getValue($object);
        }
        $reflectionClass = $reflectionClass->getParentClass();
    }
    while($reflectionClass);
    return $globalFields;
}
dająca taki oto rezultat
Array
(
    [thirdPrivate] => 
    [thirdProtected] => 
    [thirdPublic] => NEW
    [secondProtected] => 
    [secondPublic] => 
    [firstProtected] => 
    [firstPublic] => DEFAULT
    [secondPrivate] => 
    [firstPrivate] => NEW PRIVATE
)
Funkcję ta jednak ma główną wadę w postaci nadpisywania zmiennych klas bliższych badanemu obiektowi przez zmienne jego przodków. Na szczęście można tą funkcję dowolnie rozwijać i sprawić by generowała wszelkie informacje dotyczące badanej klasy:
function getAllFieldsStrict($object)
{
    $globalFields = array();
    $reflectionClass = new ReflectionClass($object);
    do
    {
        $reflections = $reflectionClass->getProperties();

        foreach($reflections as $reflectionProperty)
        {
            if($reflectionProperty->getDeclaringClass()->name == $reflectionProperty->name)
            {
                switch(true)
                {
                    case $reflectionProperty->isPrivate(): $globalFields[$reflectionProperty->name][$reflectionProperty->name]['access'] = 'private'; break;
                    case $reflectionProperty->isProtected(): $globalFields[$reflectionProperty->name][$reflectionProperty->name]['access'] = 'protected'; break;
                    case $reflectionProperty->isPublic(): $globalFields[$reflectionProperty->name][$reflectionProperty->name]['access'] = 'public'; break;
                }
                $reflectionProperty->setAccessible(true);
                $globalFields[$reflectionProperty->name][$reflectionProperty->name]['value'] = $reflectionProperty->getValue($object);
                $globalFields[$reflectionProperty->name][$reflectionProperty->name]['static'] = $reflectionProperty->isStatic();
            }
        }
        $reflectionClass = $reflectionClass->getParentClass();
    }
    while($reflectionClass);
    return $globalFields;
}
czego rezultatem jest
Array
(
    [Third] => Array
        (
            [thirdPrivate] => Array
                (
                    [value] => 
                    [static] => 
                    [access] => private
                )
            [thirdProtected] => Array
                (
                    [value] => 
                    [static] => 
                    [access] => protected
                )
            [thirdPublic] => Array
                (
                    [value] => NEW
                    [static] => 
                    [access] => public
                )
        )
    [Second] => Array
        (
            [secondPrivate] => Array
                (
                    [value] => 
                    [static] => 
                    [access] => private
                )
            [secondProtected] => Array
                (
                    [value] => 
                    [static] => 
                    [access] => protected
                )
            [secondPublic] => Array
                (
                    [value] => 
                    [static] => 
                    [access] => public
                )
        )
    [First] => Array
        (
            [firstPrivate] => Array
                (
                    [value] => NEW PRIVATE
                    [static] => 
                    [access] => private
                )
            [firstProtected] => Array
                (
                    [value] => 
                    [static] => 
                    [access] => protected
                )
            [firstPublic] => Array
                (
                    [value] => DEFAULT
                    [static] => 
                    [access] => public
                )
        )
)
Wydajność
get_object_vars:  0.28459501266479
getAllFields:   4.3010709285736
getAllFieldsStrict:  4.3191359043121
Podczas testu wykonano każde z zapytań 100000 razy i jak widać wygenerowanie rozbudowanej struktury klas zajmuje praktycznie tyle samo czasu co stworzenie prostszej. Mimo wszystko jednak generowanie trwa ok. 15 razy dłużej w porównaniu do wyciągnięcia informacji za pomocą get_object_vars(), dlatego też jeśli potrzebujemy dostać się do zmiennych klas i mamy możliwość deklarowania pól jako protected a nie private - to zdecydowanie lepiej tak zrobić i używać get_object_vars().

Przykładowy kod do testowania można pobrać z mojego chomika (link).

czwartek, 4 sierpnia 2011

Listowanie nazw pól klasy w PHP

Chcąc dobrać się do zmiennych klasy - ich nazw oraz ewentualnie wartości - dokopałem się do trzech sposobów. Dwa z nich (get_class_vars() i get_object_vars()) pochodzą jeszcze z czasów strukturalnego pisania kodu, zaś trzeci (ReflectionClass) jest już cudem współczesnego przerośniętego obiektowego PHP5.

No ale przechodząc do rzeczy, a właściwie do przykładu obrazującego o co mi chodzi :)

class First
{
    private $firstPrivate;
    protected $firstProtected;
    public $firstPublic="DEFAULT";
}

class Second extends First
{
    private $secondPrivate;
    protected $secondProtected;
    public $secondPublic;
}

class Third extends Second
{
    private $thirdPrivate;
    protected $thirdProtected;
    public $thirdPublic;
}
Otóż mamy 3 klasy, a w każdej z nich 3 zmienne - private, protected i public... Na początku miałem nadzieję, że uda się dobrać do nich wszystkich, jednak okazało się, że do pól prywatnych można dostać się jedynie z kontekstu tej samej klasy - tak więc musiałbym w każdej klasie umieszczać dedykowany kod (lub użyć przerośniętej funkcji działającej w oparciu o Reflection), a takie rozwiązanie w grę nie wchodziło :x Tak więc poświęciłem prywatne zmienne i zamieniłem je na protected i ten problem zniknął ^.^

Pobieranie nazw parametrów
Jednak wracając do zagadnienia - samo uzyskanie nazw zmiennych jest dość banalne i można je osiągnać choćby dzięki dowolnej z poniższych metod:

function getClassVars()
{
    return get_class_vars(get_class($this));
}

function getObjectVars()
{
    return get_object_vars($this);
}

function reflectionGetDefaultProperties()
{
    $reflectionClass = new ReflectionClass($this);
    return $reflectionClass->getDefaultProperties();
}

function reflectionGetProperties()
{
    $reflectionClass = new ReflectionClass($this);
    return $reflectionClass->getProperties();
}

3 pierwsze z nich zwracają tablicę, w której klucze elementów mają nazwę parametrów, a wartości do tych kluczy przypisane równe są wartościom obiektów. Tylko, że tutaj uwaga, gdyż get_class_vars() oraz ->getDefaultProperties zwracają jedynie wartości na sztywno przypisane (domyślne) w kodzie do poszczególnych zmiennych, a nie aktualne wartości tych zmiennych w instancji obiektu.

Tak więc po wykonaniu kodu:

class First
{
    private $firstPrivate;
    protected $firstProtected;
    public $firstPublic="DEFAULT";
    static $firstStatic = "STATIC";

/** metody identyczne do podanych w poprzednim przykładzie */
 function getClassVars() {...}
 function getObjectVars() {...}
 function reflectionGetDefaultProperties() {...}
 function reflectionGetProperties() {...}
}

$object = new A();
$object->firstPublic = "NEW";

print_r($d->getClassVars());
print_r($d->getObjectVars());
print_r($d->reflectionGetDefaultProperties());
print_r($d->reflectionGetProperties());
otrzymamy:
Array
( 
    [firstStatic] => STATIC
    [firstPrivate] => 
    [firstProtected] => 
    [firstPublic] => DEFAULT
)
Array
(
    [firstPrivate] => 
    [firstProtected] => 
    [firstPublic] => NEW
)
Array
(
    [firstPrivate] => 
    [firstProtected] => 
    [firstPublic] => DEFAULT
    [firstStatic] => STATIC
)
Array
(
    [0] => ReflectionProperty Object
        (
            [name] => firstPrivate
            [class] => First
        )

    [1] => ReflectionProperty Object
        (
            [name] => firstProtected
            [class] => First
        )

    [2] => ReflectionProperty Object
        (
            [name] => firstPublic
            [class] => First
        )

    [3] => ReflectionProperty Object
        (
            [name] => firstStatic
            [class] => First
        )
)

Jednak jeśli zależy nam tylko na nazwach zmiennych to generalnie nie ma wielkiej różnicy w wybranej metodzie. Poza tym jak widać ostatnia metoda (->getProperties) zwraca nam obiekty klasy ReflectionProperty.. ale o tym w innym wpisie. Warto jeszcze wspomnieć o tym, że get_object_vars() nie zwraca statycznych pól klasy, ale po co nam one jeśli chodzi nam o stan konkretnej instancji obiektu?
Wydajność
Generalnie jeśli zależy nam jedynie na uzyskaniu nazw parametrów to dlaczego by nie wybrać najszybszej metody? Testy przeprowadziłem na hostingu ovh (większa stabilność wyników niż przy testowaniu na własnym kompie):

get_class_vars:   3.3929491043091
get_object_vars:   2.7406477928162
->getDefaultProperties:  3.6021101474762
->getProperties:   8.8276469707489

Test polegał na wykonaniu pętli
for ($i = 0; $i < 1000000; $i++){ $d->bref(); }
dla każdego z zapytań i zmierzenie czasu za pomocą funkcji microtime(true). Jak widać po wynikach najszybciej działa funkcja get_object_vars(), a najwolniejsze w użyciu są klasy z rodziny Reflection. Oczywiście w przypadku wpisania nazwy klas na sztywno (literka s przy opisie) zamiast używania get_class() wyniki są trochę lepsze (wyniki w dwóch zestawach gdyż sumarycznie przekraczają 30 sekundowy maksymalny czas wykonania skryptu):

get_class_vars:   3.3419530391693
get_class_vars (s):   3.0308630466461
get_object_vars:   2.6966669559479

get_object_vars:   2.6544170379639
->getDefaultProperties:  3.5368349552155
->getDefaultProperties (s):  3.5258779525757
->getProperties:   8.8363699913025
->getProperties (s):   8.7472901344299 

Co ciekawe najbardziej na tej zmianie zyskuje get_class_vars().

Przykładowy kod do przeprowadzenia testów można pobrać (jak zawsze) z mojego chomika (link).