Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
СистПриклПрогЗабез(Хихловская).doc
Скачиваний:
25
Добавлен:
10.02.2016
Размер:
961.02 Кб
Скачать

1.2 Разработка программ в архитектуре “клиент-сервер”

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

  1. Нижний, отвечающий за методы хранения доступа, разделения данных,-- поставляемый

  2. Верхний, отвечающий за логику обработки данных и интерфейс пользователя –собой.

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

Второй не требовал наличия высокопроизводительной системы вычислений и включая в себе собственно алгоритм логику и весь интерфейс, созданный разработчиком программы. Так сложилось понятие приложения, построенного на архитектуре «клиент -сервер».

Первый уровень, сервер, включает методы, связанные с доступом данных; их реализует сервер БД из соответствующей СУБД в комплекте с драйверами доступа к телу.

Второй уровень, клиент, взаимодействует, с одной стороны, с сервером, получая от него данные, а с другой стороны – с пользователем, ресурсами приложения и ОС, осуществляя обработку данных и отображение результатов. Результаты обработки клиент опять-таки может сохранить в обработку данных и отображение результатов. Результаты обработки клиент опять-таки может сохранить в БД, используя функции серверной части. Многие известные фирмы стали предлагать стандартные интерфейсы для доступа к создаваемым им СУБД. Изменилась и структура систем программирования; они стали ориентироваться на создание в архитектуре, клиент - сервер. Предлагаемые или средства поставляются в составе систем программирования и поддерживают возможность работы с широким диапазоном известных серверов данных через один или несколько доступных интерфейсов обмена данными. Разработчик прикладной программы выбирает одно из доступных средств и возможный тип сервера. Тогда задача сводится только к созданию клиентской части приложения, построенной на основе выбранного интерфейса. В дальнейшем использовать приложение можно только в комплексе. Интерфейс обмена данными входит в систему программирования и свободно распространяется.

Серверная часть распространяется только по лицензиям, надо лицензировать средства создания и отладки БД, но результаты работы могут распространяться. Либо в случае мощных серверов, лицензия нужна на и распространение серверной части приложение. В этом случае конечный пользователь получает комплекс программы, продуктов от множества разработчиков. Развитием архитектуры программирования «клиент – сервер» явилась трехуровневая архитектура. Клиентская часть разделилась на две составляющие: сервер приложений и «тонкий клиент, обеспечивающий интерфейс доступ к результатам обработки. Серверная часть, сервер без данных, осталась без изменений. Взаимодействие между сервером приложений и тонким клиентом должно быть тесным, а, с другой стороны, должен обмениваться данными по протоколам интернет, которые стандартизованы, например, COM/DCOM, CORBA и другие (COMMON Object Reguest Broklr Architecture)

Пример простого ТСР – клента

  1. #include<sys/types.h>

  2. #include<sys/socket.h>

  3. #include<netinet/in.h>

  4. #include<arpa/inet.h>

  5. #include<stdio.h>

  6. int main (void)

  7. {

  8. struct sockaddr_in peer;

  9. int d;

  10. int rc;

  11. char buf [ 1 ];

  12. peer.sin_family = AF_INET;

  13. peer.sin_pott = Atons( 7500 );

  14. peer.sin_addr.s addr = inet_addr(“127.0.0.1”);

  15. S = socket (AF_INET, SOCK_STREAM, 0 );

  16. If ( s < 0)

  17. {

  18. perror( «ошибка вызова sockett»);

  19. exit ( 1 );

  20. }

  21. rc=connect ( s, ( struct sockaddr * )&peer, sizeof( peer) );

  22. if ( rc<=0 )

  23. {

  24. perror ( «ошибка вызова connect» );

  25. exit ( 1 );

  26. }

  27. rc = send ( s, “1”, 1, 0 );

  28. if ( rc <= 0 )

  29. {

  30. perror («ошибка вызова send» );

  31. exit ( 1 );

  32. }

  33. rc = recv( s, buf, 1, 0 );

  34. if ( rc <= 0 )

  35. perror( «ошибка вызова reccv» );

  36. else

  37. printf ( “%\n”, buf [ 0 ];

  38. exit( 0 );

  39. }

Подготовка адреса сервера:

12 – 14 Заполнение структуры sockaddr­_in путем записи в ее поля номера порта (7500) и адреса 127.0.0.1 – это возвратный адрес, который означает, что сервер находится на той же машине, что и клиент.

Получение сокета и соединение с сервером:

15 – 20 Получение сокета типа SOCK_STREAM, т.к. используется потоковый протокол ТСР.

21 – 26 Установка соединения с сервером путем обращения к системному вызову connect. Это вызов нужен, чтобы сообщить ядру адрес сервера.

Отправка и получение одного байта

27 – 38 Сначала один байт серверу, затем из сокета читается один байт и записывается в стандартный вывод. Сеанс завершается.

Перед тестированием клиента следует подготовить сервер.

Сервер должен быть готов к установлению соединений с клиентами. Для этого он должен прослуживать известный ему порт с помощью системного вызова listen.

Рисунок – Основные вызовы API сокетов для сервера.

Но предварительно необходимо привязать адрес интерфейса и номер к прослеживающему сокету. Для этого предназначен вызов bind.

#include <sys/socket.h>/*UNIX*/

#include <winsock2.h>/*windows*/

int bind( socket s, const sockaddr*name, int namelen );

Возвращаемое значение:0 – нормально, -1 или SOCKET_ERROR (Windows) – ошибка

Параметр s – это дескриптор просуживающего сокета. С помощью параметров name и namelen передаются порт и сетевой интерфейс, которые нужно прослеживать. Обычно в качестве адреса задается константа INADDR_ANY. Это означает, что будет прямое соединение, запрашиваемое по любому интерфейсу. Если хосту с несколькими сетевыми адресами нужно принимать соединение только по одному интерфейсу, нужно указать IP – адрес этого интерфейса. Через namelen обозначается длина структуры sockaddr_in.

После привязки локального адреса к сокету нужно перевести сокет в режим прослушивания входящих соединений с помощью системного вывода listen. Его задача – пометить сокет как прислуживающий. Когда хосту поступает запрос на установление, ядро ищет для которого адрес назначения и номер порта соответствуют указанным в запросе.

#include <sys/socket.h>/*UNIX*/

#include <winsock2.h>/*windows*/

int listen( SOCKET s, int backlog );

0 – нормально; -1(UNIX) или SOCKET_ERROR (Windows) – ошибка.

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

Вызов accept служит для приема соединения, ожидающего во входной очереди. После того, как соединение принято, его можно использовать для передачи данных, например, с помощью вызовов recv и send. В случае успеха accept возвращает дескриптор нового сокета, по которому будет происходить обмен данными. Номер локального порта для этого сокета такой же, как и для прослушивающего сокета. Адрес интерфейса, на котором поступил запрос о соединении, называется локальным. Адрес и номер порта клиента считаются удаленными. Оба сокета имеют один и тот же номер локального порта. Это справедливо, т.к. ТСР – соединение полностью определяется четырьмя параметрами – локальным адресом, локальным портом, удаленным адресом, удаленным портом. Т.к. удаленный адрес и порт для этих двух сокетов различны, то ядро может отличить их друг от друга.

#include <sys/socket.h>/*UNIX*/

#include <winsock2.h>/*windows*/

int assept (socket s, structs sockaddr*addr, int*addrlen);

возвращаемое значение: 0 – нормально, -1 (UNIX) или WALID_SOCKET(Windows) – ошибка.

Параметр s – это дескриптор прослушивающего сокета. Как показано на рисунке 3, accept возвращает адрес приложения на другом конце соединения в структуре sockaddr_in, на которое указывает параметр addr, ядро присваивает значение, равное длине этой структуры. Часто нет необходимости знать адрес клиентского приложения, поэтому в качестве addr будет перезадаваться NULL. Приведенная ниже программа демонстрирует структуру сервера и элементарные вызовы API сокетов, которые обязан выполнить любой сервер.

Простой ТСР – сервер.

  1. #include<sys/types.h>

  2. #include<sys/socket.h>

  3. #include<netinet/in.h>

  4. #include<stdio.h>

  5. int main (void)

  6. {

  7. struct sockaddr_in local;

  8. int s;

  9. int sl;

  10. int rb;

  11. char buf [ 1 ];

  12. local.sin_family = AF_INET;

  13. local.sin_port = htons ( 7500);

  14. local.sin_addr.s addr = htonl (INADDL_ANY);

  15. s=socket (AF_INET, SOCK_STREAM,0);

  16. if (s<0)

  17. {

  18. perror («ошибка вызоваsocket»);

  19. exit (1);

  20. }

  21. rc = bind (s, (struct sockaddr*)&local, sizeof(local));

  22. if (rc<0)

  23. {

  24. perror («ошибка вызоваbind»);

  25. exit (t);

  26. }

  27. rc = listen (s,5);

  28. if (rc)

  29. {

  30. perror («ошибка вызоваlisten»);

  31. exit (1);

  32. }

  33. s1=assept (s,NULL, NULL);

  34. if (s1<0)

  35. {

  36. perror («ошибка вызоваassept»);

  37. exit (1);

  38. }

  39. rc = recv (sl, buf, 1, 0);

  40. if (rc<=0)

  41. {

  42. perror («ошибка вызоваrecv»);

  43. exit (1);

  44. }

  45. print (“%^c\n”, buf [0]);

  46. rc = send (s1,”2”, 1, 0);

  47. if (rc <=0)

  48. perror («ошибка вызоваsend»);

  49. exit (0)

  50. }