java_programowanie_sieciowe.pdf

(361 KB) Pobierz
Microsoft Word - roz_8.doc
Jacek Rumi ń ski - J ę zyk JAVA – Rozdzia ł 8
Rozdział 8 Integracja Javy z innymi językami - JNI.
Programowanie sieciowe
8. 1 . 1 Obs ł uga metod rodzimych w kodzie Javy
8. 1 .2 Kompilacja i generacja plików nag ł ówkowych
8. 1 .3 Implementacja metody rodzimej - funkcja a
biblioteka
8. 1 .4 Dost ę p do metod i pól zdefiniowanych w Javie
8.2 Programowanie sieciowe
8.2. 1 Adresowanie komputerów w sieci (InetAddress i URL)
8.2.2 Komunikacja przez Internet (klient-serwer)
8.3 Serwlety
8.3. 1 Model obs ł ugi wiadomo ś ci
8.3.2 Ś rodowisko wykonywania serwletów
8.3.3 Kontrola ś rodowiska wymiany wiadomo ś ci
8.3.4 Metody wywo ł ywania serwletów
8.3.5 Obs ł uga protoko ł u HTTP – pakiet
javax.servlet.http.*
8.3.6 Bezpiecze ń stwo serwletów
8.4 Zdalne wywo ł ywanie metod - RMI
8.4. 1 Typy obiektów i relacje pomi ę dzy nimi w RMI
8.4.2 Komunikacja w procesie zdalnego wykonywania metod
8.4.3 Konstrukcja obiektu zdalnego – oprogramowanie
serwera
8.4.4 Oprogramowanie klienta
8.4.5 Uruchamianie systemu.
8.1 Integracja Javy z innymi językami - Java Native Interface (JNI)
Tworząc programy w środowisku języka programowania Java napotyka się
czasami na ograniczenia związane z dostępem do specyficznych dla danej platformy
cech. Konieczne jest wówczas zastosowanie narzędzi obsługujących te cechy a
następnie zaimplementowanie tych narządzi w kodzie programu tworzonego w Javie.
Operacja taka jest możliwa poprzez wykorzystanie swoistego interfejsu pomiędzy
kodem w Javie a kodem programu stworzonego w innym środowisku, np. C lub C++.
Co więcej wykorzystanie istniejących już funkcji (napisanych wcześniej w innych
językach programowania niż Java) może znacznie uprościć tworzenie nowej aplikacji
w Javie, szczególnie wtedy gdy liczy się czas. Interfejs umożliwiający to specyficzne
połączenie kodów został nazwany Java Native Interface, lub w skrócie JNI. Każda
funkcja napisana w innym języku niż Java a implementowana bezpośrednio w kodzie
Javy nosi nazwę metody rodzimej („native method”) i wymaga jawnej,
sformalizowanej deklaracji. Metody rodzime mogą wykorzystywać obiekty Javy tak,
jak to czynią metody tworzone w Javie, a więc tworzyć obiekty, używać je oraz
modyfikować. Aby funkcjonalność metod rodzimych była pełna metody te mogą
wywoływać metody tworzone w Javie, przekazywać im parametry i pobierać wartości
lub referencje zwracane przez te metody. Możliwa jest również obsługa wyjątków
metod rodzimych.
Czym jest więc JNI? JNI to interfejs zawierający:
generator pliku nagłówkowego metody rodzimej (np. javah -jni);
formalizację deklaracji metody rodzimej,
definicję i rzutowanie typów danych,
8-3
Jacek Rumi ń ski - J ę zyk JAVA –
8. 1 Integracja Javy z innymi j ę zykami - Java Native Interface
(JNI)
plik nagłówkowy środowiska rodzimego (np. plik jni.h dla środowiska C);
Jacek Rumi ń ski - J ę zyk JAVA – Rozdzia ł 8
zbiór metod (funkcji) umożliwiających wymianę danych i ustawianie stanów (np.
wyjątków, monitora, itp.).
Implementacja JNI polega najprościej na wykonaniu następujących działań:
1. stworzenie programu w Javie zawierającego deklarację metody rodzimej (native);
2. kompilacja programu;
3. generacja pliku nagłówkowego środowiska rodzimego dla klasy stworzonego
programu (javah -jni);
4.stworzenie implementacji metody rodzimej z wykorzystaniem plików
nagłówkowych interfejsu JNI i klasy stworzonego programu ;
5. kompilacja metody rodzimej i umieszczenie jej w bibliotece;
6. uruchomienie programu korzystającego z metody rodzimej poprzez ładowanie
biblioteki.
8.1.1 Obsługa metod rodzimych w kodzie Javy
Pierwszym krokiem w implementacji interfejsu JNI jest stworzenie kodu w
Javie obsługującego metody rodzime. Najprostsza struktura obsługi może wyglądać
następująco:
Przykład 8.1:
//Informacje.java:
class Informacje{
//deklaracja metody rodzimej
public native int infoSystemu(String parametr);
//ładowanie biblioteki zawierającej implementację metody rodzimej
static{
}
System.loadLibrary(”sysinfo”);
//wykorzystanie metody rodzimej
public static void main(String args[]){
Informacje i = new Informacje();
int status = i.infoSystemu(”CZAS”);
}
}// koniec class Informacje
Powyższy szkic stosowania metod rodzimych zawiera trzy bloki. Pierwszy z nich
deklaruje metodę rodzimą, która różni się od pozostałych metod tym, że używany jest
specyfikator „native” w deklaracji. Drugi blok to kod statyczny ładowany przy
interpretowaniu (kompilacji) kodu bajtów pobierający bibliotekę przechowujący
realizację metody rodzimej. Ostatni blok to zastosowanie metody rodzimej.
Zadeklarowanie metody jako „native” oznacza, że kompilator ma uznać daną metodę
jako rodzimą zdefiniowaną i zaimplementowaną poza Javą. Podana w deklaracji
metody rodzimej nazwa jest odwzorowywana później na nazwę funkcji w kodzie
rodzimym zgodnie z regułą:
nazwa -> Java_NazwaPakietu_NazwaKlasy_nazwa, czyli np.
8-4
Jacek Rumi ń ski - J ę zyk JAVA –
Jacek Rumi ń ski - J ę zyk JAVA – Rozdzia ł 8
infoSystemu -> Java_Informacje_infoSystemu, (brak nazwy pakietu, gdyż klasa
Informacje zawiera się w pakiecie domyślnym, który nie posiada nazwy).
Wykorzystanie bibliotek, w których znajduje się realizacja metod rodzimych wymaga,
aby biblioteki te były dostępne dla uruchamianego programu, tzn. musi być
odpowiednio ustalona ścieżka dostępu.
8.1.2 Kompilacja i generacja plików nagłówkowych
Kompilacja kodu Javy wykorzystującego metody rodzime odbywa się tak samo
jak dla czystego kodu Javy, np. javac -g Informacje.java.
Nowością jest natomiast wygenerowanie pliku nagłówkowego, jaki zawarty będzie w
kodzie metody rodzimej. Generacja taka wymaga zastosowania narzędzia javah,
które generuje plik nagłówkowy o nazwie takiej jak podana nazwa klasy z
rozszerzeniem .h (header - nagłówek) tworzony w tym samym katalogu gdzie
znajduje się plik klasy programu. Przykładowo wywołanie polecenia:
j javah - j jn i i Informac j je
spowoduje wygenerowanie następującego pliku nagłówkowego:
Przykład 8.2:
//Informacje.h:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class Informacje */
#ifndef _Included_Informacje
#define _Included_Informacje
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: Informacje
* Method: infoSystemu
* Signature: (Ljava/lang/String;)I
*/
JNIEXPORT jint JNICALL Java_Informacje_infoSystemu
(JNIEnv *, jobject, jstring);
#ifdef __cplusplus
}
#endif
#endif
Jak widać jest to nagłówek dla kodu metody rodzimej tworzonego w C/C++.
Zasadniczo można tworzyć implementacje metod rodzimych w innych językach ale to
wymaga indywidualnego podejścia (konwersji typów i nazw), stąd zaleca się
korzystanie jedynie z C/C++ do obsługi metod rodzimych. W zasadniczej części
nagłówka (poza analizą składni dla C czy C++) zawarto opis metody używając do
8-5
Jacek Rumi ń ski - J ę zyk JAVA –
Jacek Rumi ń ski - J ę zyk JAVA – Rozdzia ł 8
tego komentarza zawierającego nazwę klasy, w ciele której zadeklarowano metodę
rodzimą, nazwę metody rodzimej w kodzie Javy oraz podpis (sygnatura) metody.
Sygnatura metody ma format (typy-argumentów)typy-zwracane ; gdzie poszczególne
typy są reprezentowane przez swoje sygnatury, i tak:
sygnatura znaczenie typu w Javie
Z
boolean
C
char
S
short
I
int
J
long
F
float
D
double
Lpełna-nazwa-klasy
pełna nazwa klasy
[typ
typ[]
W powyższym przykładzie pliku nagłówkowego widnieje informacja, że metoda
zawiera argument o sygnaturze Ljava/lang/String czyli obiekt klasy String oraz
zwraca wartość typu o sygnaturze I czyli typu int . Można określić sygnatury typów
argumentów i wartości zwracanych metod poprzez użycie narzędzia de-asemblacji
kodu a mianowicie javap :
j javap -s -p Informac j je
co wygeneruje:
Compiled from Informacje.java
class Informacje extends java.lang.Object {
static {};
/* ()V */
Informacje();
/* ()V */
public native int infoSystemu(java.lang.String);
/* (Ljava/lang/String;)I */
public static void main(java.lang.String[]);
/* ([Ljava/lang/String;)V */
}
W powyższym wydruku w opcji komentarza zawarto sygnatury typów.
Po opisie metody rodzimej następuje deklaracja metody dla środowiska rodzimego
czyli C/C++. Deklaracja ta oprócz omówionej już nazwy zawiera szereg nowych
elementów i tak:
JNIEXPORT i JNICALL - oznaczenie funkcji eksportowanych z bibliotek (jest to
odniesienie się do specyfikacji deklaracji funkcji eksportowanych, JNIEXPORT oraz
JNICALL są zdefiniowane w jni_md.h);
jint lub inny typ - oznaczenie typu elementu zwracanego przez funkcję, np.
8-6
Jacek Rumi ń ski - J ę zyk JAVA –
B
byte
Jacek Rumi ń ski - J ę zyk JAVA – Rozdzia ł 8
typ w Javie, typ rodzimy, rozmiar, typ dla C/C++ (Win32)
boolean
jboolean 8
unsigned unsigned char
byte
jbyte
8
signed char
char
jchar 16
unsigned unsigned short
short
jshort 16
short
int
jint
32
long
long
jlong
64
__int64
float
jfloat
32
float
double
jdouble
64
double
void
void
void
JNIEnv * wskaźnik interfejsu JNI zorganizowany jako tablica funkcji JNI o konkretnej
lokalizacji. Metoda rodzima wykorzystuje funkcje poprzez odwołanie się do
wskaźnika JNIEnv*. Przykładowo można pobrać rozmiar macierzy wykorzystując
funkcję GetArrayLength() poprzez wskaźnik JNIEnv*:
(...) JNIEnv *env (...) jintArray macierz (...)
jsize rozmiar = (*env)->GetArrayLength(env, macierz);
jobject to kolejny element deklaracji funkcji w JNI. Argument tego typu stanowi
referencję do bieżącego obiektu; jest odpowiednikiem this w Javie.
Warto tu zauważyć, że odpowiednikiem metody Javy zadeklarowanej jako ”native”
jest funkcja zawierająca co najmniej dwa argumenty, nawet wówczas gdy metoda nie
zawiera żadnego.
jstring lub inne typy argumentów - kolejne argumenty funkcji (argumenty metody
rodzimej).
8.1.3 Implementacja metody rodzimej - funkcja a biblioteka
Kolejny krok stosowania funkcji w kodzie Javy to stworzenie tych funkcji lub
ich adaptacja do formy wymaganej przez JNI. Deklaracja realizowanej funkcji musi
być taka sama jak założona (wygenerowana) w pliku nagłówkowym. Następujący
przykład ukazuję przykładową realizację metody rodzimej deklarowanej we
wcześniejszych przykładach:
Przykład 8.3:
//informacje.cpp
#include "jni.h"
#include <stdio.h>
#include <dos.h>
#include "Informacje.h"
JNIEXPORT jint JNICALL Java_Informacje_infoSystemu(JNIEnv *env, jobject o, jstring str){
struct time t;
const char *s=(env)->GetStringUTFChars(str,0);
8-7
Jacek Rumi ń ski - J ę zyk JAVA –
Zgłoś jeśli naruszono regulamin