:: Главная :: Решения :: Статьи :: Проект "Русский help" :: Файловый архив :: Фотоальбом :: Ссылки ::
   Л и с о в о д ы   в с е х   с т р а н,  о б ъ е д и н я й т е с ь !!!  


Форумы  :: FAQ FoxPro

Кто в данный момент работает с приложением
Дата: 30.10.05 14:08:09 ОтветитьЦитировать

Вопрос:

Кто в данный момент работает с приложением

Ответ:

Чтобы ответить на этот вопрос необходимо вести учет всем "подключениям" к Вашему приложению. Т.е. некий лог всех подключений.

С точки зрения FoxPro наиболее естественно хранить все данные о подключениях в таблице DBF. Однако просто делать запись в этой таблице в момент входа в приложение и удалять или очищать запись при выходе из приложения недостаточно. Дело в том, что выход из приложения может быть и аварийным. Т.е. результатом, например, сбоя питания или некорректных действий пользователя. Как следствие, запись в таблице есть, но реально пользователь с приложением не работает.

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

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

Чтобы операции с этой служебной таблицей не мешали основной работе приложения, лучше открывать ее в отдельной сессии данных. Это можно сделать, например, используя объект Session, введенный в Visual FoxPro 6.0 Service Pack 3. Для младших версий FoxPro придется очень аккуратно следить за установкой и снятием блокировок с таблиц. Т.е. за командами UNLOCK, RLOCK(), LOCK(), SET MULTILOCK. Хотя, можно использовать невидимую форму.

Итак, в базе данных создается еще одна таблица. Это обычная таблица, принадлежащая базе данных. Т.е. таблица, лежащая на сервере, а не на локальном компьютере пользователя.

Список полей этой таблицы является набором идентификаторов, по которым в Вашей задаче надо отделять процессы друг от друга. Это может быть, например:

  • SYS(0) – Идентификатор компьютера и логин пользователя при входе в Windows
  • Логин пользователя при входе в Ваше приложение
  • Дата и время последнего входа в Ваше приложение
  • GetEnv("SessionName") – имя сессии, в которой запущено приложение.

    Замечание:
    Функция GetEnv() возвращает значение переменной созданной операционной системой. Полный список таких переменных и их значение можно посмотреть из режима командной строки Windows. Нажмите кнопку "Пуск" и выберите пункт меню "Выполнить". В появившемся окне введите в командной строке команду "cmd.exe" (разумеется, без кавычек) и нажмите кнопку "Ok" или "Enter". В открывшемся черном окне введите команду "set" и нажмите "Enter".

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

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

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

    В коде это будет выглядеть примерно так.

    Служебная таблица имеет примерно такую структуру

    CREATE TABLE curProc (CurProcID I AutoInc, SYS0 C(128), LastTime T)

    Здесь CurProcID - это код записи. В данном случае использовано тип данных Integer-Autoincrement, который был введен только в версии Visual FoxPro 8.0. Для младших версий FoxPro можно формировать код записи при помощи специальной функции NewId() или любым удобным для Вас способом.

    Идентификатором процесса выступает сетевое имя компьютера SYS(0)

    Тогда собственно код функции при открытии приложения будет таким

      
     * Запоминаю текущую сессию данных  
      LOCAL lnSessionCurrent  
      lnSessionCurrent = SET("DataSession")  
        
     * Проверяю факт создания частной сессии данных  
      IF Type("m.goSessionUsers") = "U"  
      	PUBLIC goSessionUsers  
      	goSessionUsers = CreateObject("Session")  
     	* Перехожу в созданную сессию данных  
      	Set DataSession To goSessionUsers.DataSessionId  
     	* Выполняю настройки в этой сессии  
      	SET REPROCESS TO 3      
      	SET TALK OFF  
      	SET MULTILOCK ON  
      Else  
     	* Перехожу в частную сессию данных  
      	Set DataSession To goSessionUsers.DataSessionId  
      EndIf  
        
     * Собственно поиск и блокировка записи  
      IF USED("curProc")=.F.  
      	USE curProc IN 0 SHARED    
      ENDIF  
      SELECT curProc    
      LOCATE FOR SYS0 = SYS(0)    
      IF FOUND()=.F.    
      	INSERT INTO curProc (SYS0) VALUES (SYS(0))    
      ENDIF    
        
      IF RLOCK()=.F.    
     	* Запись блокирована другим процессом    
     	* Т.е. предпринята попытка повторного запуска приложения    
      ELSE    
     	* Записываю время входа    
      	REPLACE LastTime WITH DateTime()    
      ENDIF    
        
     * Возвращаюсь в исходную сессию данных  
      Set DataSession To m. lnSessionCurrent

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

    Если при закрытии приложения удалять (или очищать) созданную запись, то по факту наличия не заблокированной записи можно сделать вывод о том, что приложение было закрыто аварийно. И определить кем именно.

    Запись времени нужна для того, чтобы не накапливался мусор. Например, уже нет компьютера со значением SYS(0), но запись с таким значением все еще существует. Вот по времени последнего обращения можно оценить: оставлять такую запись или уже пора удалять.

    Теперь, собственно код, определяющий, кто же в данный момент работает с Вашим приложением.

      
     * Запоминаю текущую сессию данных  
      LOCAL lnSessionCurrent  
      lnSessionCurrent = SET("DataSession")  
        
     * Проверяю факт создания частной сессии данных  
      IF Type("m.goSessionUsers") = "U"  
     	* Это ошибка.   
     	* К моменту вызова данной функции частная сессия должна быть уже создана  
     	* Поэтому прерываю процесс с сообщением об ошибке  
      	MessageBox("Нет сессии данных служебной таблицы")  
      	Return  
      Else  
     	* Перехожу в частную сессию данных  
      	Set DataSession To goSessionUsers.DataSessionId  
      EndIf  
        
     * Большинство настроек уже все выполнены при создании частной сессии данных   
     * в момент запуска приложения. Однако одну настройку следует установить  
     * не забыв сохранить исходное значение  
      LOCAL lnReporcess  
      lnReporcess = SET("REPROCESS")  
      SET REPROCESS TO 0 SECONDS	&& Спасибо Вадиму (piva) за подсказку ключевого слова SECONDS      
        
     * Создаю временную таблицу со структурой, дублирующей структуру служебной таблицы    
     * В эту временную таблицу будет записан результат поиска   
     * Опция READWRITE была введена только в версии Visual FoxPro 7  
     * Чтобы сделать курсор редактируемым в младших версиях FoxPro  
     * его придется переоткрыть повторно в другой рабочей области.  
     * Замечу также, что при таком запросе поле типа Integer-Autoincrement исходной таблицы  
     * конвертируется в поле с обычным типом Integer, что, в данном случае, как раз и требуется   
      USE IN SELECT('curCon')    
      SELECT * FROM curProc INTO CURSOR curCon NOFILTER READWRITE WHERE .F.    
            
     * Собственно поиск записей, заблокированных другими процессами    
      LOCAL laFields(1)    
      select curProc     
      SET ORDER TO 0    
      SCAN    
      	IF IsRLocked() = .T. OR RLOCK() = .F.    
     		* Эта запись содержит информацию о пользователе,     
     		* использующем данное приложение в настоящий момент    
     		* Копирую ее в итоговый курсор  
      		SCATTER TO laFields    
      		INSERT INTO curCon FROM ARRAY laFields    
      	ELSE    
     		* Поскольку удалось установить блокировку, то данная запись никем не используется  
     		* Снимаю с нее блокировку и перехожу к следующей записи  
      		UNLOCK RECORD Recno()    
      	ENDIF    
      ENDSCAN    
        
     * Возвращаюсь к записи заблокированной при входе в текущую копию приложения  
      LOCATE FOR IsRLocked() = .T.    
        
     * Восстанавливаю исходную настройку текущей сессии  
      SET REPROCESS TO m.lnReporcess     
        
     * Отображение результата поиска    
      select curCon    
      GO TOP    
      BROWSE NOWAIT  
        
     * Возвращаюсь в исходную сессию данных  
      Set DataSession To m.lnSessionCurrent

    Следует заметить, что курсор curCon существует только в той сессии данных, где он и был создан. Поэтому, вернувшись в исходную сессию данных, Вы уже не увидите результат поиска. Если Вы хотите отображать результат поиска в другой сессии данных, то либо следует использовать постоянную таблицу (это не очень хорошее решение), либо озаботится копированием информации из курсора в другую сессию данных. Это можно сделать, например, через массив.

      
      LOCAL laStructure(1), laContent(1)  
        
      Select curCon    
     * Копирую структуру курсора в массив  
      =AFields(laStructure)  
     * Копирую содержимое курсора в массив  
      COPY TO ARRAY laContent  
     * Возвращаюсь в исходную сессию данных  
      Set DataSession To m.lnSessionCurrent  
     * Создаю новый курсор  
      CREATE CURSOR curCon FROM ARRAY laStructure  
     * Наполняю его данными из массива  
      APPEND FROM ARRAY laContent

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

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

    Смотрите также

    Как предотвратить повторный запуск приложения



    Исправлено: Владимир Максимов, 10.06.10 10:31
    Ratings: 0 negative/0 positive


  • Тема Просмотров Написано Написано
      Администрирование приложения 4217 Владимир Максимов 29.10.05 21:56
      Как предотвратить повторный запуск приложения 12652 Владимир Максимов 30.10.05 02:30
      Кто в данный момент работает с приложением 8957 Владимир Максимов 30.10.05 14:08


    Извините, но у вас нет прав для того, чтобы писать в этом форуме.

    On-line: 35 and Guests: 35


    © 2006 Fox Club 
    Яндекс.Метрика