Мрежово програмиране в Java

Протоколи  TCP/IP

Пакет  java.net

Идентификация на машина в мрежата

Класът InetAddress

Сървъри и клиенти

Протоколи TCP/IP

Примери на протоколи от приложния слой

IP (Internet protocol) - комутация на пакети(datagrames). Не съществува стандартно Java  API  позволяващо директна манипулация на протокола IP

UDP (User Datagram Protocol) - предаване на съобщения, бърза връзка, няма връзка между източник и получател, няма гаранция за получаване

TCP (Transmission Control Protocol) - трансмисия на поток, връзка между сървър и получател, гаранция за получаване.

Пакет java.net

Пакетът предлага множество класове за комуникация в Internet (и Intranet), работа с URL, дефиниция на нови протоколи.

По специално могат а бъдат създавани и използвани

Interfaces Classes Exceptions
ContentHandlerFactory
FileNameMap
SocketImplFactory
SocketOptions
URLStreamHandlerFactory
Authenticator
ContentHandler
DatagramPacket
DatagramSocket
    MulticastSocket
DatagramSocketImpl
InetAddress
NetPermission
PasswordAuthentication
ServerSocket
Socket
SocketImpl
SocketPermission
URL
URLClassLoader
URLConnection
    HttpURLConnection
    JarURLConnection
URLDecoder
URLEncoder
URLStreamHandler
MalformedURLException
ProtocolException
SocketException
    BindException
    ConnectException
    NoRouteToHostException
UnknownHostException
UnknownServiceException

Идентификация на машина в мрежата (по-точно на мрежова карта)

Адрес IP       - DNS форма                 - refg.tu-sofia.bg
                      “dotted quad”  форма     - 194.141.64.254

32 бита в IPv4:   

Ако най-старшите битове на адреса са:
0xxx: мрежа от клас A   - над 16 000 000 адреса
10xx: мрежа от клас B    - 65533 адреса
110xx: мрежа от клас C  - 254 адреса

CIDR -- Classless InterDomain Routing     RFC1519
Supernetting - ако са необходими 1000 адреса - могат да се използват 4 мрежи от клас C

192.60.128.0   (11000000.00111100.10000000.00000000)  Class C subnet address
192.60.129.0 (11000000.00111100.10000001.00000000) Class C subnet address
192.60.130.0 (11000000.00111100.10000010.00000000) Class C subnet address
192.60.131.0 (11000000.00111100.10000011.00000000) Class C subnet address
--------------------------------------------------------
192.60.128.0 (11000000.00111100.10000000.00000000) Supernetted Subnet address
255.255.252.0 (11111111.11111111.11111100.00000000) Subnet Mask
192.60.131.255 (11000000.00111100.10000011.11111111) Broadcast address

Подмрежата 192.60.128.0 включва всички адреси от 192.60.128.0 до 192.60.131.255. Идентификацията на мрежата е 22 бита а адресите вътре в мрежата - 10 бита.

CIDR нотация: 

192.60.128.0, Subnet Mask 255.255.252.0 
или:
192.60.128.0/22

128 бита в  IPv6

 

Клас InetAddress - Internet адрес (DNS и “dotted quad” форма)


Не притежава публични член променливи и конструктори

Някои член функции

за създаване на обект от класа:

static InetAddress getByName(String host) -  Определя IP  адреса на машина  (host).
static InetAddress[] getAllByName(String host) - Определя всички IP  адреси на машината host.
public static InetAddress getByAddress(byte[] addr) - addr в IPv4 е 4 байта, в IPv6 - 16.
static InetAddress getLocalHost() - адреса на локалната машина - еквивалентен на:.
                      getByName(null) ~ getByName("localhost") ~  getByName("127.0.0.1")

други:

 String getHostAddress() - IP адрес във форма на низ  : "%d.%d.%d.%d".
 String getHostName() -   името на машината на този адрес.
 boolean isMulticastAddress()проверява дали не е multicast адрес.
 
import java.net.*; 
public class NSLookupApp {
   public static void main(String args[]) {
      try {
            if(args.length!=1){ 
               System.out.println("Usage: java NSLookupApp hostName"); 
               return; 
           }
            InetAddress host = InetAddress.getByName(args[0]);
            String hostName = host.getHostName(); 
            System.out.println("Host name: "+hostName); 
           System.out.println("IP address: "+host.getHostAddress()); 
      }
      catch(UnknownHostException ex) { 
            System.out.println("Unknown host");
            return; 
      }
   }
}
java NSLookupApp localhost
Host name: localhost 
IP address: 127.0.0.1 

Упражнение: изведете на екран всички адреси на  amazon.com
 

Класът URL

Напомняне

URL: Uniforme Resource Locator. 

Низ от символи, която позволява локализирането по уникален начин един източник от Internet - протокол, машина(адрес IP+номер на порт), път на достъп(path), име на файла:

протокол: //машина[:порт]/път/име

https://ff.tu-sofia.bg/JavaBg/Network/Reseau.html

Описание

Съдържа методи за отваряне и създаване на Web страници. Не притежава променливи.

Конструктори

Обект от класа URL може да се създаде с конструктор  

URL url1 = new URL("https", "ff.tu-sofia.bg", "/futurs-etudiants/");

URL u2 = new URL("https://ff.tu-sofia.bg/");

URL u3 = new URL(u1, "Java/Network.htm");  // http://ff.tu-sofia.bg/Java/Network.html

Всички конструктори могат да генерират MalformedURLException.

 

Пример 

import java.net.MalformedURLException;
import java.net.URL;

public class Test
{
    public static void main(String[] args)
                throws MalformedURLException {

        // creates a URL with string representation.
        URL url1 =
        new URL("https://ff.tu-sofia.bg"+
             "/sites/default/files/documents_ff/FICHE_INSCRIPION-IC_002.pdf");

        // creates a URL with a protocol,host name,and path
        URL url2 = new URL("https", "ff.tu-sofia.bg",
                        "/futurs-etudiants/");
        
        //create a URL with another URL and path
        URL url3 = new URL("https://ff.tu-sofia.bg");
        URL url4 = new URL(url3, "/futurs-etudiants/");


        // print the String representation of the URL.
        System.out.println(url1.toString());
        System.out.println(url2.toString());
        System.out.println();
        System.out.println("Different components of the URL");

        // Retrieve the protocol for the URL
        System.out.println("Protocol url1: " + url1.getProtocol());

        // Retrieve the host name of the URL
        System.out.println("Hostname url1:  " + url1.getHost());

        // Retrieve the default port
        System.out.println("Default port url1: " + url1.getDefaultPort());


        // Retrieve the path of URL
        System.out.println("Path url4: " + url4.getPath());

        // Retrieve the file name
        System.out.println("File url1: " + url1.getFile());
    }
}

Към  URL могат да се закачват класове за потоков вход изход.

Пример: копиране на бинарен файл от зададен URL:

import java.io.*;
import java.net.*;
public class Test1 {
public static void main(String arg[]) {
int abyte;
try{
URL url = new URL("https://upload.wikimedia.org/wikipedia/commons/thumb/d/d9/"+
"Big_Bear_Valley%2C_California.jpg/1200px-Big_Bear_Valley%2C_California.jpg");
InputStream fi= url.openStream();
FileOutputStream fo= new FileOutputStream("picture.jpg");
System.out.println("srarting ...");
while((abyte= fi.read())!=-1)fo.write(abyte);
fi.close();
fo.close();
System.out.println("created");

}catch(MalformedURLException me) {
System.out.println("MalformedURLException: "+ me);
}catch (IOException ioe){
System.out.println("IOException: "+ ioe);
}

}
}

С използване на буфер:

import java.io.*;
import java.net.*;
public class Test2 {
public static void main(String arg[]) throws MalformedURLException, IOException{
byte buf[]=new byte[1024];
int len;
URL url = new URL("https://upload.wikimedia.org/wikipedia/commons/thumb/d/d9/"+
"Big_Bear_Valley%2C_California.jpg/1200px-Big_Bear_Valley%2C_California.jpg");
InputStream fi= url.openStream();
FileOutputStream fo= new FileOutputStream("picture1.jpg");
System.out.println("srarting ...");
while((len= fi.read(buf))!=-1)fo.write(buf,0,len);
fi.close();
fo.close();
System.out.println("created");
}
}

Пример: работа с текстов файл - извеждане на кода на URL страницата на екрана. Използване на клас филтър за текст.

import java.io.*;
import java.net.*;

class ReadURL{
   public static void main(String[] a){
      try{
         URL url = new URL("https://nbu.bg");
         BufferedReader br = new BufferedReader(new
                                  InputStreamReader(url.openStream()));
         String line;
         while((line=br.readLine()) !=null) {
            System.out.println(line);
         }
         br.close();
      }catch(MalformedURLException me) {
          System.out.println("MalformedURLException: "+ me);
      }catch (IOException ioe){
           System.out.println("IOException: "+ ioe);
      }
   }
}

Charset encoding

При четене на текстова информация в интернет може да се появи проблем с нейното кодиране. В зависимост от кодирането текстът може да бъде визуализиран  по различен начин.  Това не е проблем при латинските букви, но останалите се представят по различен начин в зависимост от използваното кодиране. Обигновено кодирането се задава в началото на страницата  в meta tag. Така например в https://nbu.bg  от горния пример се използва:

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

Кодирането на страницата може да се получи програмно,  чрез анализ на страницата или чрез използване на класа URLConnection.

В Java кодирането се управлява от клас Charset. При създаването на текстови потоци (входни и изходни) без указване на кодирането, се използва подразбиращото се кодиране на Java виртуалната машина. То може да се види с:

import java.nio.charset.Charset;

public class Test{
    public static void main(String[] arg) {
        System.out.println("Local character encoding: "+Charset.defaultCharset().displayName());       
    }
}

Подразбиращото се кодиране се задава преди стартиране на дадена апликация, кешира се и на практика не може да бъде променено от програмата. Проблеми няма, само ако кодиранията на страницата и на локалната машина съвпадат, или ако на страницата има само символи, чиито ASCII и UNICODE кодове съвпадат.

При разлика в кодирането е необходимо при създаването на входния текстови поток да се укаже използваното кодиране на страницата. 

import java.io.*;
import java.net.*;
import java.nio.charset.*;

class ReadURL{
   public static void main(String[] a){
     
      try{
         URL url = new URL("https://nbu.bg");
         BufferedReader br = new BufferedReader(new
                                  InputStreamReader(url.openStream(),Charset.forName("UTF-8")));
         String line;
         while((line=br.readLine()) !=null) {
            System.out.println(line);
         }
         br.close();
      }catch(MalformedURLException me) {
          System.out.println("MalformedURLException: "+ me);
      }catch (IOException ioe){
           System.out.println("IOException: "+ ioe);
      }
   }
}

Името на  Charset може да се зададе с каноничното му име или с някои от неговите псевдоними ( aliases ).

Списъкът на използваните кодирания (charsets) в Java може да се види на:

https://docs.oracle.com/javase/8/docs/technotes/guides/intl/encoding.doc.html

Каноничните имена на възможните текстови кодирания в Java  могат да се изведат и с 

System.out.println((Charset.availableCharsets()).values());

Псевдонимите на дадено кодиране могат да се изведат с функцията aliases().

Клас URLConnection

Този клас осигурява по-добър контрол върху обмена на информацията на URL страницата

Конструиране - на две стъпки 1) конструира се URL  2)използва се функцията openConnection()

URL tu = new URL("https://www.tu-sofia.bg");

URLConnection tu_c = tu.openConnection();

Класът притежава методи за прочитане на параметри на  страницата като:
тип на информацията getContentType(), която извежда използвания charset:

import java.io.IOException;
import java.net.*;

public class URLc {
    public static void main(String[] arg) throws MalformedURLException,IOException{
         URL url = new URL("https://nbu.bg");
         URLConnection urlc = url.openConnection();
         System.out.println(urlc.getContentType());
    }

}