Вопрос: Организация обмена данными между серверами Cache' через Socket коннект (PuTTY.exe)
Доброго времени суток.
Решил поделиться с сообществом альтернативной технологией обмена данными между серверами Cache’ и сторонними языками программирования, поддерживающие Socket коннекты.
Для начала, немного о причине появления этой технологи:
Появилась необходимость получать большие объемы данных между двумя серверами Cache’. Задача казалось бы простая, и решается стандартными методами, с применением вэб технологий, но при реализации, лично я столкнулся с подводными камнями. Главной проблемой стала ошибка “Таймаута”. Данные перед отправкой очень долго подготавливались. Можно включить мозг и начать оптимизировать предварительную подготовку данных, но было лень это делать, и я пошел другим путем.
Был разработан контроллер, позволяющий прямое Socket соединение между серверами, а за одно и между любыми средствами разработки поддерживающие сокеты.
Сервер поддерживает авторизацию и следующие команды:
"ip" - Получить IP адрес клиента со стороны сервера
"run: w $h" - Выполнить однострочную команду
"cls" - Очистить буфер команд на стороне сервера
"read" - Прочитать буфер команд записанные на стороне сервера
"run" - Выполнить команды записанные в буфере на стороне сервера
"runline" - Выполнить построчно команды записанные в буфере на стороне сервера
"key" - Получить ключ сесии
"exit" - Разорвать соединение
"ping" - тестовый запрос (после него произойдёт разрыв соединения)
"gl" - показать имя глобал в котором хранится буфер
"gl:^GBuff" - Установить имя глобала в котором хранится буфер
"setapp:AppName"- Указываем название приложение из которого подключились
Все остальные строки записываются в буфер на стороне сервера.
Проверить работу можно применив PuTTY.exe
Если кого заинтересует этот контроллер, и появятся идеи, как улучшить код, буду рад внести изменения.
Пример подключения между серверами, и выполнения MUMPS команды (взят из документации к классу)
s obj=##class(%ZMSrv.Controller).%New()
s obj.Host="127.0.0.1"
s obj.Port=6006
s obj.UserName="_SYSTEM"
s obj.UserPass="SYS"
s obj.NameSpace="USER"
if obj.Connect()=1 {
w !,obj.Send("ip")
w !,obj.Send("run: w $ZU(110)")
; Наполняем буфер командами Cache'
d obj.Send(" for a=1:1:100 d ")
d obj.Send(" . w $JOB_"":""_a ")
d obj.Send(" . w $c(13,10) ")
w !,obj.Send("run") ; запустить выполнение команд в буфере
d obj.Send("cls") ; Очистить буфер на стороне сервера
w !,"SessionKey: "_obj.SessionKey
}else{
w !,"Error: "_obj.Error,!
}
d obj.DisConnect()
q
Получить объект по ID
s obj=##class(%ZMSrv.Controller).%New()
s obj.Host="127.0.0.1"
s obj.Port=6006
s obj.UserName="_SYSTEM"
s obj.UserPass="SYS"
s obj.NameSpace="SAMPLES"
if obj.Connect()=1 {
s ExternalObject=obj.GetObject("Cinema.Film","1" )
zw ExternalObject
}else{
w !,"Error: "_obj.Error,!
}
d obj.DisConnect()
Получить объекты из Query запроса
s obj=##class(%ZMSrv.Controller).%New()
; s obj.Host="127.0.0.1"
; s obj.Port=6006
; s obj.UserName="_SYSTEM"
; s obj.UserPass="SYS"
s obj.NameSpace="SAMPLES"
if obj.Connect()=1 {
if obj.SqlQuery("","%Dictionary.ClassDefinition:Summary" )'=1 q
for {
s resNext=obj.SqlQueryNext("")
q:resNext=0
if resNext="" {
w "Error: "_obj.Error,!
q
}
s re=obj.SqlQueryGet("")
zw re
}
}else{
w !,"Error: "_obj.Error,!
}
d obj.DisConnect()
q