Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Васюткина Технология разработки програм java (Горячев).doc
Скачиваний:
135
Добавлен:
23.03.2016
Размер:
1.84 Mб
Скачать

Работа по протоколу tcp

Программы-серверы, прослушивающие свои порты, работают под управлением различных операционных систем. Чтобы сгладить различия в реализациях разных серверов, между сервером и портом введен промежуточный программный слой, названный сокетом (socket). Cлово socket переводится как электрический разъем, розетка. Так же как к розетке при помощи вилки можно подключить любой электрический прибор, к сокету можно присоединить любой клиент, лишь бы он работал по тому же протоколу, что и сервер. Каждый сокет связан (bind) с одним портом, говорят, что сокет прослушивает (listen) порт. Соединение с помощью сокетов устанавливается так.

1. Сервер создает сокет, прослушивающий порт сервера.

2. Клиент тоже создает сокет, через который связывается с сервером, сервер начинает устанавливать (accept) связь с клиентом.

3. Устанавливая связь, сервер создает новый сокет c новым номером, и сообщает этот номер клиенту.

4. Клиент посылает запрос на сервер через порт с новым номером.

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

В Java сокет — это объект класса Socket из пакета java.io. В классе шесть конструкторов, в которые разными способами заносится адрес хоста и номер порта. Чаще всего применяется конструктор Socket(String host, int port) .

Многочисленные методы доступа устанавливают и получают параметры сокета. Нам понадобятся методы, создающие потоки ввода/вывода:

getInputStream() — возвращает входной поток типа InputStream;

getOutputStream() — возвращает выходной поток типа OutputStream.

В приведенном примере 7.1 рассматриваются сервер и клиент, работающие по протоколу TCP. Клиент делает запрос на совершение действия, сервер выполняет это действие и возвращает результат. Получив запрос, сервер распознает тип операции по идентификатору, выполняет операцию и возвращает результат клиенту в виде целого числа. При малейшем подозрении на нарушение протокола сервер должен разрывать соединение с клиентом. Помните, что с сервером одновременно могут взаимодействовать тясычи клиентов, и если сервер упал, то все клиенты перестали работать.

Пример 7.1. Примитивный клиент

import java.net.Socket;

class Client{

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

// Имя хоста и номер порта

String host = "localhost";

int port = 3333;

// Протокол передачи

// Запрос (3 целых чила): [операция][аргумент 1][аргумент 2]

// Ответ (1 целое число): [результат]

// Операции: 0 - сложение, 1 - умножение

int operation = 1;

int arg1 = 5; int arg2 = 2;

try {

System.out.println("Client is running");

// запрос клиента на соединение

Socket sock = new Socket(host, port);

// Исходящий поток

DataOutputStream outStream = new DataOutputStream(

sock.getOutputStream());

// Отправляем запрос и аргументы

outStream.writeInt(operation);

outStream.writeInt(arg1);

outStream.writeInt(arg2);

// Входящий поток

DataInputStream inStream = new DataInputStream(

sock.getInputStream());

int d = inStream.readInt();

System.out.println("Result is " + d);

// Завершаем потоки и закрываем сокет

inStream.close(); outStream.close(); sock.close();

}

catch(Exception e) { System.err.println(e); }

}

}

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

Для создания серверного сокета в пакете java.net есть класс ServerSocket. В конструкторе этого класса указывается номер порта ServerSocket(int port). Основной метод этого класса accept() ожидает поступления запроса. Когда запрос получен, метод устанавливает соединение с клиентом и возвращает объект класса socket, через который сервер будет обмениваться информацией с клиентом. Обратите внимание, что для каждого клиента сервер создает свой поток, в котором происходит их взаимодействие.

Примитивный сервер

class Server {

public static void main(String[] args){

try {

System.out.println("Server is running");

int port = 3333;

// создание серверного сокета

ServerSocket ss = new ServerSocket(port);

// Ждет клиентов и для каждого создает отдельный поток

while (true) {

Socket s = ss.accept();

ServerConnectionProcessor p =

new ServerConnectionProcessor(s);

p.start();

}

}

catch(Exception e) { System.out.println(e); }

}

}

class ServerConnectionProcessor extends Thread {

private Socket sock;

public ServerConnectionProcessor(Socket s) {

sock = s;

}

public void run() {

try {

// Получает запрос

DataInputStream inStream = new DataInputStream(

sock.getInputStream());

int operationId = inStream.readInt();

int arg1 = inStream.readInt();

int arg2 = inStream.readInt();

// Выполняет расчет

int result = 0;

if (operationId == 0) { result = arg1 + arg2; }

else if (operationId == 1) { result = arg1 * arg2; }

// Отправляет ответ

DataOutputStream outStream = new DataOutputStream(

sock.getOutputStream());

outStream.writeInt(result);

// Подождем немного и завершим поток

sleep(1000);

inStream.close(); outStream.close(); sock.close();

}

catch(Exception e) { System.out.println(e); }

}

}

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