ЖУРНАЛ «СТА» №4/2006

Device_ErrorCode error; //Уникальный идентификатор соединения Device_Link lid; //Номер порта канала Abort u_short abortPort; //Максимальный размер ожидаемого //устройством сообщения u_long maxRecvSize; }; Значение идентификатора клиента никак не влияет на алгоритм установ- ления соединения. В спецификации [1] рекомендуется сохранять данное зна- чение в протоколе работы сервера, что может быть полезным при анализе сбо- ев в его работе. При первом вызове процедуры create_link() сервер должен сгенериро- вать уникальный идентификатор соеди- нения lid и вернуть его. При последую- щих вызовах всегда возвращается lid , сгенерированный при первом обраще- нии, и изменяется значение счётчика вызовов create_link() (счётчика соеди- нений). Следует отметить, что соедине- ние может быть аннулировано с помо- щью функции destroy_link() , при вы- зове которой счётчик соединений уменьшается на единицу, а при дости- жении значения 0 соединение с данным lid прекращает своё существование, и при последующем вызове create_link() должен быть сгенерирован новый иден- тификатор соединения. Признак блокировки устройства lockDevice позволяет одному соедине- нию заблокировать другие соединения, то есть пока для конкретного lid не бу- дет вызвана процедура device_unlock() , запросы на вызов большинства проце- дур будут возвращать код ошибки 11 (устройство заблокировано другим со- единением). Такое поведение имеет смысл, если через текущий сервер доступно не одно, а несколько различ- ных устройств. Например, в приборе имеются независимые блоки А и Б. Со- единения устанавливаются независимо для каждого из блоков. Тип блока, для которого устанавливается соединение в данном вызове create_link() , опреде- ляется через входной строковый пара- метр device . В одном случае этот пара- метр будет иметь значение “Block A\n” и lid, равный 3742, а в другом – “Block B\n” и lid, равный 8452. При блокиров- ке сервера соединением 3742 (блок А) взаимодействия клиентов с соединени- ем 8452 (блок Б) будут запрещены (про- цедуры будут возвращать код ошибки). Попытка установить соединение с заблокированным сервером будет за- 62 СТА 4/2006 П Р О Г РАММНО Е ОБ Е С П Е Ч Е НИ Е / ИН С Т Р УМЕ Н ТАЛ Ь НЫ Е СИС Т ЕМЫ www.cta.ru // Указатель на функцию, которая ожидает от клиента // подтверждения об использовании открытого порта для // экстренного завершения программы pthread_t pThreadAbort = NULL ; // Дескриптор клиента со стороны сервера (используется для службы прерываний) CLIENT *clntIntr = NULL ; // Уникальный идентификатор, // передаваемый клиенту при возникновении прерывания char *handleIntr = NULL ; // Сокет, открываемый на прослушивание, // ассоциированный с каналом Abort struct sockaddr_in addr; Device_Link current_lid=0;//Идентификатор текущего соединения long int connect_counter=0;//Счетчик сеансов с текущим соединением /**Создание сокета. *@parameter port  [in] Номер открываемого порта. *@parameter sock  [out] Указатель на сокет. *@return  0  если успешно.*/ int getsocket( in_port_t port, int * sock ) { int rc = 1; if ( ( (*sock) = socket( AF_INET, SOCK_STREAM, 0 ) ) == 1 ){ printf(“Create stream socket failed!\n”); exit( EXIT_FAILURE ); } if ( setsockopt((*sock), SOL_SOCKET, SO_REUSEADDR, &rc, sizeof (rc)) != 0){ printf(“Set socket option failed!\n”); exit( EXIT_FAILURE ); } memset( &addr, 0, sizeof ( addr ) ); addr.sin_len = sizeof ( addr ); addr.sin_family = AF_INET; addr.sin_port = htons( port ); addr.sin_addr.s_addr = htonl( INADDR_ANY ); if (bind((*sock), ( struct sockaddr*)&addr, sizeof ( struct sockaddr)) != 0){ (*sock) = 0; return 1; } if ( listen( (*sock), 25 ) != 0 ) { printf(“Put socket in listen state failed!\n”); exit( EXIT_FAILURE ); } return 0; } /**Потоковая функция, которая ожидает от клиента команду device_abort() . *@parameter port указатель на сокет, выделяемый под канал Abort.*/ void * threadAbort( void * port){ int i=0, sock=0; int * _port=( int *)port; *_port=BASE_PORT; do {// Открываем первый свободный порт, начиная с BASE_PORT if ( ( getsocket(*_port+i, &sock ) ) == 0 ) { *_port+=i; break ; } } while ( ++i < (65536BASE_PORT) ); int readSock; sched_yield();//Для гарантии копирования параметра, переданного потоку while (1){ if ( ( readSock = accept( sock, NULL , NULL ) ) < 0 ){ printf(“device_abort!\n”); //... Здесь вызываем процедуры, прерывающие текущую задачу exit( EXIT_FAILURE ); } close( readSock ); } return NULL ; } Create_LinkResp * create_link_1_svc(Create_LinkParms *argp, struct svc_req *rqstp){ static Create_LinkResp result;//результат работы функции int port;//Порт канала Abort //Запускаем поток, создающий и прослушивающий порт канала Abort if ( pthread_create(&pThreadAbort, NULL , &threadAbort, &port) != EOK) errx(1, “ThreadAbort create error\n”); sched_yield(); // Для гарантии копирования переданного потоку параметра //Если это первое соединение, то генерируем уникальный идентификатор соединения if (current_lid==0)current_lid=clock(); connect_counter++;//увеличиваем количество соединений на 1 // Заполняем возвращаемую структуру параметров result.error = 0; result.lid = current_lid; result.abortPort = port; result.maxRecvSize = MAX_RECV_SIZE; return &result; } Листинг 2

RkJQdWJsaXNoZXIy MTQ4NjUy