|
Программирование >> Структура ядра и системные вызовы
10.8.5. Программа типа клиент/сервер, использующая функцию mmap Описанное в разделе 10.7,7 приложение клиент/сервер можно легко перестроить на использование функции ттар. Изменения необходимо внести только в заголовок message.h. Модули client.C и server. С не изменяются. Новый заголовок message4.h, в котором используются семафоры и API ттар, выглядит так: fifndef MESSAGE4 H fdefine MESSAGE4 H finclude <strstream.h> finclude <stdio.h> finclude <stdlib.h> finclude <string.h> finclude <fcntl.h> finclude <memory.h> finclude <unistd.h> finclude <sys/types.h> finclude <sys/ipc.h> finclude <sys/mman.h> finclude <sys/sem.h> finclude <sys/wait.h> finclude <sys/errno.h> /* общие объявления для серверного процесса */ SHMSIZE=1024, SEMSIZE=2 }; 3, ILLEGAL CMD = 4, enum ( MSGKEY=186, MAX LEN=256, enum ( LOCAL TIME = 1, UTC TIME = 2, QUIT CMD SEM RD = 0, SEM WR=1 } ; struct mgbuf long mtypejiifoimt char mtext tMAX LEN]; class message private: int semId; struct mgbuf *msgPtr; enum ipc op ( RESET SEM, CLIENT GET MEM, CLIENT SND REQ, SERVER RCV REQ, SERVER GET MEM, SERVER SND RPY, CLIENT RCV RPY ] ; public: /* попробуем изменить значения семафоров */ void getsem( enum ipc op opType ) static struct sembuf args[2] = { (SEM RD}, (SEM WR} ); switch (opType) { case SERVER GET MEM; return; case CLIENT GET MEM: args[SEM RD].sem op = args[SEM WR].sem op = break; case CLIENT SND REQ: args[SEM RD].sem op = args[SEM WR].sem op = break; case SERVER RCV REQ: args[SEM RD].sem op = args[SEM WR].sem op = break; case SERVER SND RPY: args[SEM RD].sem op = args [SEM WR] .sem op = break; case CLIENT RCV RPY: args[SEM RD].sem op = args[SEM WR].sem op = break; case RESET SEM: args[SEM RD].sem op args[SEM WR].sem op = 0, -1; 1, 0; -1, 0; 1, 1; -1, -1; 0, 1; if (semop(semId,args,SEMSIZE)= -l) perror( semop ) FOO key XO /* функция-конструктор */ message( int key ) ( char mfile[256], fillchr=\0; ostrstream(mfile,sizeof mfile) int fd =open(mfile,0 RDWR,0); if (fd==-l) ( /* новый файл */ if ((fd=open(mfile,0 RDWRlO CREATO TRUNC,0777})==1) perror( open ); else { /* заполнить файл нулями; без этого в некоторых системах функция mmap не работает*/ for (int i=0; i < SHMSIZE; 1++} write(fd, Sfillchr, 1}; if ((semld=semget(key, SEMSIZE, IPC CREAT0666))==-1} perror( semget ); else getsem(RESET SEM); / инициализировать новый набор семафоров */ } else- ( /* присоединить к существующему набору */ if ({semld=semget(key. О, 0))==-!) perror( semget ); if ((msgPtr=(struct mgbuf*)mmap(О, SHMSIZE, PROT READ I PROT WRITE, MAP SHARED, fd,0))== MAP FAILED) perror( mmap ); else close(fd); /* функция-деструктор */ -message О (l; /* проверить статус создания очереди сообщений */ int goodO ( return (semld>=0) ? 1 : 0; } ; /* удалить очередь сообщений */ int rmQ{) if (!semctl(semid,О,IPC RMXD,0) && Imunmap((caddr t)msgPtr, SHMSIZE)) return 0; perror( shmctl or semctl ); return -1; /* передать сообщение */ int send( const void* buf, int size, int type) { int server = (type 99); getsem(server ? SERVER GET MEM : CLIENT GET MEM); memcpy (msgPtr->mtext buf, size); msgPtr->ratext[size] = \0; msgPtr->mtype = type; getsem(server ? SERVER SND RPY : CLIENT SND REQ); return 0; /* принять сообщение */ int rcv( void* buf, int size, int type, int* rtype) int- server = (type < 0) ; ftsIerver /sERVER RCV REQ : CLIENT RCV RPY ; memcpy(buf,msgPtr->mtext,strlen(msgPtr->mtext)+l), if (rtype) *rtype = msgPtr->mtype; if (!server) getsem(RESET SEM); return strlen(msgPtr->mtext); ); /* message */ #endif Изменения касаются функции-конструктора message, для которой вызов shmget гшешп вызовом ттар. Имя отображаемого файла включает префикс имени F00 (он выбран произвольно) и заданный ключевой идентификатор. Вновь создаваемый файл инициализируется NULL-символами, количество которых определяется переменной SHMSIZE. Это необходимо для того. чтобы убедиться: вся отображенная область памяти была выделена ядром под хранение данных. Еще одно изменение в заголовке message.h коснулось функции rmQ. Она вызывается, когда серверный процесс завершается и ему нужно удалить свой набор семафоров и отсоединиться от отображенной области памяти. Остальной код заголовка message.h - такой же, как представленный в разделе 10.7.7. Результаты выполнения этой программы также аналогичны приведенным в разделе 10.7.7. 10.9. Организация разделяемой памяти в соответствии со стандартом POSIX.lb В POSIX.lb определены следующие API разделяемой памяти: #include <sys/mman.h> int shm open ( char* name, int flags, mode t mode ); int shm unlink ( char* name ); Функция shmjopen создает разделяемую область памяти, имя которой задано аргументом пате. Значения этого аргумента такие же, как используемые для организации взаимодействия с помощью сообщений в стандарте POSIX.lb. Аргумент flags содержит флаги доступа к памяти (0 RDWR, 0 RDONLY или 0 WR0NLY), а также флаги 0 CREAT и 0 EXCL. Аргумент mode используется в том случае, если данный вызов создает новую разделяемую область памяти. Его значение указывает права доступа на чтение и запись для владельца, группы и прочих пользователей, устанавливаемые для новой области. В случае успешного выполнения эта функция возвращает неотрицательный дескриптор, а в случае неудачи--1. В отличие от API shmget ОС UNIX System V, API shm open не задает размер разделяемой области памяти, который определяется в последующем вызове ftruncate. Прототип функции ftruncate выглядит так: int ftruncote ( int fd, off t shared memory size j; Здесь аргумент fd содержит дескриптор разделяемой памяти, возвращенный вызовом shmjopen. Аргумент sharedjmemory size содержит размер разделяемой области памяти, которая будет вьщелена. После выделения разделяемой области памяти и определения ее размера необходимо вызвать функцию ттар, которая отх)бразит разделяемую область памяти в виртуальное адресное пространство вызывающего процесса. После завершения работы с разделяемой областью памяти процесс вызывает функцию типтар, которая отсоединяет разделяемую область памяти от его виртуального адресного пространства. Затем можно вызвать функцию shm nlink, которая удалит разделяемую область памяти из системы. Аргументом этой функции является путевое UNIX-имя разделяемой области памяти. Приведенная ниже программа testjshmp. С открывает для чтения и записи разделяемую область памяти с именемО (посредством вызова shmjopen) и устанавливает ее размер, вызывая для этого функцию /truncate. Данная разделяемая память отображается в виртуальное адресное пространство процесса с помощью вызова ттар. В переменной тетр хранится начальный адрес разделяемой области памяти. После организации в процессе разделяемой области памяти вызывается функция semjnit, которая создает семафор по начальному адресу разделяемой памяти. Затем процесс работает с семафором и разделяемой областью памяти. По завершении работы процесс вызывает функцию sem destroy, которая удаляет семафор из системы. После этого вызываются функции shmjinlink и shmjinmap, которые удаляют из системы разделяемую область памяти и отсоединяют ее от виртуального адресного пространства. tinclude tinclude tinclude tinclude tinclude tinclude <stdio.h> <unistd.h> <errno.h> <fcntl.h> <sys/stat.h> <semaphore.h> tinclude <sys/mman.h> int main(} long siz = sizeof(sem t) + 1024; int shmfd = shm open ( /shm.O , 0 CREAT0 RDWR, S IRWXU}; if (shmfd==-l) { perror( shm open }; return 1; ) if (ftruncate(shmfd, siz)==-l) { perror( ftruncate ); return 2; ) char* memp = (char*) mmap (0, siz, PROT READ I PROT WRITE MAP SHARED, shmfd, OL); , if (Imerop) { perror( mmap ); return 3} j (void)close(shmfd); if (sem init((sem t*}memp,1,1} < 0} { perror( sem init }; return 4; /* do work with the shared memory and semaphore */ if (sem destroy((sem t*)menp) < 0) { perror( sem destroy }; return 5; } if (shm unlink( /shm.O ) < 0) { perror( shm unlink }; return 6; } return munmap( memp, sizeof(sem t) + 1024); 10.9.1. Программа типа клиент/сервер, соответствующая стандарту POSIX.Ib Описанное в разделе 10.7.7 приложение клиент/сервер можно переписать, используя разделяемую память и семафоры стандарта POSIX.Ib. Изменения опять-таки необходимо внести только в заголовок message.h. Модули client.C и server.C не изменяются. Новый заголовок messageS.h, который содержит класс message, использующий разделяемую память и семафоры стандарта POSIX.Ib, выглядит так: tifndef MESSAGE5 H tdefine MESSAGES Н /* указать, что следующий исходный текст соответствует стандарту POSIX.Ib */ Idefine P0SIX C SOURCE 199309L tinclude <strstream.h> tinclude <stdio.h> tinclude <memory.h> tinclude <unistd.h> tinclude <string.h> tinclude <limits.h> tinclude <sys/stat.h> tinclude <semaphore.h> tinclude <sys/mman.h> /* общие объявления для серверного процесса */ enum { MSGKEY=186, MAX LEN=256, MAX MSG=20 }; enum { L0CAL TIME=1, UTC TIME=2, QUIT CMD=3, ILLEGAL CMD=4 }; /* запись данных для одного сообщения */ struct mgbuf long char mtype; mtext{MAX LEN] ; тип сообщения текст сообщения strucrshmheader разделяемой области памяти сообщения */ еа ег sem t semaphore; struct mgbuf rosgList[MAX MSG}; семафор список сообщений /* класс message */ class message private: struct shm header *memptr; sem t *sem id; char mfile(256];
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |