Сокеты и сокетные соединения

Оглавление

URL (Uniform Resource Locator). 3

Соединение с URL. 5

Чтение и запись. 5

Сокеты и сокетные соединения. 6

Варианты заданий.. 8

 


 

Java делает сетевое программирование простым благодаря наличию специальных средств и класса Network. Основной используемый протокол TCP/IP.

Приложения клиент/сервер используют компьютер, выполняющий специальную программу сервер, которая предоставляет услуги другим программам клиентам. Клиент это программа, получающая услуги от сервера. Клиент-серверные приложения основаны на использовании верхнего уровня протоколов.

Каждый компьютер по протоколу TCP/IP имеет уникальный IP-адрес. Это 32-битовое число, обычно записываемое как четыре числа, разделенные точками, каждое из которых изменяется от 0 до 255. IP-адрес может быть временным и выделяться динамически для каждого подключения или быть постоянным, как для сервера. Обычно при подключении к компьютеру вместо числового IP адреса используются символьные имена, называемые именами домена. Специальная программа DNS (Domain Name Sever) преобразует имя домена в числовой IP-адрес. Получить IP-адрес в программе можно с помощью объекта класса InetAddress из пакета java.net:

// вывод IP-адреса локального компьютера

import java.net.*;

public class MyLocal {

public static void main(String[] args){

InetAddress myIP = null;

try {

myIP = InetAddress.getLocalHost();}

catch (UnknownHostException e) {}

System.out.println(myIP);

}

}

 

Метод getByName позволяет получить IP-адрес из имени домена:

// извлечение IP-адреса из имени домена

import java.net.*;

public class IPfromDNS {

public static void main(String[] args){

InetAddress bsu = null;

try {

bsu = InetAddress.getByName("www.ya.ru"); }

catch (UnknownHostException e){ }

System.out.println(bsu);

}

}

 

Для явной идентификации услуг к IP-адресу присоединяется номер порта через двоеточие, например 217.21.43.2:31. Номера портов от 1 до 1024 используются, например, для запуска двух программ серверов на одном компьютере. Если порт явно не указан, браузер воспользуется значением по умолчанию: 20 – FTP-данные, 21 – FTP-управление, 23 – TELNET, 53 – DNS, 80 – HTTP, 110 – POP3, 119 – NNTP.


URL (Uniform Resource Locator)

Рассмотрим пример URL: http://ya.ru/

Здесь:

· http — идентификатор протокола. Кроме HTTP существует некоторое количество других: File Transfer Protocol (FTP), Gopher, File, News.

· ya.ru/ — имя ресурса. Слеш в конце — сокращение для «/index.html »)

Идентификатор протокола и имя ресурса должны быть разделены двоеточием и двумя прямыми слешами. Формат имени ресурса полностью зависит от используемого в конкретной ситуации протокола, однако, для многих протоколов (в т.ч. и для HTTP) имя состоит из одного или нескольких следующих компонентов:

· Имя хоста

· Имя файла (путь к файлу на сервере)

· Номер порта

· Ссылка (слово или группа слов, к которым привязан гипертекстовая ссылка; элемент HTML, связывающий веб-документы)

Для большинства протоколов обязательными для указания являются лишь первые два компонента.

В Java для представления URL есть специальный класс с одноименным названием из пакета java.net. Самый простой способ создать объект этого класса — передать строковое представление url в конструктор:

URL yandex = new URL("http://ya.ru/");

 

Созданный объект является абсолютным URL. Абсолютный в этом контексте означает, что указаны все параметры, необходимые для навигации к требуемому узлу. URL также может создаваться с использованием относительного (relative) имени.

Пример для адреса http://news.yandex.ru/Russia/

URL yandex = new URL("http://ya.ru/");

URL yandexRussia = new URL(yandex, "Russia/")

 

В случае, когда известны все 4 компонента адреса есть еще 2 конструктора (когда известен номер порта и нет):

new URL("http", "www.gamelan.com", "/pages/Gamelan.net.html");

new URL("http://www.gamelan.com/pages/Gamelan.net.html"); // эквивалентно

 

С номером порта:

new URL("http", "www.gamelan.com", 80, "pages/Gamelan.network.html");

// для адреса: http://www.gamelan.com:80/pages/Gamelan.network.html


Иногда адрес может содержать специальные символы (например, пробелы), которые должны заменяться на их эквиваленты в URL (пробел = %20). Для автоматической обработки подобных случаев используется класс java.net.URI, содержащий метод toURL() для преобразования в объект класса URL:

// сайт «http://foo.com/hello world/»

URI uri = new URI("http", "foo.com", "/hello world/", "");

URL url = uri.toURL();

 

Каждый из URL конструкторов использует класс-исключение MalformedURLException.

Полезные методы класса URL:

· getProtocol

Возвращает идентификатор протокола

· getAuthority

Возвращает доменный адрес вместе с портом (например ya.ru:80)

· getHost

Возвращает адрес хоста

· getPort

Возвращает номер порта. Если порт не установлен, возвращает -1

· getPath

Возвращает путь

· getQuery

Возвращает компонент query

· getFile

Возвращает объединение getPath и getQuery (так, как они представлены в адресе)

· getRef

Возвращает компонент URL ссылка.

Пример:

import java.net.*;

import java.io.*;

 

public class ParseURL {

public static void main(String[] args) throws Exception {

URL aURL = new URL("http://java.sun.com:80/docs/books/tutorial"

+ "/index.html?name=networking#DOWNLOADING");

System.out.println("protocol = " + aURL.getProtocol());

System.out.println("authority = " + aURL.getAuthority());

System.out.println("host = " + aURL.getHost());

System.out.println("port = " + aURL.getPort());

System.out.println("path = " + aURL.getPath());

System.out.println("query = " + aURL.getQuery());

System.out.println("filename = " + aURL.getFile());

System.out.println("ref = " + aURL.getRef());

}

}

 

Результаты работы:

protocol = http

authority = java.sun.com:80

host = java.sun.com

port = 80

path = /docs/books/tutorial/index.html

query = name=networking

filename = /docs/books/tutorial/index.html?name=networking

ref = DOWNLOADING

 

Метод openStream() возвращает поток для указанного URL (что полезно, к примеру, для чтения данных с запрашиваемой веб-страницы).

Соединение с URL

После успешного создания объекта типа URL можно вызвать метод openConnection для получения объекта URLConnection (или одного из специфических подклассов протокола, например, java.net.HttpURLConnection). Он используется для установки каких-либо параметров, необходимых для настройки непосредственно перед подключением (вызовом URLConnection.connect).

Пример:

try {

URL yahoo = new URL("http://www.yahoo.com/");

URLConnection yahooConnection = yahoo.openConnection();

yahooConnection.connect();

 

} catch (MalformedURLException e) { // new URL() failed

. . .

} catch (IOException e) { // openConnection() failed

. . .

}

При этом нет необходимости явно вызывать метод connect, т.к. в java все операции, зависящие тем или иным образом от открытого соединения (например, getInputStream, getOutputStream), в случае необходимости сами неявно будут выполнять соединения.

Чтение и запись

Создав объект URLConnection, можно легко начать считывать данные из потока, возвращаемого методом URLConnection.getInputStream (работая с ним как с обычным IO-потоком)

URL yahoo = new URL("http://www.yahoo.com/");

URLConnection yc = yahoo.openConnection();

BufferedReader in = new BufferedReader(new InputStreamReader(yc.getInputStream()));

 

С записью всё аналогично, с тем лишь исключением, что перед получением потока (метод getOutputStream), необходимо установить параметр output в значение true (функция setDoOutput(true)).

URL url = new URL(args[0]);

URLConnection connection = url.openConnection();

connection.setDoOutput(true);

OutputStreamWriter out = new OutputStreamWriter(connection.getOutputStream());

 

Сокеты и сокетные соединения

Сокеты это сетевые разъемы, через которые осуществляются двунаправленные поточные соединения между компьютерами. Сокет определяется номером порта и IP-адресом. При этом IP-адрес используется для идентификации компьютера, номер порта – для идентификации процесса, работающего на компьютере. Когда одно приложение знает сокет другого, создается сокетное соединение. Клиент пытается соединиться с сервером, инициализируя сокетное соединение. Сервер ждет, пока клиент не свяжется с ним. Первое сообщение, посылаемое клиентом на сервер, содержит сокет клиента. Сервер в свою очередь создает сокет, который будет использоваться для связи с клиентом, и посылает его клиенту с первым сообщением. После этого устанавливается коммуникационное соединение.

Сокетное соединение с сервером создается с помощью объекта класса Socket. При этом указывается IP-адрес сервера и номер порта (80 для HTTP). Если указано имя домена, то Java преобразует его с помощью DNS-сервера к IP-адресу:

try { socket = new Socket("localhost",8080); }

catch (IOException e){ System.out.println("ошибка: " + e); }

 

Сервер ожидает сообщения клиента и должен быть запущен с указанием определенного порта. Объект класса ServerSocket создается с указанием конструктору номера порта и ожидает сообщения клиента с помощью метода accept(), который возвращает сокет клиента:

Socket socket = null;

try { server = new ServerSocket(8080);

socket = server.accept(); }

catch (IOException e) { System.out.println("ошибка: " + e); }

 

Клиент и сервер после установления сокетного соединения могут получать данные из потока ввода и записывать данные в поток вывода с помощью методов getInputStrеam() и getOutputStrеam() или к PrintStream для того, чтобы программа могла трактовать поток как выходные файлы.

В следующем примере для посылки клиенту строки "привет!" сервер вызывает метод getOutputStream() класса Socket. Клиент получает данные от сервера с помощью метода getInputStream(). Для разъединения клиента и сервера после завершения работы сокет закрывается с помощью метода close() класса Socket. В данном примере сервер посылает клиенту строку «привет!» после чего разрывает связь.


import java.io.*;

import java.net.*;

 

public class MyServerSocket{

public static void main(String[] args) throws Exception{

Socket s = null;

try {//посылка строки клиенту

ServerSocket server = new ServerSocket(8030);

s = server.accept();

PrintStream ps = new PrintStream(s.getOutputStream());

ps.println("привет!");

ps.flush();

s.close(); // разрыв соединения

}catch (IOException e){System.out.println("ошибка: " + e); }

}

}

 

Получение клиентом строки:

import java.io.*;

import java.net.*;

 

public class MyClientSocket {

public static void main(String[] args) {

Socket socket = null;

try {//получение строки клиентом

socket = new Socket("www.bsu.by", 8080);

BufferedReader dis = new BufferedReader(new

InputStreamReader(socket.getInputStream()));

String msg = dis.readLine();

System.out.println(msg);

} catch (IOException e) {System.out.println("ошибка: " + e); }

}

}

Аналогично клиент может послать данные серверу через поток вывода с помощью метода getOutputStream(), а сервер может получать данные с помощью метода getInputStream().

Если необходимо протестировать подобный пример на одном компьютере, можно соединится самому с собой, используя статические методы getLocalHost() класса InetAddress для получения динамического IP-адреса компьютера, который выдается при входе в Internet.


Варианты заданий

1. Разработать сервер для чат-клиентов. Программа должна поддерживать любое количество одновременно подключенных клиентов.

В окне программы отображается список подключенных клиентов (IP адрес и nickname) и кнопка «отключить», позволяющая отключить выбранного в списке клиента.

2. Разработать программу чат-клиента. Окно программы должно состоять из диалога и строки отправляемого сообщения.

При подключении к серверу программа должна выдать диалоговое окно, в котором необходимо ввести nickname (псевдоним пользователя) и IP адрес сервера.

При отключении от сервера (обрыве связи) должно выводится сообщение.

3. Разработать 2 программы:

a. Программа, показывающая исходный текст веб-страницы по введенному адресу

b. Программа, позволяющая скачать файл с ftp-адреса (адрес файла на ftp-сервере вводится пользователем в текстовое поле).

4. Необходимо разработать программу для отправки почтовых сообщений по протоколу SMTP.

5. Необходимо разработать программу для отправки почтовых сообщений по протоколу POP3.