Материал: metod_ukaz

Внимание! Если размещение файла нарушает Ваши авторские права, то обязательно сообщите нам

закрыть соединение с клиентом;

закрыть сокет для работы с клиентом;

закрыть «слушающий» сокет;

}

Для случая сервера, работающего без установления соединения, отсутствует поток ожидания соединения, а потоки приема, обработки и передачи создаются сразу после создания и инициализации сокета.

Шаблон программы-клиента для случая TCP-соединения представлен ниже:

объявить сокет для работы с сервером

объявить флаг завершения потока установления соединения;

объявить флаг завершения потока передачи запросов;

объявить флаг завершения потока приема ответов;

функция передачи запросов()

{

пока (флаг завершения потока передачи запросов не установлен)

{

задержка на время;

создать запрос;

передать запрос в сокет;

}

}

функция приема ответов()

{

пока (флаг завершения потока приема ответов не установлен)

{

принять ответ из сокета;

вывести ответ на экран;

}

}

функция установления соединения()

{

пока (флаг завершения потока установления соединения не установлен)

{

установить соединение с сервером;

если соединение установлено

{

создать поток передачи запросов;

создать поток приема ответов;

завершить работу потока;

}

}

}

основная функция()

{

объявить идентификатор потока установления соединения;

объявить идентификатор потока передачи запросов;

объявить идентификатор потока приема ответов;

создать сокет для работы с сервером;

создать поток установления соединения;

ждать нажатия клавиши;

установить флаг завершения потока передачи запросов;

установить флаг завершения потока приема ответов;

установить флаг завершения потока установления соединения;

ждать завершения потока установления соединения;

ждать завершения потока передачи запросов;

ждать завершения потока приема ответов;

закрыть соединение с сервером;

закрыть сокет;

}

Для случая клиента, работающего без установления соединения, отсутствует поток установления соединения, а потоки передачи и приема создаются сразу после создания и инициализации сокета.

В сервере каждый студент реализует функцию, на которую указывает строка таблицы. Номер функции соответствует номеру студента в списке группы.

Номер

Функции

1

uname - получение системной информации

2

sysinfo - получение системной информации Linux

3

sysconf - получение значения системной переменной

4

statfs - получение статуса файловой системы

5

stat - получение статуса файла

6

pathconf - получение информации о файле

7

получение даты и времени в формате ГГГГ.ММ.ДД ЧЧ:мм:СС

8

getsockopt - получение установок опций сокета

9

getsockname - получение адреса сокета

10

gethostbyname - получение информации о хосте по его имени

11

getaddrinfo - возвращает одну или несколько структур addrinfo, каждая из которых содержит Интернет-адрес

12

getrusage - сводка ресурсов

13

getrlimit - получение лимита ресурсов

14

getegid - получение эффективного id группы

getgrgid –получение инфо о группе по id

getgrnam –получение инфо о группе по имени

15

getgid - получение id группы

getgrgid–получение инфо о группе по id

getgrnam –получение инфо о группе по имени

16

getgroups - получение дополнительных групп

17

geteuid - получение эффективного id пользователя

getpwuid получение информации о пользователе по id

getpwnam получение информации о пользователе по имени

18

getuid - получение действительного id пользовател

getpwuid получение информации о пользователе по id

getpwnam получение информации о пользователе по имени

19

getpriority - получение приоритета (процесса, группы, пользователя)

20

getpgid - получение id группы родителя заданного процесса

21

getpgrp - получение id группы родителя текущего процесса

22

getpid - получение id текущего процесса

23

getppid - получение id родительского процесса

24

getpagesize - получение размеров страницы в системе

25

gethostid - получение уникального идентификатора основной системы

Вопросы для самопроверки

  1. Каким образом обеспечить одновременную работу сервера с несколькими клиентами?

  2. Каким образом обеспечить работу клиента с многократным соединением и разъединением с сервером?

  3. Каким образом обеспечить работу программ сервера и клиента без блокировки функций приема, ожидания и установления соединения?

  4. Как на стороне сервера определить адрес клиента, который установил соединение?

  5. Как обеспечить обмен сообщениями между двумя программами через сокеты без установления соединения?

  6. Какие прикладные протоколы, основанные на протоколах TCP и UDP, существуют?

  7. Как обработать случай, когда вторая сторона некорректно разрывает соединение?

  8. Обоснуйте целесообразность вызова функций accept() и connect() в отдельных потоках.

  9. Какие параметры сокета необходимо использовать для осуществления обмена данными между локальными процессами?

Раздел 4. Управление информацией в ос

10. Создание и использование библиотек

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

Общие сведения

Библиотека – это средство многократного использования объектного кода.

Библиотеки бывают двух видов – статические и динамические.

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

Использование динамической библиотеки может осуществляться двумя способами.

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

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

При использовании статических библиотек программа получается большего размера (по сравнению с программой, использующей динамические библиотеки), поскольку код библиотеки содержится в коде программы. Но при выполнении такой программы нет необходимости загружать библиотеки, что приводит к большей скорости выполнения.

Использование статических библиотек

Предположим, что у нас есть код, который требуется оформить как статическую библиотеку.

Код выглядит следующим образом.

Заголовочный файл kia.h содержит объявление следующих функций:

void kiaInit();

void kiaClose();

void kiaSend(char*, int);

void kiaReceive(char*, int&);

Файл kia.cpp содержит реализацию этих функций:

#include "kia.h"

void kiaInit()

{

…

}

void kiaClose()

{

…

}

void kiaSend(char * ba, int size)

{

…

}

void kiaReceive(char * ba, int & size)

{

…

}

Следующая команда компилятора превратит исходный код, содержащийся в файле kia.cpp, в объектный код kia.o:

g++ -c kia.cpp

Чтобы из полученного объектного кода создать статическую библиотеку, необходимо использовать команду ar следующим образом:

ar cr libkia.a kia.o

Использование динамических библиотек Создание динамической библиотеки

Будем использовать ту же пару – заголовочный файл kia.h и файл реализации kia.cpp, что и в предыдущем примере.

Компиляцию файла kia.cpp необходимо выполнить с ключем –fPIC (Position-Independent Code – позиционно-независимый код):

g++ -c -fPIC kia.cpp

Чтобы из полученного объектного кода создать динамическую библиотеку, необходимо использовать команду g++ следующим образом:

g++ -shared –fPIC –o libkia.so kia.o

В результате получаем динамическую библиотеку – файл libkia.so.

Загрузка динамической библиотеки вместе с загрузкой программы

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

Будем использовать предыдущий вариант – программу prog.cpp.

Компиляция программы выполняется так же, как и в предыдущем случае. Результатом компиляции является файл prog.o.

Помещаем файл libkia.so в один каталог с файлом prog.o (для простоты) и вызываем команду сборки с подключением динамической библиотеки:

g++ -o prog prog.o -L. -lkia

В результате сборки получаем исполняемый файл prog. Однако запустить программу, например, командой “./prog” не удастся. Дело в том, что при запуске программа ищет библиотеки в определенных каталогах, а именно, в каталогах /lib и /usr/lib.

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

Это может быть сделано с помощью переменной LD_LIBRARY_PATH. Необходимо передать этой переменной список всех дополнительных каталогов, в которых необходимо искать библиотеки. В нашем случае это текущий каталог, поэтому присвоение этой переменной значения текущего каталога будет выглядеть следующим образом:

LD_LIBRARY_PATH = .

Запускать программу следует с использованием данного присвоения, а именно:

LD_LIBRARY_PATH = . ./prog

Загрузка динамической библиотеки по запросу из программы

В этом случае динамическая библиотека загружается в программе системным вызовом dlopen(). Вызов имеет следующий шаблон:

void *dlopen(const char *filename, int flag);

где:

const char *filename – имя файла динамической библиотеки;

int flag – флаг, указывающий на способ разрешения неопределенных символов библиотеки. Варианты флагов можно узнать из справочного руководства, набрав команду: man dlopen.

Результатом работы функции является ссылка на загруженную динамическую библиотеку.

Чтобы определить адрес требуемой функции, входящей в динамическую библиотеку, необходимо вызвать функцию:

void *dlsym(void *handle, char *symbol);

где:

void *handle – ссылка на загруженную библиотеку;

char *symbol – строка символов – имя функции.

Результатом работы функции является адрес функции, которую требуется выполнить в программе.

Например, если функция в библиотеке имеет шаблон:

void kiaInit();

то в программе надо объявить переменную:

void (*func)(void);

Команда ar создает архивы, которые представляют собой статические библиотеки.

Параметр “c” – параметр создания архива;

параметр “r” – параметр добавления файлов в архив;

libkia.a – имя архивного файла – статической библиотеки;

kia.o – имя добавляемого в архив файла.

Подробности о команде ar можно узнать из справочного руководства man.

В результате получаем статическую библиотеку – файл libkia.a.

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

Упрощенный пример программы prog.cpp выгдядит следующим образом:

#include "kia.h"

int main()

{

char buffer[256];

int size;

kiaInit();

kiaSend(buffer,size);

kiaReceive(buffer,size);

kiaClose();

}

Помещаем файлы prog.cpp и kia.h в один каталог (для простоты) и вызываем команду компиляции:

g++ -c prog.cpp

Результатом выполнения команды является файл prog.o.

Помещаем файл libkia.a в один каталог с файлом prog.o (для простоты) и вызываем команду сборки с подключением статической библиотеки:

g++ -static -o prog prog.o -L. -lkia

опция “-static” указывает на необходимость подключения статической библиотеки;

опция “-L” указывает на включение библиотек из каталога, который указан после опции, указан текущий каталог “.”;

опция “-l” указывает на включение библиотеки “libkia.a”.

После сборки получаем исполняемый код –“prog”.

затем вызвать функцию dlsym(), чтобы получить адрес функции kiaInit() в загруженной библиотеке:

func = (void(*)(void))dlsym(handle,”kiaInit”);

а затем вызвать саму функцию kiaInit() следующим образом:

func();

Если функции dlopen() и dlsym() возвращают NULL, то это свидетельствует об ошибке. Описание ошибки можно получить, вызвав функцию:

const char *dlerror(void);

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

int dlclose(void *handle);

Чтобы функция dlsym() получила доступ к функциям динамической библиотеки, в объявления этих функций необходимо добавить выражение extern “C”. Например, ранее представленный заголовочный файл kia.h должен выглядеть следующим образом:

extern “C” void kiaInit();

extern “C” void kiaClose();

extern “C” void kiaSend(char*, int);

extern “C” void kiaReceive(char*, int&);

Источник: https://studfile.net/preview/16676187/