Пример приложения клиент/сервер на языке Java
С помощью следующего приложения мы осветим вопросы программирования сокетов как для протокола TCP, так и для протокола UDP. Приложение функционирует следующим образом.
1. Клиент считывает со стандартного устройства ввода (клавиатуры) строку символов и посылает эту строку серверу через свой сокет.
2. Сервер принимает строку через свой сокет.
3. Сервер переводит все символы строки в верхний регистр.
4. Сервер отсылает модифицированную строку клиенту.
5. Клиент получает строку и печатает ее с помощью стандартного устройства вывода (монитора).
Мы начнем с рассмотрения приложения, в котором взаимодействие клиента и сервера осуществляется через логическое соединение по протоколу TCP (рис. 2.20).
Ниже мы приведем тексты программ для клиентской и серверной сторон приложения и снабдим пояснениями каждую строку кода. Программа-клиент названа TCPClient.java, программа-сервер — TCPServer.java. Отметим, что приведенные программы лишь иллюстрируют ключевые фрагменты приложения и не претендуют на то, чтобы называться «хорошими» с точки зрения практического применения. Для улучшения программ приведенные тексты следовало бы снабдить несколькими дополнительными строками.
После компиляции обеих программ (каждой на своем компьютере) первой запускается программа-сервер, поскольку для установления соединения серверный процесс должен ожидать запроса со стороны клиентского процесса. Клиентский процесс создается после запуска программы-клиента, и в его функцию входит инициирование TCP-соединения с сервером. После того как соединение установлено, пользователь, находящийся на клиентской стороне, может вводить строки символов и получать их обратно в верхнем регистре.
Ниже приведен текст программы TCPClient.java.
import java.io.*;
import java.net.*;
class TCPClient {
public static void main(String argv[]) throws Exception
{
String sentence;
String modifiedSentence;
BufferedReader inFromUser =
new BufferedReader(
new InputStreamReader(System.in));
Socket clientSocket = new Socket («hostname». 6789);
DataOutputStream outToServer =
new DataOutputStream(
clientSocket.getOutputStream());
BufferedReader inFromServer =
new BufferedReader(
new InputStreamReader(
cli entSoket.getInputStream()));
sentence = inFromUser.readLine();
outToServer.writeBytes(sentence + ‘\n’);
modifiedSentence = inFromServer.readLine();
System.out.printing «FROM SERVER: » + modifiedSentence);
clientSocket.close();
}
}
Как показано на рис. 2.21, программа TCPClient создает три потока данных и один сокет.
Сокет имеет название clientSocket. Поток inFromUser является входным потоком данных программы и связан со стандартным устройством ввода (клавиатурой). Все символы, вводимые с клавиатуры пользователем, попадают в поток inFromUser. Другой входной поток данных программы, inFromServer, связан с сокетом и состоит из символов, передаваемых серверной стороной приложения. Выходной поток данных программы TCPClient имеет название outToServer и также связан с сокетом. Этот поток содержит символы, передающиеся серверу для обработки.
Теперь рассмотрим приведенный код подробнее. Первые две строки содержат имена
двух Java-пакетов, java i’о и java. net:
import java.io.*;
import java.net.*;
Пакет java.io содержит классы входных и выходных потоков данных. Обычно этими классами являются BufferedReader и DataOutputStream, которые и были использованы в программе. Пакет java.net хранит классы, поддерживающие работу с компьютерной сетью (Socket и ServerSocket). Объект clientSocket программы порожден классом Socket.
class TCPClient {
public static void main(String argv[]) throws Exception
{……}
}
Конструкции, аналогичные приведенной выше, являются стандартными в практике программирования на Java. Первая строка представляет собой начало блока определения класса. В ней присутствует ключевое слово class и имя определяемого класса TCPClient. Класс может содержать переменные и методы; в объявлении класса они заключены в фигурные скобки и фактически составляют блок определения класса. В классе TCPClient нет переменных, он содержит единственный метод с именем main(). Методы похожи на процедуры и функции языков, подобных С; метод main() также играет роль, схожую с функцией main() в С или С++. Когда интерпретатор Java исполняет приложение (будучи вызванным управляющим классом приложения), он обращается к методу main() этого класса. Метод mainQ вызывает все остальные методы, используемые в приложении. Если в данный момент вы впервые сталкиваетесь с Java-приложением, можете не обращать внимания на ключевые слова public, static, void, main и throws Exception.
String sentence;
String modifiedSentence;
Приведенные две строки являются объявлениями объектов типа String. Объект sentence предназначен для хранения строки, вводимой пользователем и передаваемой серверу. Объект modifiedSentence содержит строку, принимаемую от сервера и выводимую на стандартное устройство вывода.
BufferedReader inFromUser =
new BufferedReader(new InputStreamReaderCSystem.in));
Здесь происходит создание потокового объекта in From User типа BufferedReader. Инициализация потока данных производится объектом System.in, связывающим поток со стандартным устройством ввода. После выполнения этой команды клиенту начинают передаваться символы, вводимые пользователем с клавиатуры.
Socket clientSocket = new Socket («hostname», 6789);
В приведенной строке происходит создание объекта clientSocket типа Socket. Кроме того, при этом инициируется TCP-соединение между клиентом и сервером. Слово hostname необходимо заменить именем хоста, сохранив кавычки (например, «_fling.seas.upenn.edu»). Перед началом установки TCP-соединения клиент производит DNS-запрос IP-адреса хоста. Значение 6789 — это номер порта; вы можете выбрать другое число, однако необходимо помнить, что клиентская и серверная стороны должны использовать один и тот же номер порта. Как упоминалось ранее, IP-адрес хоста в совокупности с номером порта приложения идентифицирует серверный процесс.
DataOutputStream outToServer =
new DataOutputStream(clientSocket.getOutputStream());
BufferedReader inFromServer =
new BufferedReader(new InputStreamReader(clientSoket.getlnputstream()));
Здесь происходит создание потоковых объектов, связанных с сокетом. Поток outToServer обеспечивает вывод программы через сокет, а поток inFromServer предназначен для приема данных от серверной стороны (см. рис. 2.21).
sentence = inFromUser. readLineO;
Эта строка помещает последовательность символов, вводимых пользователем, в переменную sentence. Ввод оканчивается нажатием пользователем клавиши Enter. Как видим, для помещения символов в переменную используется потоковый объект inFromUser.
outToServer.writeBytes(sentence + ‘\n’);
Здесь строка sentence, снабженная символом возврата каретки, помещается в выходной поток outToServer. После этого она будет передана через сокет в канал, соединяющий клиента с сервером.
modifiedSentence = inFromServer. readLineO;
Ответ сервера принимается во входной поток inFromServer, откуда принятая строка копируется в переменную modifiedSentence. Помещение символов в строку modifiedSentence продолжается до тех пор, пока не будет получен символ возврата каретки.
System.out.println(«FROM SERVER: » + modifiedSentence);
Здесь происходит вывод принятой от сервера строки на монитор,
clientSocket.close();
Эта строка закрывает сокет, а следовательно, и TCP-соединение между клиентом и сервером. Как будет показано в главе 3, исполнение этой команды ведет к отправке TCP-клиентом сообщения ТСР-серверу.
Ниже приведен текст программы TCPServer.java.
import java.io.*;
import java.net.*;
class TCPServer {
public static void main(String argv[]) throws Exception
{
String clientSentence;
String capitalizedSentence;
ServerSocket welcomeSocket = new ServerSocket (6789);
while (true) {
Socket connectionSocket = welcomeSocket.
accept();
BufferedReader inFromClient =
new BufferedReader(new InputStreamReaderC
connectionSocket.getInputStream()));
DataOutputStream outToClient =
New DataOutputStreamC connectionSocket.getOutputStream());
clientSentence = inFromClient. readLineO; capitalizedSentence =
clientSentence.toUpperCaseO + ‘\n’;
outToClient.writeBytes(capitalizedSentence);
}
}
}
Программа TCPServer имеет много общего с программой TCPClient; рассмотрим ее подробнее, опустив строки, общие с программой TCPClient и описанные выше.
ServerSocket welcomeSocket = new ServerSocket (6789);
Здесь происходит создание объекта welcomeSocket типа ServerSocket. Объект welcomeSocket представляет собой впускающий сокет, с помощью которого клиент устанавливает первоначальный контакт с сервером. Для этого сокета используется порт с номером 6789, совпадающим с номером порта сокета клиента (мы раскроем причины совпадения номеров портов сокетов клиента и сервера в главе 3). Протокол TCP устанавливает прямой виртуальный канал между сокетом clientSocket на клиентской стороне и connectionSocket на серверной стороне, после чего клиент и сервер могут свободно осуществлять обмен информацией. После создания сокета connectionSocket сервер может вновь использовать сокет welcomeSocket для инициирования других соединений с клиентами (приведенная программа не обрабатывает новых соединений, однако ее можно модифицировать соответствующим образом).
Далее программа создает несколько потоковых объектов, аналогичных clientSocket.
capitalizedSentence = clientSentence.toUpperCaseO + ‘\n’;
та команда основная в приложении. Она выполняет получение строки, передаваемой клиентом, перевод строки в верхний регистр с помощью метода tollpperCase() и добавление в конец символа возврата каретки. Все остальные команды программы являются периферийными и не касаются взаимодействия сервера с клиентом.
Для того чтобы протестировать совместную работу наших программ, следует поместить их на разные хосты и указать в программе TCPClient имя хоста-сервера. Затем необходимо запустить программу TCPServer, чтобы создать серверный процесс. Серверный процесс будет находиться в состоянии ожидания до тех пор, пока клиентский процесс не инициирует TCP-соединение; для этого, в свою очередь, нужно запустить программу TCPClient. Наконец, чтобы проверить наше приложение в действии, следует ввести на стороне клиента строку, оканчивающуюся символом возврата каретки (он вводится нажатием клавиши Enter).
Используя приведенные тексты программ, вы можете создать собственное приложение клиент/сервер. Например, вы можете изменить работу сервера таким образом, что вместо перевода строки в верхний регистр он будет подсчитывать количество букв «s» в ней.
ни подскажите , откудо я могу найти литературу про client-server opplication ????
Толку от этой статьи, если с ней разберется только тот, кто понимает, что символ C надо заменить на открывающую скобку, и почему надо поменять одни кавычки на другие кавычки…
Спасибо за статью, все очень понятно и подробно.
Отличная статья! Спасибо!!
Отличная статья, просто и доступно.
Spasibo vam bolwoe! O4en’ pomoglo
->Garegin: ни подскажите , откудо я могу найти литературу про client-server opplication ????
Лучше букварь сначала:))) А то будет «Opplication.getInstance…»
Спасибо, большое! Все понятно!
Хорошие описание, но код слегка корявый! Не смотря на то что я нупчик в JAVA их удалось исправить. Хочу из этого сначала просто чат сделать со SWING, а затем и голосовой может быть.