Programarea în reţea – Datagrame şi Url-uri
5. Citirea şi scrierea către un URL
Scopul acestei lucrări este de insuşire
a următoarelor mecanisme;
- comunicarea prin UDP
- lucrul cu URL-uri
- comunicarea cu un CGI
Clienţii care comunică prin intermediul TCP, utilizând socket-uri, au un canal dedicat, iar transmisia datelor
este sigură. Datele sunt recepţionate în ordinea în care acestea au
fost trimise.
In contrast, când datele sunt transmise prin UDP, ajungerea acestora la
destinaţie nu este garantată, de asemenea, ordinea de sosire la
destinaţie a datagramelor poate să difere de ordinea în care acestea
au fost transmise.
Avantajul lucrului cu datagrame este creşterea vitezei cu care pachetele
(datagramele) ajung la destinaţie. Există cazuri în care viteza de
transmisie a datelor este mai importantă decât garantarea 100% a ajungerii
acestora la destinaţie. De exemplu în cazul transmiterii unui semnal audio
în timp real, viteza de transmitere a acestuia este mai importantă decât
garantarea ajungerii la destinaţie.
In java pentru implementarea protocolului UDP sunt utilizate clasele: DatagramPacket şi DatagramSocket.
Spre deosebire de programarea TCP, în cazul UDP nu există conceptul de ServerSocket. Atât serverul cât şi clientul
utilizează DatagramSocket pentru realizarea
conexiunii. Pentru transmiterea şi recepţionarea datelor se
utilizează clasa DatagramPacket.
Programarea prin
url-uri se desfăşoară la un nivel mai înalt decât programarea
prin socketuri. Utilizând clasa URL, se va putea
deschide o conexiune către o resursa aflată pe web.
O data deschisă conexiunea, către resursă, clientul va putea
citi date sau trimite date către respectiva resursă.
URL este acronimul
de la Uniform Resource Locator (de asemenea este
şi numele unei clase java). Un URL este un pointer
către o resursă din Internet.
Sintaxa
generală a unui URL este:
protocol://hostname[:port]/path/filename#ref
In cadrul acestei secţiuni este construit un server de timp care va
trimite la cerere data curentă către clienţii care solicită
acest lucru. De asemenea este construit şi clientul care accesează
serviciile serverului de timp.
La nivelul serverului se creează un obiect DatagramSocket,
care va primi ca parametru portul pe care serverul va începe ascultarea.
DatagramSocket socket = new DatagramSocket(1977);
In continuare se construieşte un obiect DatagramPacket,
care va fi utilizat de către server pentru a recepţiona cererea de la
client. O dată construit obiectul DatagramPacket,
serverul va începe ascultarea portului 1977, prin invocarea metodei receive().
byte[] buf = new byte[256];
DatagramPacket packet = new DatagramPacket(buf,buf.length);
socket.receive(packet);
In momentul în care un client doreşte să apeleze la serviciile
serverului, acesta va trimite un pachet către server. Serverul
citeşte din cadrul pachetului portul şi adresa clientului, şi îi
va trimite acestuia un pachet ce conţine data curentă.
InetAddress address = packet.getAddress();
int port = packet.getPort();
buf = ((new Date()).toString()).getBytes();
packet = new DatagramPacket(buf,buf.length,address,port);
socket.send(packet);
Un client, pentru a se conecta la server, trebuie să creeze un
obiect DatagramSocket, şi să trimită
un pachet către server. Spre deosebire de server, clientul nu este obligat
să specifice nici un port în momentul creierii obiectului DatagramSocket, întrucât se atribuie automat un port liber
respectivului obiect.
import java.io.*;
import java.net.*;
import java.util.*;
public class TimeServer extends Thread{
boolean running=true;
public TimeServer() {start();}
public void run(){
try{
DatagramSocket socket = new DatagramSocket(1977);
while(running){
//asteapta client
byte[] buf = new byte[256];
DatagramPacket packet = new DatagramPacket(buf,buf.length);
socket.receive(packet);
//citeste adresa si portul clientului
InetAddress address = packet.getAddress();
int port = packet.getPort();
//trimite
un reply catre client
buf = ((new Date()).toString()).getBytes();
packet = new DatagramPacket(buf,buf.length,address,port);
socket.send(packet);
}
}catch(Exception ex){ex.printStackTrace();}
}
public static
void main(String[] args) {
TimeServer timeServer1 = new TimeServer();
}
}
import java.io.*;
import java.net.*;
import java.util.*;
public class Client {
public static
void main(String[] args) {
try{
DatagramSocket socket = new DatagramSocket();
byte[] buf = new byte[256];
DatagramPacket packet = new DatagramPacket(buf,buf.length,
InetAddress.getByName("localhost"),1977);
socket.send(packet);
packet = new DatagramPacket(buf,buf.length);
socket.receive(packet);
System.out.println(new String(packet.getData()));
}catch(Exception ex){ex.printStackTrace();}
}
}
In această secţiune este prezentat modul de lucru în java cu URL-uri.
Pentru a accesa o resursă din Internet identificată printr-un URL, în java, primul pas este de a crea un obiect
URL.
URL utcn = new
URL(“www.utcluj.ro”);
Clasa URL conţine metode prin intermediul cărora se pot afla
toate componentele unui URL: getProtocol(), getPort(), getHost(), getFile(), getRef().
Odată creat obiectul URL, se utilizează metoda openStream() pentru a deschide un flux de intrare, prin
intermediul căruia se citeşte conţinutul respectivului URL.
BufferedReader in = new BufferedReader(
new InputStreamReader(
utcn.openStream()));
String inputLine;
while ((inputLine = in.readLine()) != null)
System.out.println(inputLine);
in.close();
Daca se doreşte să se realizeze mai mult decât citirea conţinutului unui URL, atunci din cadrul clasei URL se poate apela metoda openConnection(). Această metodă va returna un obiect URLConnection. Acest obiect va putea fi utilizat pentru operaţii de scriere, citire precum şi interogări către un URL.
URLConnection connection
= utcn.openConnection();
In continuare este prezentat un scurt program care citeşte
conţinutul unui URL utilizând clasa URLConnection.
import java.net.*;
import java.io.*;
public class URLConnectionReader {
public static void main(String[] args) throws Exception {
URL utcluj = new URL(http://www.utcluj.ro);
URLConnection con = yahoo.openConnection();
BufferedReader in = new BufferedReader(
new InputStreamReader(
con.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null)
System.out.println(inputLine);
in.close();
}
}
Multe pagini HTML conţin form-uri (zone de text, butoane etc.) care
permit introducerea de date şi transmiterea acestora către server. După
completarea câmpurilor se apasă un buton iar browserul
web va transmite datele către URL-ul corespunzător. URL-ul
care recepţionează datele este un script cgi-bin. Acesta procesează datele şi transmite
către client un răspuns, care de obicei este o altă pagină
HTML.
Programele java pot interacţiona cu
script-urile cgi-bin. Ele trebuie să fie
capabile să scrie date către un URL. Acest lucru se realizează
utilizând clasa URLConnection.
In listingul următor este exemplificat
modul în care un program java poate interacţiona
cu un script cgi-bin.
try{
String data=””;
data +=
URLEncoder.encode("nume") + "=" +
URLEncoder.encode("Adi”);
data +=
"&" + URLEncoder.encode("nota”) +
"=" + URLEncoder.encode("8.50”);
URL url = new URL(“http://193.226.6.117:80/test/test.php");
URLConnection conn = url.openConnection();
conn.setDoOutput(true);
OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream());
wr.write(data);
wr.flush();
// Get the response
BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line;
while ((line = rd.readLine()) != null) {
System.out.println(line);
}
rd.close();
wr.close();
}catch(Exception
ex){ex.printStackTrace();}
In listingul anterior se presupune că
există un script cgi-bin
test.php, către care programul java trimite
două variabile : nume=adi şi nota=8.50 . Scriptul cgi va citi respectivele
variabile şi va transmite către programul java un răspuns.
Pentru testarea listingului anterior se va reveni în
cadrul laboratorului care prezintă servleturile.
In listingul următor este prezentat un
exemplu complet al unui applet care citeşte
conţinutul unui fişier identificat printr-un URL. In cazul de
faţă appletul citeşte chiar
fişierul .class propriu.
import java.applet.*;
import java.awt.*;
import java.net.*;
import java.io.*;
public class FileURL extends Applet
{
byte[] appletCode; //stocare fisier citit
public void init()
{
try {
// Ceraza obiect URL
URL url = new URL(getCodeBase(),
getClass().getName()+".class");
// Deschide conexiunea catre
URL
URLConnection urlConn = url.openConnection();
// Utilizeaza ByteArrayOutputStream ca un container temporar.
// Dupa terminare citire va
fi convertit catre un array
ByteArrayOutputStream tempBuffer;
tempBuffer = new ByteArrayOutputStream();
// Creaza fluxul de citire catre URL
InputStream instream = urlConn.getInputStream();
// Citeste continutul URL-ului in bufferul temporar
int ch;
while ((ch = instream.read())
>= 0) {
tempBuffer.write(ch);
}
// Converteste bufferul temporar intr-un array
appletCode = tempBuffer.toByteArray();
} catch (Exception e) {
e.printStackTrace();
}
}
public void paint(Graphics
g)
{
g.setColor(Color.black);
if (appletCode == null) {
g.drawString("Nu s-a citit fisierul
.class",
10, 30);
} else {
g.drawString("Lungimea fisierului
class. "+
appletCode.length+" bytes
.", 10, 30);
}
}
}
In această secţiune este prezentat modul în care se poate
construi în java un browser de internet.
import javax.swing.*;
import java.awt.*;
import javax.accessibility.*;
import javax.swing.event.*;
import javax.swing.text.*;
import java.net.*;
import java.io.*;
import java.awt.event.*;
public class Browser extends JPanel {
Browser() {
setLayout (new BorderLayout (5, 5));
final JEditorPane jt = new JEditorPane();
final JTextField input =
new JTextField("http://127.0.0.1:8080");
// read-only
jt.setEditable(false);
// follow links
jt.addHyperlinkListener(new HyperlinkListener () {
public void hyperlinkUpdate(
final
HyperlinkEvent e) {
if (e.getEventType() ==
HyperlinkEvent.EventType.ACTIVATED) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// Save original
Document doc = jt.getDocument();
try {
URL url = e.getURL();
jt.setPage(url);
input.setText (url.toString());
}
catch (IOException io) {
JOptionPane.showMessageDialog (
Browser.this, "Can't
follow link",
"Invalid Input",
JOptionPane.ERROR_MESSAGE);
jt.setDocument (doc);
}
}
});
}
}
});
JScrollPane pane = new JScrollPane();
pane.setBorder (
BorderFactory.createLoweredBevelBorder());
pane.getViewport().add(jt);
add(pane, BorderLayout.CENTER);
input.addActionListener (new ActionListener() {
public void actionPerformed (ActionEvent e) {
try {
jt.setPage (input.getText());
} catch (IOException ex) {
JOptionPane.showMessageDialog (
Browser.this, "Invalid URL",
"Invalid Input",
JOptionPane.ERROR_MESSAGE);
}
}
});
add (input, BorderLayout.SOUTH);
}
}
import javax.swing.*;
public class Start extends JFrame{
public Start(){
Browser b = new Browser();
getContentPane().add(b);
pack();
setVisible(true);
}
public static void main(String args[])
{
Start
s = new Start();
}
}