|
Программирование >> Oracle
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
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |