    Глава 9 

    Сетевые средства Java 

    Несомненно, одной из важнейших особенностей Java является наличие 
встроенных средств программирования для Internet. Взможность их применения 
способствовала росту популярности нового языка, позволяющего программировать 
интерактивное содержимое Web-страниц при помощи встроенных апплетов и 
использующего классы для работы в сети (пакет java.net). 
    Язык Java создавался в расчете на работу в Internet и корпоративных сетях 
intranet. Основная система установления сетевых Internet-соединений, или 
протоколов, называется TCP/IP. Возможность установления соединений в 
соответствии с протоколом TCP/IP должна обеспечиваться всеми платформами, 
способными связываться с Internet и intranet-сетями. Среди базовых пакетов 
платформно-независимого языка Java имеется пакет java.net. Это означает, что 
вне зависимости от платформы, на которой выполняется апплет или приложение, 
используя платформно-независимые классы этого пакета, можно связаться через 
Internet с любой машиной. 
    На многих платформах программирование для TCP/IP — процесс достаточно 
трудоемкий. Но общую природу асинхронной работы в сети, где иногда происходят 
существенные задерЗк!сйТТ]Гл1сТб"ой момент возможны прерывания, можно обойти, 
используя классы пакета java.net. 
    Соединения в Internet осуществляются с помощью^ виртуальных каналов связи, 
называемых сокетами (socket). Сокет — это канал связи между двумя программами. 
Каждой программе принадлежит один "конец" канала связи. Данные, помещаемые в 
канал одной программой, может прочитать другая программа. В пакете java.net 
имеется класс Socket. Более того, при установлении сетевого соединения через 
сокет используются классы, порожденные от классов Java InputStream и 
OutputStream. (Об этих классах и их использовании можно прочитать в главе 8.) 
Это означает, что операции чтения и записи через сокет можно осуществлять с 
помощью тех же методов, которые используются для чтения и записи в локальной 
файловой системе. 
    В этой главе рассказывается об Internet, о том, как компьютеры, используя 
IP-адреса, могут связываться по сети. Вы узнаете о классах Java, позволяющих 
устанавливать сетевые соединения между двумя различными программами, о 
реализации сокетов, дающих вам возможность создавать собственные 

    265 

    информационные серверы (например, HTTP-серверы) на Java. В конце главы 
описывается класс URL, с помощью которого вы можете получать информацию с 
HTTP- и FTP-серверов. 
    I 

    Язык Internet: TCP/IP 

    Все подключенные к Internet машины "разговаривают" на одном и том же 
языке. Его имя — TCP/IP (Transmission Control Protocol/Internet Protocol). 
TCP/IP представляет собой набор коммуникационных протоколов, позволяющих 
различным компьютерам связываться друг с другом через паутину межсетевых 
соединений. Эти соединения могут быть самых разных типов: локальные сети 
lOBaseT, спутниковые каналы, телефонные ISDN-линии и даже простые телефонные 
линии связи. Все они формируют коммуникационную сеть, называемую Internet. 
    TCP/IP представляет собой сложный набор форматов пакетов данных и 
протоколов установления соединений, описывающих, как компьютеры могут надежно 
обмениваться потоками данных. Потоки данных были описаны в главе 8. Те же 
самые потоки данных, используемые для описания механизма ввода и вывода 
информации из файлов, используются при описании сетевых соединений в Internet. 
Подробно об этом будет рассказано далее. В этой книге не описаны детали 
протокола TCP/IP, имеющего очень сложную спецификацию. Подробнее узнать о нем 
можно в WWW, например на узле http://ds.internic.net. Там представлена 
обширная информация о протоколах Internet, используемых в настоящее время, 
даны прогнозы на будущее. 

    IP-адреса 

    У любой машины, подключенной к Internet, имеется по крайней мере один 
Internet-адрес. С помощью таких адресов различные компьютеры связываются друг 
с другом. Зная Internet-адрес, или //"-адрес, машины, можно получать от нее 
или отправлять ей потоки данных. 
    Однако вышесказанное не совсем верно. Связаться можно только с теми 
машинами, чье программное обеспечение "прослушивает" сеть, т.е. ожидает 
поступления запроса на соединение. Некоторые машины защищены от контакта 
брандмауэрами. Брандмауэр разрешает или запрещает установление соединений с 
машиной, которую он защищает, в соответствии с принятой стратегией защиты. 
Брандмауэры обеспечивают защиту данных от несанкционированного доступа. 
Например, рядовому пользователю не разрешено связываться с большинством 
компьютеров министерства обороны. Понятно, что администраторы сети, 
обеспечивающей связь военных ведомств Соединенных Штатов, не хотят, чтобы 
кто-нибудь посторонний получил доступ к их компьютерам, особенно тот, кто 
может представлять угрозу стратегическим интересам. Многие корпорации также 
устанавливают брандмауэры, запрещающие доступ извне к секретной информации. 

    266	Visual J++: основы программирования 

    Тем не менее множество компьютеров Internet допускают установление сетевых 
соединений, и в сети всегда можно найти интересующую вас информацию или просто 
"поболтать" с другими пользователями. При установлении соединений с тем или 
иным компьютером используется один из его IP-адресов. 
    IP-адрес представляет собой 32-битовое число. В Java-программах IP-адреса 
хранятся в массиве из четырех байтов. Старший байт имеет индекс О, младший — 
индекс 3. По соглашению, при записи IP-адреса в виде строки число разделяется 
на четыре отдельных байта, при этом старший байт записывается первым, а 
младший — последним. Байты разделяются точками, например так: 

    192.176.7.45 

    Читается это следующим образом: "сто девяносто два точка сто семьдесят 
шесть точка семь точка сорок пять". Произнести такой номер достаточно трудно. 
В связи с этим первые пользователи Internet при сообщении друг другу 
IP-адресов вели примерно такие диалоги: 
    — Привет, Боб! Почему ты не свяжешься с моей машиной? 
    Мой IP-адрес: двести семьдесят семь точка семь точка два... нет, семь. 
    — Семьсот семьдесят семь? 
    — Нет, двести семьдесят семь! 
    — Сколько-сколько? 
    Понятно, что необходимость запоминать все эти числа превращалась в 
серьезную проблему для первых пользователей Internet. Поэтому была выработана 
схема именования отдельных машин (а точнее говоря — IP-адресов), более удобная 
для человека. Это те имена, которые вы обычно видите в URL: 

    http://www.microsoft.com/visualj 

    Здесь "www.microsoft.com" — это имя машины одного из общедоступных 
компьютеров империи Microsoft. Можно использовать и следующий URL: 

    http://198.105.232.30/visualj 

    Имя машины "www.microsoft.com" является синонимом ее настоящего IP-адреса "198.105.232.30". 

    Класс InetAddress 

    В Java объекты класса InetAddress, содержащегося в пакете java.net, 
представляют отдельные IP-адреса Internet. Чтобы связаться с другим 
компьютером, необходимо сначала создать объект класса InetAddress, который 
будет содержать ссылку на него. 

    Глава 9. Сетевые средства Java	267 

    Статический метод getByName() класса InetAddress создает новый объект 
класса InetAddress по данному имени машины или IP-адресу следующим образом: 

    InetAddress inetaddr = InetAddress.getByName ("www.microsoft.com"); 

    ИЛИ 

    InetAddress inetaddr = InetAddress.getByName("198.105.232.30"); 

    (Во втором примере IP-адрес передается в виде строки с тем же порядком 
байтов и с таким же разделением точками, как описано ранее.) Если имя машины 
не найдено (например, из-за того, что оно не является корректным 
Internet-именем), то метод выдает исключение UnknownHostException. 
    Метод getAllByName() аналогичен методу getByName(). Различие заключается в 
том, что метод getAHByNameQ возвращает все IP-адреса, связанные с данным 
именем машины. Помните, что с одним IP-адресом может быть связано несколько 
имен машин в Internet и, наоборот, одна машина может иметь несколько 
IP-адресов. Метод getAHByName() возвращает массив IP-адресов, каждый из 
которых относится к машине с заданным именем. Ниже приведен пример приложения, 
которое, получая имя машины, выводит на экран все связанные с ней объекты типа InetAddress: 

    import java.net.*; 
    public class ShowAddresses { 
    public static void main(String[] astrArgs) { 
    // Каждый аргумент командной строки является именем // машины, которую 
следует найти в Internet. for(int ii=0 ; iiostrArgs. length ; ii++) ( try { 
    InetAddress[] inetaddrs = 
    InetAddress . getAHByName (astrArgs [ii]) ; 
System.out.println(astrArgs[ii] + ":"); for(int jj=0 ; jj<inetaddrs.length ; jj++) 
    System.out.println(inetaddrsIjj]); } catch (UnknownHostException e) { 
    System.out.println("Error connecting to " + astrArgs[ii]); 
    } 
    При запуске этого приложения с командной строкой "jview ShowAddresses 
www.microsoft.com java.sun.com www.javasoft.com" на экран выводится следующее: 
    www.microsoft.com: www.microsoft.com/198.105.232.6 
www.microsoft.com/198.105.232 . 7 www.microsoft.com/198.105.232.30 


    268 Visual J++: основы программирования 


    www.microsoft.com/198.105.232.10 www.microsoft.com/207.68.137.7 
www.microsoft.com/207.68.137.8 www.microsoft.com/207.68.137 . 9 
www.microsoft.com/207.68.137 .34 www.microsoft.com/207.68.137.35 
www.microsoft.com/207.68.137.36 www.microsoft.com/207.68.137 .40 
www.microsoft.com/207.68.137.41 www.microsoft.com/207.68.137.42 
www.microsoft.com/207.68.137.43 www.microsoft.com/198.105.232.4 
www.microsoft.com/198.105.232.5 Java.sun.com: 
    Java.sun.com/206.26.48.100 www.j avasoft.com www.JavaSoft.com/206.26.48.100 

    Из этого примера видно, что машина www.microsoft.com имеет несколько 
IP-адресов, а машины java.sun.com и www.javasoft.com пользуются одним общим IP-адресом. 
    Метод getAddressQ возвращает массив из четырех байтов, представляющий 
собой IP-адрес, на который ссылается объект InetAddress. Как уже говорилось, 
самый старший байт 32-битового IP-адреса хранится в элементе массива с 
индексом 0, а самый младший — в элементе с индексом 3. 
    Метод getHostNameQ возвращает строку с одним из имен машины, имеющей 
заданный IP-адрес. Если объект InetAddress создан с использованием IP-адреса 
машины, то метод вернет его в виде строки. Если объект InetAddress роздан 
каким-то другим образом, то метод вернет одно из имен, связанных с IP-адресом, 
на который ссылается объект InetAddress. 
    Еще одним полезным методом класса InetAddress является статический метод 
§е1Ьоса1Ноз1().1метод getLocalHostQ Этот метод возвращает объект InetAddress, 
соответствующий IP-адресу машины, на которой в данный момент выполняется 
апплет или приложение. Например, если запустить приложение Java с машины по 
имени "cyrano.supercorp.com" (это вымышленное имя), код 

    InetAddress inetlocal = InetAddress.getLocalHost(); String 
strLocalHostName = inetlocal.getHostName(); Systern.out.println(strLocalHostName); 

    обеспечит вывод на экран такой строки: 

    cyrano.supercorp.com 


    ПОРТЫ в киберпространстве 

    IP-адреса являются в киберпространстве, по сути, коммутаторами. Каждый 
IP-адрес соответствует массиву точек соединения, называемых портами, 


    Глава 9. Сетевые средства Java	269 


с которыми через Internet может связаться другой компьютер. Принцип такой 
связи проиллюстрирован на рис. 9.1. 

    IP-адреса 
    подключенной 
    к Internet машины 

    Рис. 9.1. IP-адрес соответствует массиву портов киберпространства 

    Когда две машины осуществляют соединение через Internet, между двумя 
портами образуется виртуальная линия связи. Можно установить соединение между 
портами разных машин или между разными портами одной и той же машины. 
Обеспечить взаимодействие между процессами в Java (помимо использования 
собственных методов этого языка или объектов COM/DCOM) можно с помощью сокетов 
одной и той же машины. Интересно заметить, что при сегодняшнем уровне развития 
программирования технология обеспечения связи между двумя процессами одной и 
той же машины совпадает (обычно используется один и тот же программный код) с 
технологией установления соединения между двумя компьютерами, находящимися в 
разных точках земного шара! 
    Термин соединение через сокет (socket connection) применяется для 
обозначения виртуального соединения, устанавливаемого между любыми двумя 
портами в Internet. Слово "сокет" (англ, socket — "разъем", "гнездо") 
используется для обозначения того или иного порта, поскольку порты похожи на 
гнезда разъемов, которые можно соединить проводами и передавать по ним данные. 
Возможно, лучшей аналогией была бы телефонная линия. Каждый порт в Internet 
можно рассматривать в качестве отдельного телефона. При "звонке" с одного 
порта на другой между двумя телефонами устанавливается линия связи. Все, что 
говорится в микрофон, слышно на другом конце линии. Связь заканчивается, когда 
одна из сторон "кладет трубку". Термин "сокет" используется для обозначения 
любого порта в Internet. 

    27О Visual J++: основы программирования 


    Установление соединений через сокеты 

    Чтобы установить соединение через сокет между двумя машинами, 
подключенными к Internet, нужен объект класса InetAddress, который ссылается 
на IP-адрес удаленной машины. В предыдущем параграфе рассказано, как создавать 
объекты класса InetAddress. Если объект InetAddress уже имеется, остается 
создать из него объект Socket и таким образом осуществить соединение через сокет. 
    Объекты класса Socket представляют в Java соединения, установленные через 
сокеты. Для создания объекта Socket используется оператор new. При передаче 
конструктору класса Socket объекта InetAddress и номера порта, с которым надо 
соединиться, конструктор устанавливает соединение через этот сокет. Ниже 
приведен фрагмент кода, предназначенного для создания соединения: 

    InetAddress inetaddr = InetAddress.getByName ("www.microsoft.com"); Socket 
sock = new Socket(inetaddr, 80); 

    В этом примере показано, как создается соединение между некоторым портом 
некоторой локальной машины и портом номер 80 машины с именем 
"www.microsoft.com", находящейся где-то в киберпространстве. В 
действительности же данный код позволит установить соединение между вашей 
машиной и центральным WWW-сервером фирмы Microsoft. Если вы создадите 
программу, способную "общаться" с WWW посредством HTTP-протокола, 
HTML-документы или какую-то другую информацию можно будет загружать с сервера 
фирмы Microsoft. 
    Следует помнить, что соединение через сокет осуществляется между двумя 
портами, один из которых находится на локальной машине, а другой на удаленной. 
Конструктору класса Socket для связи с удаленной машиной требуется знать 
только номер ее порта. Предполагается, что пользователя не интересует, какой 
порт его машины будет задействован, поэтому при установлении соединения класс 
Socket выбирает свободный порт. Ситуации, когда требуется знать номер порта 
локальной машины, с которой устанавливается соединение через сокет, почти не встречаются. 

    Передача ааниых через сокет 

    Если объект класса Socket создан, можно начинать передачу данных от своего 
приложения и принимать данные от другого приложения, связанного с 
противоположным концом соединения. При передаче данных через сокет 
используется поток вывода, который предоставляется объектом Socket. Метод 
getOutputStream() класса Socket возвращает ссылку на поток вывода. 
Записываемые в этот поток вывода байты передаются через Internet программе, 
связанной с другим концом соединения. 
    Отметим, что вся передача данных осуществляется с использованием потоков. 
С точки зрения программиста, вывод в поток не отличается от вывода в обычный 
файл. Поэтому для записи данных в файл и для записи тех же данных на удаленную 
машину через сокет используется один и тот же 

    Глава 9. Сетевые среасгва Java	271 

код. Это — одно из самых больших преимуществ классов Java. Для того чтобы 
научиться пересылать данные через Internet, не надо изучать новый интерфейс 
API или новые классы. 

    Пример эхо-клиента 

    Некоторые номера портов в Internet зарезервированы для особых целей. 
Настройка портов на выполнение этих особых функций не обязательна, но в 
большинстве машин она осуществляется. Например, порт номер семь зарезервирован 
для проведения эхо-контроля. Каждый раз при установлении соединения с портом 
номер семь другой машины, независимо от ее IP-адреса, все посланные данные 
возвращаются назад. Таким образом реализуется встроенный механизм проверки, 
благодаря которому вы можете убедиться, что сетевое соединение или 
Internet-программа функционируют нормально. 
    Ниже представлено простое приложение Java — эхо-клиент. Передавая машине 
указанное в командной строке имя или IP-адрес, эта программа осуществляет 
соединение с портом номер семь указанной машины. Все, что будет набрано на 
клавиатуре, скопируется в сокет, после чего машина будет ждать какого-нибудь 
отклика. Конечно, вернувшиеся байты будут теми же, что были посланы, поскольку 
в соединении участвует эхо-порт удаленной машины. Такой эхо-клиент может быть 
очень легко создан с помощью классов InetAddress и Socket. 
    Не на всех машинах Internet имеется эхо-сервер, подключенный к седьмому 
порту. Читатель, пользующийся Windows 95, может заметить, что эта система не 
обеспечивает связь с его собственным компьютером. Так и должно быть. Но на 
большинстве машин эхо-порт реализован. Если с помощью этой программы будет 
установлено соединение с машиной "www.microsoft.com" или "www.javasoft.com", 
то все, что будет набрано на клавиатуре локальной машины, вернется назад и 
будет отображено на экране. 
    Ниже приведен код эхо-клиента Java: 

    import java.io.*    // Классы потоков данных, import java.net.*   // 
Классы для работы в сети. 
    public class EchoClient { 
    public static final int ECHO_PORT = 7; 
    public static void main(String[] astrArgs) { 
    // Единственный аргумент командной строки — имя машины 
    // или IP-адрес. 
    
    if(0 == astrArgs.length) { 
    System.err.println("Usage Error: \n EchoClient \ 
    <machine-name>"); System.exit (-1); } 
    PrintStream out = null; 
    DatalnputStream socket_in = null; 
    DatalnputStream user_in = new DatalnputStream(System.in); 


    272	Visual J++: основы программирования 


    try { 
    InetAddress addr = InetAddress.getByName(astrArgs[0]); 
    Socket sock = new Socket(addr, ECHO_PORT); 
    out = new PrintStream(sock.getOutputStream()); 
    socket_in = new DatalnputStream (sock.getlnputStream()); } catch 
(Exception e) { 
    System.err.println("Error:\n Connecting to remote \ port: " + e) ; 
    e.printstaсkTrace(System.err) ; 
    System.exit(-1); } 
    // Каждая введенная строка передается обратно через сокет, // затем 
ожидается отклик из сокета. Если пользователь // набирает "Quit", программа 
завершается, try { 
    boolean fDone = false; while(!fDone) { 
    String str = user_in.readLine(); if("QUIT".equals(str)) { fDone = true; 
break; } 
    out.println(str); 
    String strResponse = socket_in.readLine(); System.out.println("From the 
socket: " +strResponse), } } catch (Exception e) { 
    System.err.println("Error:\n Problem with \ 
    communications: " + e); e.printStackTrace(System.err); System.exit(-1); } 
    if(null != out) 
    out.close(); if (null != socket_in) 
    socket_in.close(); user_in.close(); } catch (Exeption e) { 
    System.err.println("Error:\n Problem closing the 
    socket: " + e); 
    e.PrintStackTrace(System.err); System.exit(-1); 
    ) 
    } 


    Блокирование сокетов 

    В программе эхо-клиента используются потоки ввода и вывода, связанные с 
сокетом. Сетевые соединения не всегда бывают быстродействующими. Большинство 
пользователей домашних компьютеров, подключенных к 

    Глава 9. Сетевые среаства Java	273 

Internet через модем со скоростью работы 28800 бод, знают, что связь с 
Internet осуществляется гораздо медленнее, чем доступ к данным локальной 
файловой системы. 
    При чтении данных из потока ввода, связанного с сокетом, любое выполнение 
операции read() над этим потоком будет блокировать выполнение программы, пока 
данные из соединения не будут полностью прочитаны. Это значит, что фоновый 
программный поток, который вызвал метод read(), будет ждать, пока запрошенные 
данные не будут переданы из Internet на машину. Иногда это ожидание бывает 
довольно долгим. Например, при попытке прочитать 10 Кб данных из сокета во 
время одного вызова метода readQ, этот метод не завершится до тех пор, пока 
все байты не будут загружены (это занимает несколько секунд) или пока 
соединение не разорвут с другой стороны. 
    Если сетевое соединение разрывают с другой стороны, то вызов метода readQ 
приводит к выдаче исключения EOFException. Чтобы сделать возможной обработку 
этой ситуации, следует переписать код приложения EchoClient следующим образом 
(добавленные строки выделены жирным шрифтом): 

    // Каждая веденная строка пересылается обратно через сокет, // а затем 
ожидается ответ. Если пользователь набирает // "Quit", программа завершается, 
try { 
    boolean fDone = false; while(!fDone) ( 
    String str = user_in.readLine (); if("QUIT".equals(str)) { fDone = true; 
break; } 
    out.println(str); 
    String strResponse = socket_in.readLine (); 
    System.out.println("From the socket: " + 
    strResponse); } } catch (EOFException eEOF) { 
    System.out.println("Socket has been closed \ 
    from the other side"); fDone = true; } catch (Exception e) { 
    System.err.println("Error:\n Problem with \ 
    communications: " + e); e.printStackTrace(System.err); System.exit(-1); } 

    Аналогичным образом при передаче данных через сокет с использованием 
потока вывода метод writeQ будет блокировать выполнение программы, пока все 
данные не будут переданы через сокет. Если соединение во время вызова метода 
writeQ будет разорвано с противоположной стороны, то 


    274	Visual J++: основы программирования 

    произойдет выдача исключения lOException. Для обработки этого исключения в 
приложении EchoClient имеется блок try/catch, включающий вызов метода socket_out.println(): 

    } catch (lOException eWrite) ( 
    System.out.println("Socket was closed from other side \ 
    during write()"); fDone = true; 


    Негарантированные отправка n получение данных 

    Вся изложенная выше информация о соединениях через сокеты и связи с 
Internet верна только отчасти, поскольку сетевые соединения были представлены 
как последовательные потоки байтов. Если воспользоваться приведенными выше 
примерами, то результаты совпадут с описанными: все данные, посланные 
удаленному порту, будут им получены в том же порядке. Однако существуют 
ситуации, позволяющие посылать данные отличным от описанного способом. Это 
ситуации, в которых гарантия получения отправленных данных не является 
обязательной или в которых не нужно гарантировать правильную 
последовательность получения данных. 
    Предположим, вы хотите написать простую программу, которая передает 
сигналы точного времени на другой конец сетевого соединения в виде пакетов 
байтов. Каждую секунду посылается набор данных, представляющий один такт 
времени. В этом случае точный порядок получения данных не имеет значения. Если 
через секунду после отправления такта 12:00:01 был послан такт 12:00:02, то не 
стоит беспокоиться, если противоположная сторона получит 12:00:01 после 
12:00:02. К моменту передачи значения 12:00:02 значение 12:00:01 устареет, и 
уже не будет иметь значения, получила ли его вторая сторона. 
    В подобных случаях не обязательно использовать гарантированное соединение 
(называемое TCP-соединением). Другим вариантом установления соединения через 
сокет является соединение с применением дейтаграмм (datagram). В дейтаграмме 
каждый пакет данных адресуется и отсылается индивидуально. Пакеты принимаются 
на другом конце сетевого соединения независимо от того, дошли ли остальные 
пакеты, а также в случае, если пришло несколько копий одного и того же пакета. 
    В Internet одиночный пакет данных не обязательно достигнет пункта своего 
назначения, и наоборот, в пункт назначения может поступить некоторое 
количество копий одного и того же пакета. TCP-соединение создается таким 
образом, что все пакеты данных имеют индивидуальные номера. Когда в порт 
назначения пакет приходит с нарушением порядка следования, порт ждет 
предыдущего пакета, не передавая уже полученные пакеты программе. Если пакет 
не приходит, сокет запрашивает порт отправки на предмет 

    Глава 9. Сетевые средства Java	275 

    повторной посылки потерянного пакета. Дубликаты игнорируются. При 
использовании дейтаграмм индивидуальные пакеты не нумеруются, проверка факта 
их получения не производится, так же как и выявление дубликатов. Но для 
некоторых приложений такой способ пересылки вполне приемлем. 
    TCP-соединения обходятся дороже и с точки зрения временных затрат, и с 
точки зрения сетевого трафика. Поэтому иногда дейтаграммы обладают 
определенным преимуществом перед TCP-соединениями. В приведенном выше примере 
с часами предпочтительнее использовать как раз дейтаграммы, а не TCP-соединения. 
    Имеется перегруженная версия конструктора класса Socket, с помощью которой 
можно создавать соединения с использованием дейтаграмм. Синтаксис этого 
конструктора такой: 

    public Socket(InetAddress addr, int port, boolean stream); 

    Если значение параметра stream равно true, то будет установлено 
TCP-соединение. Если оно равно false, то будет отправлена дейтаграмма. 

    Создание Internet-серверов 

    Приведенное в предыдущем примере приложение Java EchoClient функционирует, 
связываясь с седьмым портом другой машины Internet. Однако эта программа будет 
работать только в том случае, если к седьмому порту удаленной машины будет 
подключена программа эхо-сервера. Сервер представляет собой программу, которая 
"прослушивает" сокет, ожидая запроса на установление соединения. Используя 
аналогию с телефонной связью, можно сказать, что сервер похож на человека, 
ожидающего телефонного звонка. Приложение без программы-сервера аналогично 
телефону, чью трубку никто не снимает. 
    При попытке связаться с портом машины, на которой не запущен сервер, 
ожидающий соединения, произойдет выдача исключения lOException. При этом на 
экране появляется сообщение, подобное приведенному ниже: 

    Error: 
    Connecting to remote port: Java.net.SocketException: connect 


    Класс ServerSocket 

    Для сознания слушающего сокета в Java используется класс ServerSocket. 
Объект ServerSocket связан с локальным портом и ожидает соединения. При 
установлении соединения объект ServerSocket переадресует его на какой-нибудь 
другой локальный порт, после чего его самого можно будет_«юва установить в 
режим ожидания соединения. 
    Перенаправление соединения на другой локальный порт очень важно для 
правильной работы объекта ServerSocket. Это похоже на звонок в офис: звонящий 
сначала разговаривает с секретарем, который, переключив его на необходимый 
телефон, может отвечать на другие звонки. 

    276	Visual J++: основы программирования 

    Объект ServerSocket похож на такого секретаря. Вместо того чтобы 
устанавливать соединение через единственный серверный сокет данного порта, 
объект ServerSocket передает соединение другому порту, после чего с ним самим 
можно связываться снова. Вот почему некоторые номера jrppTOB в Internet могут 
быть зарезервированы. С эхо-портом (портом номер семь) обычно связана 
программа, ожидающая запросы на установление соединения. После того как 
соединение с удаленной машиной установлено, сервер передает его другому порту 
и начинает "слушать", т.е. ожидать следующего запроса, адресуемого все тому же 
порту номер семь. 

    Созааипе программ-серверов на Java 

    Большинство программ-серверов, написанных на языке Java, похожи друг на 
друга. Главный программный поток программы-сервера управляет серверным сокетом 
в некотором цикле, периодически прослушивая запросы на установление 
соединения, и при их наличии устанавливает соединение. Для каждого внешнего 
соединения сервер порождает дополнительный программный поток, управляющий 
связью с отдельным клиентом. Чаще всего основная часть приложения представляет 
собой отдельный класс, а для обработки конкретных соединений создаются 
дополнительные классы. 
    Ниже приведен пример реализации эхо-сервера. Если запустить это приложение 
на локальной машине, то класс EchoServer, используя метод acceptQ класса 
ServerSocket, создаст объект ServerSocket, ожидающий внешних соединений с 
седьмым портом. После установления соединения классом EchoServer будет создан 
обработчик для программы эхо-клиента, предназначенный для работы с этим 
конкретным соединением. Эхо-сервер создает также окно, в котором отображается 
текущий номер соединения и имя машины локального сервера. 

    import java.net.*; import java.awt.*; import EchoClientHandler; 
    public class AchoServer extends Frame { private static int ECHO_PORT = 7; 
private static String m_strServerName; private static int m_cClients; private 
static EchoServer m_f = null; private static ServerSocket sock; 
    // Метод main() создает объект EchoServer, который // отображает имя 
машины сервера и число связавшихся // клиентов. 
    public static void main(String[] astrArgs) { try { 
    sock = new ServerSocket(ECHO_PORT); m_cClients = 0; 
    m_strServerName = InetAddress.getLocalHost().getHostName(}; } catch 
(Exception e) { 
    System.err.println("Error:\n Problem creating the \ ServerSocket: " + e) ; 


    Глава 9. Сетевые средства Java	277 


    e.printStackTrace(System.err) System.exit (-1); 
    } 
    // Создание окна, отображающего название сервера и // число соединений. 
m_f = new EchoServer(); m_f.resize(300, 200); m_f.repaint(); 
    while(true) { try ( 
    Socket s = sock.accept(); 
    new EchoClientHandler(s); // Класс для 
    // обработки соединения. m_cClients++; m_f.repaint(); } catch (Exception 
e) { 
    System.err.println("Error:\n Problem listening\ 
    for clients: " + e) ; e.printStackTrace(System.err); System.exit(-1); } 
    1 
    public static void decrementClientCount() { 
    m_cClients--; .[';>•- '-/:;•. m_f . repaint () ; 
    ">.. ,') '  .       . .    .- ...,.- .   ..     . •   .; ::.••.•  
•:.-•...:•  '•' .-.'    '  •'• 
    public static void shutdown() { 
    System.out .println ("Shutting down..."); 
    System.exit(-1); } 
    public EchoServer() { 
    super("EchoServer Application"); >	. 
    public void paint(Graphics g) { 
    FontMetrics fm = g.getFontMetrics(); g.drawSreing("Server: " + 
m__strServerName + "\n" + "Clients: " + m_cClients, 10, 10); 
    '   •')      .         - -:   '  •       - .•    .'•   ' 
    // Обработка событий WINDOW_DESTROY с помощью // вызова метода shutdown(). 
public boolean handleEvent(Event evt) { if(evt.id == Event.WINDOW_DESTROY) ( shutdown(); 
    return true; // Эта команда никогда не выполняется, // однако она 
необходима компилятору. 


    278 Visual J++: основы программирования 


    } 
    return false; } } 

    Класс EchoClientHandler управляет программой-демоном, чья работа 
заключается в том, чтобы непрерывно читать данные из потока ввода, связанного 
с сокетом, и передавать их потоку вывода, связанному с тем же      ( сокетом. 
Фоновый программный поток является потоком-демоном, поэтому он автоматически 
уничтожается при завершении программы Server. 

    import java.net.*; import java.io.*; 
    public class EchoClientHandler implements Runnable { 
    // Входной поток — это сокет, передаваемый конструктору, private Socket 
m_sock = null; 
    // Конструктор сохраняет ссылку на сокет и создает фоновый // поток, 
работа которого определена в методе run() . public EchoClientHandler(Socket s) 
{ m_sock = s; 
    Thread t = new Thread(this); t.setDaemon(true); t.start (); } 
    public void run() { try { 
    DatalnputStream is = new 
    DatalnputStream(m_sock.getlnputStream()); PrintStream os = new 
PrintStream(m_sock.getOutputStream()); while(true) ( 
    String str = is.readLine(); os.println(str); } } catch (Exception e) { 
    System.err.println("Error:\n Problem in client, \ 
    killing: " + e) ; e.printStackTrace(System.err); } 
    EchoServer.decrementClientCount(); } } 


    Глава 9. Сетевые средства Java	279 


    URL и ПРОТОКОЛЫ 

    При получении данных от Internet-серверов большинство транзакций 
выполняются согласно следующей базовой модели: 
    1.   Клиент подключается к серверу через сетевое соединение. 
    2.   Сервер и клиент осуществляют некий предварительный обмен информацией, 
во время которого договариваются о том, какая информация нужна клиенту от сервера. 
    3.   Сервер передает клиенту требуемую информацию. 
    4.   Если клиенту требуется дополнительная информация (и протоколом эта 
передача разрешена), то опять выполняются действия пункта 2. 
    5.   После того как клиент получает всю необходимую информацию, сетевое 
соединение разрывается со стороны клиента. 
    В этих пяти пунктах описано, как происходит большинство взаимодействий 
сервера с клиентом, особенно при получении информации из WWW. Но бывают и 
специфические транзакции. Предположим, вы хотите получить HTML-страницу с 
информацией по Visual J++ с WWW-сервера фирмы Microsoft. Для этого нужно 
обратиться на данный сервер и указать особый идентификатор "visualj". Вот что 
при этом должно произойти: 
    1.   Программа-клиент должна создать сокет для установления сетевого 
соединения с компьютером, имя которого "www.microsoft.com". Соединение будет 
установлено с портом номер 80, который обычно резервируется для 
HTTP-протокола. Ниже приведен метод, с помощью которого осуществляется это соединение: 

    public   Socket  makeHTTPConnection(String  strServerName)    { try   { 
    InetAddress addrServer =  InetAddress.getByName(strServerName); return   
new  Socket(addrServer,   80);      //   Порт  номер   80 
    //  зарезервирован // для HTTP-соединений. }   catch   (Exception  e)    { 
return  null; 
    } } 

    2.   После отсылки и получения некоторой идентифицирующей информации, 
сообщающей о том, какие программы сервера и клиента выполняются, 
программа-клиент посылает следующую команду: 

    GET /visualj/ HTTP/1.0 

    Эта команда сообщает HTTP-серверу о том, что требуется ресурс "/visualj". 
Информация, которой обменялись программы сервера и клиента, фиксируется, 
поэтому администратор WWW-сервера может выяснить, кто связывался с сервером. 

    28О	Visual J+v: основы программирования 

    3.   WWW-сервер отсылает HTML-файл программе-клиенту через сетевое 
соединение. Прежде чем отправить содержимое файла, сервер посылает некоторые 
сведения, в том числе о типе данных, которые содержатся в этом ресурсе, схеме 
кодирования (если таковое выполнялось), дате создания и тому подобное. Эта 
информация используется программой-клиентом для соответствующей перекодировки 
данных, поступающих из "/visualj". 
    4.   При использовании HTTP-протокола этот (четвертый) пункт данного 
списка всегда пропускается. Это обусловлено тем, что в настоящее время данный 
протокол не позволяет клиенту во время одного соединения несколько раз 
запрашивать у сервера данные. Для того чтобы получить дополнительные данные от 
того же сервера, программа-клиент должна установить другое HTTP-соединение с 
WWW-сервером, в ходе которого снова будут выполнены действия, соответствующие 
остальным пунктам рассматриваемого списка. 
    5.   После получения данных из yvisualj" (на самом деле являющихся 
HTML-файлом) клиент разрывает сетевое соединение. 
    Многие другие протоколы, предназначенные для получения информации, 
придерживаются такого же порядка получения данных. К ним относится, например, 
FTP — протокол передачи файлов. Соединение, осуществляемое по пункту 1, 
происходит почти описанным выше способом, только порт при этом используется 
другой. Для FTP-серверов в Internet зарезервирован порт номер 21. Пункты 3, 4 
и 5 выполняются аналогично. 
    Выполнение пункта 2 для FTP-протокола осуществляется несколько иначе. 
Именно на этапе предварительного обмена информацией проявляются различия 
протоколов. При использовании HTTP-протокола происходит обмен базовой 
информацией между сервером и клиентом (сообщаются номера версий, имена 
программ, электронный адрес пользователя, если программа-клиент решила 
предоставить эту информацию), и клиент выдает команду "GET", "POST" или 
"HEAD", указывающую, какая информация требуется от сервера. В FTP-протоколе 
применяются совсем другие команды. Например, для получения ресурса с именем 
"/some/cool/resource.zip" с FTP-сервера программа-клиент передает следующий 
набор команд: 

    CD some CD cool GET resource.zip 

    Эти команды весьма отличаются от команд, передаваемых HTTP-серверу. 
Рассмотренные нами протоколы выполняют одинаковые функции, но их спецификации 
не похожи между собой. 

    URL 

    Стандарт, в соответствии с которым осуществляется идентификация ресурсов в 
WWW, называется URL (Uniform Resource Locator — унифицированный 

    Глава 9. Сетевые средства Java	281 

    локатор ресурсов ). Ниже приведен пример URL для титульной страницы Visual J++: 

    http://www.microsoft.com/visualj 

    Обычно URL состоит из трех отдельных частей. В первой части указывается 
протокол, используемый для доступа к информации. В приведенном примере это 
"http". Первая часть всегда отделяется от остальных двоеточием. Во второй 
части указывается имя машины, на которой находится программа-сервер. Перед 
именем машины стоят две косые черты. В нашем примере имя машины — 
"www.microsoft.com". В третьей части указывается идентификатор ресурса, 
("/visualj"). Третья часть URL называется URI (Uniform Resource Identifier — 
универсальный идентификатор ресурсов). URI выглядит как описание пути, где 
между именем каталога и подкаталога находится косая черта. URI обычно 
интерпретируется сервером как путь к ресурсу, т.е. отдельные ресурсы хранятся 
где-то на машине сервера, a URI является путем к файлу, который пожелал 
загрузить клиент. 
    Применение URL обеспечивает унифицированную систему адресации ресурсов в 
WWW. Используя URL, можно обращаться к файлам ресурсов, доступных на 
HTTP-серверах ("http://www.microsoft.com/visualj"), FTP-cep-верах, 
Gopher-серверах или Internet-серверах любого другого типа. Поскольку основная 
форма URL неизменна, запомнить и использовать эту систему адресации легче, чем 
использовать синтаксис различных протоколов. 
    В Java каждый объект класса URL представляет собой отдельный URL. Для 
загрузки данных, на которые указывает URL, можно использовать public-методы 
объекта. Это значит, что объект URL, созданный для титульной страницы Visual 
J++ на WWW-сервере фирмы Microsoft, можно использовать для загрузки 
HTML-страницы Visual J++. При этом не надо создавать сетевое соединение, иметь 
дело с потоками ввода, сталкиваться с прочими сложностями..Методы класса URL 
выполнят все описанные выше этапы процесса доступа к данным. 
    Создание сетевого соединения, чтение из потока ввода, передача команд 
серверу — все эти операции происходят автоматически, способствуя существенной 
экономии времени. Ниже приведен Java-код, необходимый для загрузки титульной 
страницы Visual J++: 

    URL urlVJ = new URL("http://www.microsoft.com/visualj"); Object obj = urlVJ.getContent(); 


    Типы содержимого 

    Все ресурсы, идентифицируемые по URL, имеют тип содержимого (content 
type), который позволяет узнать, что представляет собой ресурс, а также формат 
данных. Скажем, тип содержимого "image/gif' сообщает, что ресурс — это 
изображение и данные этого изображения закодированы в формате GIF. 
    В приведенной ниже программе URL создается с использованием идентификатора 
"file:". Именем сервера служит пробел слева, сообщающий, что 

    282	Visual J++: основы программирования 

используется локальная машина. Первый аргумент командной строки — это URI. 
Идентификатор "file:" не относится к стандартным. Он показывает, что ресурсом 
является локальный файл. В этой программе для открытия файла, указанного в 
командной строке, используется метод URL.getContentQ; программа направляет 
содержимое этого файла в поток System.outPrintStream. 

    import java.io.*; import java.net.*; 
    public class PrintOutText { 
    // Только параметр командной строки служит именем файла, // который надо 
открыть. Следует убрать букву, // обозначающую логической диск. Программа 
использует // текущий диск. 
    public static void main(String astrArgs[]) { if(0 == astrArgs.length) { 
    System.err.println("Usage Error:\n PrintOutFile <file path>"); 
System.exit(-1); } 
    Object obj = null; try f 
    URL url = new URL("file://" + astrArgs[0]); 
    obj = url.getContent(); 
    if (null == obj) | | (! (obj instanceof InputStream))) { 
    System.out.println("Content could be read: " + obj); System.exit(-1); } } 
catch (Exception e) { 
    System.err.println("Error:\n Unable to open file: " + e); 
e.printStackTrace(System.err); System.exit(-1); } 
    // Чтение строк входного файла и запись их в System.out. DatalnputStream 
is = new DatalnputStream((InputStream)obj); try { 
    String str = ""; do { 
    System.out.println(str); str  =   is.readLine(); 
    }   while((null   !=   str)    &&    (str.length()    !=   0)); 
is.close(); }   catch(lOException  ioe)    { 
    System.err.println("Error:\n  Reading  from  file:   "   +  ioe); 
ioe.printStackTrace(System.err); System.exit(-1); } ) ) 


    Глава 9. Сетевые средства Java	283 

    Если эту программу немного модифицировать, ее можно будет использовать для 
чтения и отображения на экране любого ресурса, указанного с помощью URL. 
Аналогично программе PrintOutText, данная программа связывается с любой 
машиной, указанной в URL, и выводит на экран полученные данные. Если объект, 
возвращаемый методом getContentQ, не является потоком вывода, то программа 
завершается, поскольку она не знает, что делать с таким объектом. Это может 
случиться, в частности, в случае, если URL, переданный в качестве первого 
аргумента командной строки, указывает на файл изображения с расширением GIF 
или на аудиофайл с расширением AU. В обоих случаях метод getContent() 
фактически читает все данные объекта Image или AudioClip, как ему указано 
типом содержимого ресурса. 

    import java.io.*; import java.net.*; 
    public class PrintOutURL { 
    // Только параметр командной строки служит именем файла, // который надо открыть. 
    public static void main(String astrArgs[]) { if(0 == astrArgs.length) { 
    System.err.println("Usage Error:\n PrintOutURL <URL>"); System.exit(-1); } 
    Object obj = null; try { 
    URL url = new_URL(astrArgs[0]); •       : 'obj = url. getContent (} ; -  : 
       if (null ==" obj)"""! | 
    (! (obj instanceof InputStream))) ( System.out.println("Content could be 
read \ 
    as text: " + obj); System.exit(-1); } } catch (Exception e) { 
    System.err.println("Error:\n Unable to open file: " + e); 
e.prontStackTrace(System.err); System.exit(-1); } 
    // Чтение всех строк файла ввода и запись их в 
    // System.out. 
    DatalnputStream is = new DatalnputStream((InputStream)obj); 
    try { 
    String str = ""; do { 
    System.out.println(str); str = is.readLine(); } while((null != str) && 
(str.length () != 0)); 


    284 Visual J++: основы программирования 


    is.close (); }   catch(lOException  ioe)    { 
    System.err.println("Error:\n Reading from file:   "  +  ioe) 
ioe.printStackTrace(System.err); System.exit(-1); } ) } 


    Самостоятельное получение содержимого URL 

    Что следует делать пользователю, если он не хочет полагаться на метод 
getContentQ класса URL при получении и интерпретации содержимого ресурса, а 
желает делать это самостоятельно? В классе URL есть методы, с помощью которых 
можно получить доступ к ресурсам, адресуемым объектом URL, как к потоку ввода байтов. 
    Метод getURLConnectionQ класса URL возвращает объект URLConnection файла 
ресурса, адресуемого объектом URL. URL-соединение аналогично соединению, 
производимому объектом Socket, по крайней мере концептуально. Установив 
URL-соединение, можно получить потоки ввода-вывода, связанные с 
Internet-ресурсом. Различие заключается в том, что к тому времени, когда метод 
getURLConnectionQ вернет объект URLConnection, предварительный обмен 
информацией и установление сетевого соединения будут уже завершены. Это все 
равно что получить поток байтов ресурса, не вникая в детали протокола. 
    Если данные ресурса представлены в формате, не известном Java, можно 
использовать URL-соединение. Предположим, вы определяете новый формат файла, 
описывающий игру в шахматы, с использованием лишь байтов и чисел. При загрузке 
одного из таких файлов, чей тип содержимого не известен классам пакета 
java.net, можно установить URL-соединение и з1ш~исать прочитанные байты 
непосредственно в свои пользовательские структуры данных. 
    Вот как можно создать URL-соединение и прочитать байты из Internet-ресурса: 

    URL url = new URL(strResource); URLConnection conn = 
url.getURLConnection(); corTnTconhect () ; InputStream is = conn.getlnputStream(); 
    // Чтение содержимого ресурса. is.close(); 

    Соединение открывается в два приема. Сначала URL-соединение 
устанавливается по заданному URL, затем оно открывается для передачи данных с 
помощью метода URLConnection.connectQ. Между этими двумя вызовами 

    Глава 9. Сетевые средства Java	285 

можно поместить другие команды, определяющие различные спецификации 
URL-соединения, чтобы использовать их для предварительного обмена информацией 
с сервером и запроса ресурса. Так, некоторым Internet-протоколам требуется 
осуществить взаимодействие с пользователем. Одним из таких протоколов является 
FTP. Если пользователь должен ввести пароль, ему следует вызвать метод 
allowUserlnteractionQ объекта URLConnection. Другие протоколы требуют передачи 
дополнительной информации через поток вывода URL-соединения (возвращаемый 
методом URLConnection.ge-tOutputStreamO). Например, HTTP-запрос "POST" 
требует, чтобы наряду с запросом ресурса серверу были посланы данные, 
содержащиеся в HTML-форме, или данные какого-то другого типа. Возможно, вам 
уже приходилось заполнять различные формы в WWW. Сама форма связана с программой, 
которая выполняется или готова к выполнению на HTTP-сервере. 
    1	Когда форма передается WWW-броузеру, тот связывается с сервером и делает 
запрос "POST". Передаваемый серверу URI является идентификатором, связанным с 
программой обработки этой формы на машине сервера. После того как будет 
отослан URI, отошлется и содержимое формы. 
    Итак, некоторые протоколы требуют, чтобы серверу отсылалось некоторое 
количество байтов дополнительной информации. Для того чтобы послать эти 
дополнительные байты серверу с помощью URL-соединения, следует открыть поток 
вывода посредством метода URLConnection.getOutputStream(). Но до этого 
необходимо вызвать метод setOutputStreamQ объекта URLConnection, который 
сообщит URL-соединению, надо или нет посылать серверу дополнительную 
информацию через поток вывода. Ниже приведен код метода, который посылает 
серверу некоторый массив байтов и возвращает результирующий поток ввода из URL-соединения: 

    public InputStream getPostedData!nputStream(URL url, byte[] ab, 
    int offset, int length) throws lOException { , // Обработка исключения 
lOException опущена, чтобы // не затруднять понимание примера. 
    // Установление соединения и отправка массива данных ab. 
    URLConnection conn = url.openConnection (); 
    conn.setDoOutput(true); 
    OutputStream os = conn.getOutputStream(); 
    os.write(ab, offset, length); 
    os.close () ; 
    // Если метод allowUserlnteractionО не вызван, следует •II закрыть поток 
OutputStream до открытия InputStream для // URLConnection. return conn.getlnputStream(); 
    }


    Типы содержимого ресурсов 

    Как было показано ранее, содержимое каждого ресурса в Internet имеет 
определенный тип, указывающий, информация какого вида в нем находится и в 
каком формате. Обычно тип содержимого описывается с использованием 

    286	Visual J++: основы программирования 

    строки вида "<type>/<subtype>". Например, изображения формата GIF имеют 
тип содержимого "image/gif', аудиофайлу соответствует тип содержимого 
"audio/an", HTML-файлу — "text/html", содержимое обыкновенного текстового 
файла имеет тип "text/plain". По соглашению, всем ресурсам, чей тип не 
определен, присваивается тип содержимого "application/octet-stream", и все они 
читаются как простой поток байтов. 
    Если объект URLConnection связался с сервером, то с помощью метода 
getContentTypeQ можно узнать тип содержимого ресурса. Есть ряд других общих 
свойств ресурсов, которые можно получить с помощью объекта URLConnection. 
Наряду с типом содержимого эти свойства передаются от сервера к клиенту через 
сетевое соединение до того, как посылаются данные ресурса. Каждое свойство 
представляется в текстовом виде, причем в одной строке посылается одно 
свойство. Формат таких строк обычно выглядит следующим образом: 

    property-type: property value 

    В следующей таблице перечислены свойства, доступные при помощи методов 
класса URLConnection, и описаны методы, используемые для получения этих свойств. 

    Метоп 

    Возвращаемая информация 

    getURL()	Возвращает URL, с помощью которого создано данное URL-соединение. 
Эта информация доступна в любой момент жизненного цикла объекта URLConnection. 
    getContentLength()         Возвращает объем (в байтах) содержимого 
ресурса. Эта информация становится доступной после того, как с помощью метода 
URLConnection.connect() устанавливается соединение, и только для некоторых 
ресурсов. Большинство HTTP-ресурсов такую информацию предоставляют, а многие 
FTP-ресурсы — нет. 
    getContentType()	Возвращает строку вида "<type>/<subtype>", описывающую 
тип и формат ресурса. Эта информация доступна для всех HTTP- и FTP-ресурсов. В 
случае неизвестных бинарных данных возвращается тип 
"application/octet-stream", в случае ресурсов с неизвестными текстовыми 
данными — тип "text/plain". 
    getContentEncodingO     Возвращает строку, описывающую дополнительную 
кодировку, примененную к данным. Например, данные могут быть представлены в zip-формате. 
    getExpiration()	Для многих ресурсов Internet устанавливается "срок 
годности", который позволяет узнать, в течение какого времени они достоверны. 
Например, биржевая котировка может быть действительна в течение 24 часов, а 
бета-версия технической спецификации — в течение 6 месяцев. 
    getDate()	Возвращает дату создания ресурса. 
    getLastModified()	Некоторые серверы и ресурсы содержат информацию о 
    времени последней  модификации ресурса.  Обычно эта 
    ______________информация не очень надежна, а часто и вовсе отсутствует. 

    Глава 9. Сетевые средства Java 287 


    Метоп	Возвращаемая информация 

    getHeaderField()	Возвращает любое другое свойство. Если методу передано 
имя свойства, он вернет строку значения свойства, если передано целое я— 
значение n-го свойства из заголовка. 
    getHeaderFieldInt()        Предполагает, что значением свойства является 
целое число, т.е. соответствующая строка заголовка имеет вид "Имя свойства: 
число". Возвращает значение свойства, указанного в качестве единственного 
входного параметра этого метода. 
    getHeaderFieldDate()      Предполагает, что значением свойства является 
дата. Единственным параметром метода является имя свойства, и его значение 
будет преобразовано в формат даты. Возвращает объект типа Date. 
    getHeaderfieldKeyO         Возвращает имя я-го свойства, связанного с 
ресурсом. Единственный параметр, передаваемый этому методу, — целое п. 


    Резюме 

    Родной "язык" Internet называется TCP/IP. Все подключенные к Internet 
машины "разговаривают" друг с другом при помощи протокола TCP/IP. Каждая такая 
машина имеет один или несколько адресов, которые идентифицируют массив 
виртуальных портов, используемых для получения и отправки пакетов данных. 
Класс InetAddress представляет в Java IP-адреса. Сокет — это соединение между 
двумя Internet-портами. Порты могут находиться на одной машине или на разных. 
    Для того чтобы с удаленным Internet-портом можно было связаться, на 
удаленной машине должна быть запущена программа-сервер, ожидающая (или 
"слушающая") запросы на новые соединения. Примерами таких программ являются 
HTTP-сервер и FTP-сервер. Используя объект типа Server-Socket, можно создать 
свой собственный сервер. Этот объект ожидает запросы на установление 
соединения с данным портом, и его метод acceptQ создает новый сокет при 
установлении каждого нового соединения. 
    URL — это универсальный форматированный "адрес" ресурса данных Internet. 
Такой ресурс может быть файлом, хранящимся на удаленной машине, или 
динамически генерируемой информацией. В частности он может быть статическим 
HTML-файлом или представлять точное время атомных часов. URL включает название 
протокола, имя машины (IP-адрес) и URI, который* указывает, какой ресурс 
требуется получить. URI похож на описание пути, в котором вместо обратной 
косой черты, принятой в качестве разделителя на Windows-платформах, 
используется обычная косая черта. 
    Класс URL представляет в Java отдельные URL. Используя этот класс, можно 
посредством метода getContentsQ запрашивать содержимое ресурса, на который 
ссылается URL. Кроме того, с помощью метода getlnputStreamQ можно 
устанавливать непосредственные соединения и самостоятельно загружать данные. 
Для передачи серверу дополнительной информации (некоторые протоколы, например 
HTTP, это позволяют) следует записать ее в поток вывода, возвращаемый методом 
getOutputStreamQ класса URL. 

    288	Visual J++: основы программирования 

