- •05.12.12 Лекция 12
- •Темпоральная логика
- •Определение Модальной логики
- •Динамически порождаемые процессы
- •Радиус-сервер интернет-телефонии
- •Спецификация скелета радиус-сервера.
- •Главный процесс радиусСервер
- •Сеанс входящего звонка
- •Авторизация внешнего абонента, номера и пути
- •Сеанс звонка
- •Сеанс исходящего звонка
- •Авторизация внутреннего абонента
- •Свойства спецификации сеанса
- •Реализация скелета радиус-сервера
- •Этап4. Замена receive на if
- •Этап6. Сборка обработчика из разных кусков сопрограммы
- •class SEANCE {
- •else if (AuthPathBillingReply(ID j, bool ответ))
- •Реализация для ненадежных каналов
- •Изменившаяся часть реализации радиус-сервера
- •Процессорная спецификация языка исчисления вычислимых предикатов
- •type ID;
- •Исполнение программы
- •runRight(SECT s, RIGHT right) {
- •Исполнение параллельной композиции
Сеанс звонка
process авторизацияПутиЗвонок( : #nextcall | #stop) {
$sAuthNum: receive |
{ |
|
AuthPath(): авторизацияПути( : #yes2| #nextcall | #stop); |
||
yes2: |
сеансЗвонка( : #nextcall | #stop) |
|
case |
StartCall(): |
звонок( : #nextcall | #stop) |
case |
Stop(): |
#stop |
} |
|
|
}
process сеансЗвонка( : #nextcall | #stop) {
$sCall: receive |
{ |
StartCall(): |
звонок( : #nextcall | #stop) |
||
} |
case |
|
Stop(): |
#stop |
|
|
|
|
|
|
|
} |
|
|
|
|
|
process звонок( : #nextcall | #stop) { |
|
||||
$sStartCall: |
receive { |
StartTalk(): |
|
||
$sTalk: |
|
|
|
|
receive StopTalk(); |
$sStopTalk: |
|
|
|
|
receive StopCall(); |
|
|
|
|
|
БС ! CallBilling() |
|
}; |
case |
StopCall(): |
БС ! CallBilling(); |
|
|
|
|
|
|
if (Stop()) #stop else #nextcall
Сеанс исходящего звонка
process сеансИсходящегоЗвонка(ID id: #end) { авторизацияВнутреннегоАбонента( : #key | #num | #stop);
key: авторизацияПоКоду( : #key | #num| #stop); num:авторизацияНомераПутиЗвонок( : #num| #stop); stop: БС ! StopBilling(); удалитьСеанс(id) #end
}
process авторизацияНомераПутиЗвонок( : #nextcall | #stop) { $sAuthNumPath:
receive {
AuthNum(): авторизацияНомера( : #yes1| #nextcall | #stop); yes1: авторизацияПутиЗвонок( : #nextcall | #stop)
case Stop(): #stop
}
}
Авторизация внутреннего абонента
process авторизацияВнутреннегоАбонента( : #key | #num | #stop) { БС ! AuthOutgoingBilling();
$sAuth: receive AuthOutgoingBillingReply(bool ответ); СИТ ! AuthOutgoingReply(ответ);
if (Stop()) #stop ;
if (ответ) #num else #key
}
process авторизацияПоКоду( : #key | #num | #stop) {
$sKey: |
receive { |
Key(): |
БС ! KeyBilling(); |
$sKeyBilling: |
|
|
receive KeyBillingReply(bool ответ); |
|
|
|
СИТ ! KeyReply(ответ); |
|
|
|
if (Stop()) #stop ; |
|
case |
Stop(): |
if ( ответ) #key |
|
#stop |
||
|
} |
|
|
|
#num |
|
|
} |
|
|
|
Свойства спецификации сеанса
•сообщение Stop() может придти в любой момент, но его обработка реализуется не всегда в порядке поступления
•остальные сообщения упорядочены
Цепочки следования сообщений:
AuthIncomingPath StartCal StartTalk StopTalk StopCall Stop AuthIncoming AuthPath StartCall …
AuthOutgoing Key AuthNum AuthPath StartCall …
Правило: пока не завершена авторизация (посылкой ответного сообщения на СИТ) другие сообщения этого сеанса, в том числе сообщение Stop(), не обрабатываются.
Вхождения сообщения Stop() в спецификации являются источником недетерминизма
дедлок ?
Реализация скелета радиус-сервера
Неэффективность:
•использование параллельных процессов
•блокировка исполнения на операторах receive
Этап1. Фиксация специальных внутренних состояний
$sAuth: |
|
$sAuth: state := sAuth; |
Этап2. Вынос обработки сообщений Stop()
type STATE = enum sAuthNum, sCall, sKey, sAuthNumPath, sAuthIncoming, sAuthNumBilling, sAuthPathBilling, sStartCall, sTalk, sStopTalk, sAuth, sKeyBilling;
class SEANCE { |
|
STATE state; |
// текущее специальное состояние данного сеанса |
bool stop = false; // = true поступило сообщение Stop() для данного сеанса
} to be continued
process обработкаОчередногоСообщения( : #loop) { receive { AuthIncoming(ID j):
……………………………………………
case Stop(ID j): |
// сеанс(j) ! Stop( ) |
se = сеанс(j);
if (se.state in {sAuthNum, sCall, sKey, sAuthNumPath}) { БС ! StopBiling(); удалитьСеанс(se.id) }
else se.stop = true
};
! После этапа 2 порядок поступления сообщений в процесс сеанса радиус-сервера совпадает с порядком их обработки.
Этап3. Замена процесса сеанса на сопрограмму
Специальное внутреннее состояние точка сопрограммного прерывания
! После этапа 3 всякий оператор receive выполняется без ожидания
Этап4. Замена receive на if
receive {<сообщение1>: <оператор1> case…case <сообщениеN>: <операторN>}
if (<сообщение1>) <оператор1> else if…else if (<сообщениеN>) <операторN>
Этап5. Замена создания параллельного процесса сеанса на непосредственный вызов процесса
receive AuthIncoming(ID j): |
se= new SEANSE(j); |
|
создатьСеанс(j, se); |
|
сеансВходящегоЗвонка1(j) |
! После этапа 5 нет параллельных процессов. Программа исполняется в сопрограммном режиме.
Обработчик сообщения фрагмент программы, соответствующий обработке одного сообщения
Этап6. Сборка обработчика из разных кусков сопрограммы
На примере AuthIncoming() и AuthPathBillingReply(). AuthIncoming() БС ! AuthIncomingBilling(); $sAuthIncoming: AuthPathBillingReply()
СИТ ! AuthPathReply(ответ);
if (Stop()) #stop else if (ответ) #yes else #no ; Необходимо продолжить для #yes и #no авторизацияПути авторизацияВнешнегоНомераПути
сеансВходящегоЗвонка2 сеансЗвонка (#yes #yes3 #call $sCall ) авторизацияПути авторизацияПутиЗвонок сеансЗвонка
(#yes #yes2l $sCall ) #yes $sCall
авторизацияПути авторизацияПутиЗвонок сеансВходящегоЗвонка1 (#no #nextcall #stop ) авторизацияПутиЗвонок авторизацияНомераПутиЗвонок сеансИсходящегоЗвонка авторизацияНомераПутиЗвонок (#no #nextcall #num $sAuthNumPath )
авторизацияПути авторизацияВнешнегоНомераПути (#no #stop )#no #stop, $sCall вводится новое поле outgoing
#no if (se.outgoing) $sAuthNumPath else #stop
class SEANCE {
bool outgoing = false; // = true для сеанса исходящего звонка
bool incomingPath = false; // = true если первым приходит сообщение // AuthIncomingPath()
SEANCE(ID j, bool outgoing, bool incomingPath);
//
bool completedlAll(); // = true в случае, когда все звонки в серии звонков // завершены либо серия пуста
}
SEANCE se; // текущий сеанс в радиус-сервере process собработкаОчередногоСообщения(: #loop) {
if (AuthIncoming(ID j))
{ se = new SEANCE(j, false, false); БС ! AuthIncomingBilling(); $sAuthIncoming } else if (AuthIncomingPath(ID j))
{ se = new SEANCE(j, false, true); БС ! AuthIncomingBilling(); $sAuthIncoming } else if (AuthOutgoing(ID j))
{se = new SEANCE(j, true, false); БС ! AuthOutgoingBilling(); $sAuth } else if (AuthIncomingBillingReply(ID j, bool ответ))
{СИТ ! AuthIncomingReply(ответ);
if (se.stop ответ) #stop
else { БС ! AuthNumBilling(); $sAuthNumBilling }
}
else if (AuthNumBillingReply(ID j, bool ответ)) { СИТ ! AuthNumReply(ответ);
if (se.stop) #stop
else if ( ответ) if (se.outgoing) $sAuthNumPath else #stop else if (se.outgoing se.incomingPath) $sAuthNum
else { БС ! AuthPathBilling(); $sAuthPathBilling }
}