Программирование >>  Oracle 

1 ... 456 457 458 [ 459 ] 460 461 462 ... 469


1800

Приложение А

tkyte@TKYTE816> CREATE OR REPLACE PACKAGE simple tcp client

2 as

3 - Функция для подключения к хосту. Возвращает сокет ,

4 - который на самом деле представляет собой просто число.

5 function connect to(p hostname in varchar2,

6 p portno in number) return number;

8 - Передача данных. Мы знаем только, как посылать данные типа

9 - RAW. Вызывающие должны приводить данные типа VARCHAR2 к ти 10 - RAW. На низком уровне, все проходящие через сокет данные -

-> байты.

12 procedure send(p sock in number,

13 p data in raw);

15 - Процедура recv предназначена для получения данных.

16 - Если maxlength еет значение -1, мы попытаемся получить

17 - 4 Кбайт данных. Если maxlengthis еет ЛЮБОЕ значение, кроме

18 - -1, мы попытаемся прочитать все байты данных p data. Други

19 - словами, я ограничиваю объем получаемых данных до 4 Кбайт, -> если не сказано иначе.

2 0 procedure recv(p sock in number,

21 p data out raw,

22 p maxlength in number default -1);

2 4 - Получает строку данных из входного сокета. Т.е. данные

2 5 - вплоть до ствола новой строки, \n.

2 6 procedure getline(p sock in number, 27 p data out raw);

28 29

3 0 - Обеспечивает отключение от сервера.

31 procedure disconnect(p sock in number); 32

33 - Получает время сервера по Гринвичу (GMT) в формате yyyyMMdd

34 HHmmss z procedure get gmt(p gmt out varchar2); 35

3 6 - Получает часовой пояс сервера. Полезно для некоторых -> протоколов Internet.

37 procedure get timezone(p timezone out varchar2); 38

3 9 - Получает имя хоста, на котором работает ваш сервер. Это тоже

40 - пригодится для некоторых протоколов Internet.

41 procedure get hostname(p hostname out varchar2);

43 - Возвращает количество байтов, которые можно прочитать.

44 function peek(p sock in number) return number;

46 - Кодирует данные типа RAW алгоритмом base64. Пригодится для

47 - отправки вложений в сообщениях электронной почты или при

48 - работе по протокол HTTP, требующему скрывать -> пользователя/пароль путем кодования с помощью base64.



Пакет UTL TCP 1801

49 procedure b64encode(p data in raw, p result out varchar2) ;

50 end;

51 /

Package created.

Поскольку ни одну из этих функций нельзя реализовать на PL/SQL, мы реализуем их на языке Java. Java-код, необходимый для этого, на удивление, невелик - занимает всего 94 строки. Будем использовать стандартный класс Socket языка Java и поддерживать небольшой массив сокетов, обеспечивающий в PL/SQL возможность поддерживать одновременно до десяти подключений. Если необходимо более десяти подключений, увеличьте размер массива socketUsed в представленном далее коде. Я пытался сделать код как можно проще и короче, предпочитая основную работу выполнять с помощью PL/SQL. Я представлю небольшой класс, который нам понадобится, и прокомментирую его:

tkyte@TKYTE816>set define off

tkyte@TKYTE816> CREATE or replace and compile JAVA SOURCE

2 NAMED jsock

3 AS

4 import java.net.*;

5 import java.io.*;

6 import java.util.*;

7 import java.text.*;

8 import sun.misc.*; 9

10 public class jsock

11 {

12 static int socketUsed[] = { 0,0,0,0,0,0,0,0,0,0 };

13 static Socket sockets[] = new Socket[socketUsed.length];

14 static DateFormat tzDateFormat = new SimpleDateFormat( z );

15 static DateFormat gmtDateFormat =

16 new SimpleDateFormat( yyyyMMdd Hss z ) ;

17 static BASE64Encoder encoder = new BASE64Encoder(); 18

В этом классе есть несколько статических переменных. Основные - это массивы socketUsed и sockets. При вызове функций из PL/SQL мы должны возвращать что-то, что можно будет передать в последующих вызовах для идентификации используемого сокета подключения. Мы не можем возвращать объекты Java-класса Socket в PL/SQL-подпрограммы, поэтому я использую массив, в котором они хранятся, и возвращаю в PL/SQL индекс этого массива. Метод java connect to просматривает массив socketsUsed в поисках пустого слота и выделяет этот слот подключению. Именно индекс в массиве socketsUsed и возвращается PL/SQL-подпрограммам. Эта особенность используется во всех остальных функциях работы с сокетами для получения доступа к фактическому Java-объекту, представляющему сокет.

Остальные статические переменные используются для повышения производительности. Мне необходимы объекты, форматирующие дату, и для того, чтобы не создавать их каждый раз при вызове java get gmt или java get timezone, я выделяю их один раз и в дальнейшем использую при необходимости. Наконец, объект для выполнения кодиро-



1802 Приложение А

вания по алгоритму base 64. По той же причине, что и объекты для форматирования даты, я выделяю объект encoder.

Теперь рассмотрим функции для подключения к серверу по протоколу TCP/IP. Мы проходим в цикле по массиву socketUsed в поисках пустого слота (для которого значение socketUsed[I] отлично от 1).Если мы находим пустой слот, используется Java-класс Socket для подключения к указанному хосту/порту, и флаг socketUsed для этого слота массива устанавливается равным 1. В случае ошибки (нет свободного слота) возвращается значение -1; в случае успешного подключения - положительное число:

19 static public int java connect to(String p hostname, int p portno)

2 0 throws java.io.IOException

21 {

22 int i;

24 for(i = 0; i < socketUsed.length && socketUsed[i] == 1; i + ;

25 if (i < socketUsed.length)

26 {

27 sockets[i] = new Socket(p hostname, p portno);

28 socketUsed[i] = 1;

29 }

3 0 return i<socketUsed.length?i:-l; 31 }

Следующие две Java-функции вызываются чаще всего. Они отвечают за передачу и прием данных через подключенный TCP/IP-сокет. Функция java send data понятна: она получает выходной поток, соответствующий сокету, и в]дает в него данные. Функция java recv data несколько сложнее. Она использует для возврата данных параметры типа OUT, отсюда, например, и объявление int[] plength. Эта функция проверяет длину данных, переданных вызывающим, и, если она имеет значение -1, выделяет для чтения буфер размером 4 Кбайт; в противном случае она выделяет буфер указанного размера. Затем она пытается прочитать из сокета соответствующий объем данных. Реальный объем прочитанных данных (который будет меньше или равен затребованному) возвращается как результат в параметре p length:

34 static public void java send data(int p sock, byte[] p data)

35 throws java.io.IOException

36 {

37 (sockets[p sock].getOutputStream()).write(p data);

38 }

40 static public void java recv data(int p sock,

41 byte[][] p data, int[] plength)

42 throws java.io.IOException

43 {

44 p data[0] = new byte[p length[0] = -1 ? 4096:p length[0] ];

45 p length[0] = (socketstp sock].getInputStream()).read(p data[0]);

46 } 47



1 ... 456 457 458 [ 459 ] 460 461 462 ... 469

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика