Перенаправить текущее устройство ввода-вывода для стороннего стандартного взаимодействия

У меня есть множество подпрограмм M-Code, поставляемых поставщиками как часть гораздо более крупного продукта, который использует READ и WRITE напрямую для взаимодействия с текущим устройством. Я не могу изменить этот код. Я хочу обернуть некоторые из этих подпрограмм в систему, в которой я могу вводить ввод и получать вывод в интерактивном режиме.

В настоящее время это реализуется путем открытия TCP-соединения с удаленным хостом и создания его текущим устройством. READ и WRITE действительно подключены к сокету. Это довольно неудобно, так как требует настройки отдельной службы, которая прослушивает TCP-сокет, и координации с локальным заданием, чтобы весь процесс работал. Я также должен отключить nagle и пропустить буферизацию, иначе соединение станет управляемым с задержкой или зависнет. (например, параметр TCP OPEN /SEN=1, также известный как +Q). К сожалению, это приводит к большому количеству 1-байтовых TCP-сегментов, а также очень неэффективно.

Я бы предпочел управлять всем взаимодействием через один процесс. В идеале я мог бы сделать так, чтобы вызовы READ, WRITE и других функций, работающих на текущем устройстве, запускали некоторый М-код или обратные вызовы в интерфейс Caché Callin C или пользовательский модуль расширения для обеспечения необходимых функций на серверной части. Таким образом, я могу управлять вводом-выводом на своих условиях, не нуждаясь в координации между процессами. Однако я не смог найти точку входа, чтобы настроить это.

Есть ли в Caché такая вещь, как определяемое пользователем устройство?

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

Я подумал о том, чтобы создать новый процесс, чтобы Windows перенаправляла STDIN и STDOUT с помощью SetStdHandle для каналов, которыми я управляю из того же процесса, используйте Callin для подключения к Caché и разрешите ему использовать устройство по умолчанию, которое должно быть STDIN и STDOUT. Кто-нибудь знает, действительно ли это сработает?


person Chris Smith    schedule 25.09.2013    source источник


Ответы (1)


Caché на самом деле поддерживает произвольное перенаправление ввода-вывода. Это возможно с недокументированной функцией. Не рекомендуется, но вряд ли изменится.

Аннотированный код ниже. В этом примере я решил перенаправить ввод-вывод на %Stream.GlobalBinary — вы можете делать с ним все, что захотите. Ключом являются конкретные имена меток — вы можете указать другую процедуру с помощью вызова use $io:: и указать эти метки в другом месте.

//The ProcedureBlock = 0 is important
//  it allows for calling of labels within the ClassMethod
ClassMethod testIORedirection() [ ProcedureBlock = 0 ]
{
    //Create a stream that we will redirect to
    set myStream = ##class(%Stream.GlobalBinary).%New()

    //Redirect IO to the current routine - makes use of the labels defined below
    use $io::("^"_$ZNAME)

    //Enable redirection
    do ##class(%Device).ReDirectIO(1)

    //Any write statements here will be redirected to the labels defined below
    write "Here is a string", !, !
    write "Here is something else", !

    //Disable redirection
    do ##class(%Device).ReDirectIO(0)

    //Print out the stream, to prove that it worked
    write "Now printing the string:", !
    write myStream.Read()


    //Labels that allow for IO redirection
    //Read Character - we don't care about reading
rchr(c)      quit
    //Read a string - we don't care about reading
rstr(sz,to)  quit
    //Write a character - call the output label
wchr(s)      do output($char(s))  quit
    //Write a form feed - call the output label
wff()        do output($char(12))  quit
    //Write a newline - call the output label
wnl()        do output($char(13,10))  quit
    //Write a string - call the output label
wstr(s)      do output(s)  quit
    //Write a tab - call the output label
wtab(s)      do output($char(9))  quit
    //Output label - this is where you would handle what you actually want to do.
    //  in our case, we want to write to myStream
output(s)    do myStream.Write(s)  quit
}
person Brandon Horst    schedule 25.09.2013
comment
Потрясающе, это именно то, что я искал. Благодарю вас! - person Chris Smith; 26.09.2013