Рекомендую ознакомиться со статьей на ресурсе infostart.ru - Как решать повседневные задачи с помощью OneScript здесь

Скачайте и установите 1Script - язык сценариев для специалистов по 1С (сайт) здесь

Кроме TCP сервера в библиотеке есть TCP клиент. Он тоже спроектирован под особенности кода односкрипта. Оба могут быть запущены различными способами, описанными в параграфах Варианты запуска сервера. и Варианты запуска клиента. Это дает гибкость при построении клиент-серверного приложения.

В этом примере создается эхо-сервер:


// Этот сервер можно запускать для тестирования клиентов. // В ответ на сообщения клиентов сервер будет пересылать сообщение // как самому клиенту, так и всем подключенным клиентам. Перем МС, Сервер; Процедура ПриПодключенииКлиента() Экспорт АргументыСобытия = МС.АргументыСобытия; Сообщить("Клиент подключился: " + АргументыСобытия.ИдентификаторКлиента); Сообщить("Активных клиентов: " + Сервер.КоличествоАктивныхКлиентов); Сообщить("========================"); КонецПроцедуры Процедура ВывестиСообщение(Данные, ИдентификаторКлиента) Попытка РазмерДанных = Данные.ПрочитатьЦелое32(0); ДанныеСообщения = Данные.Прочитать(4, РазмерДанных); ДД = ПолучитьДвоичныеДанныеИзБуфераДвоичныхДанных(ДанныеСообщения); ОтдельноеСообщение = ПолучитьСтрокуИзДвоичныхДанных(ДД, КодировкаТекста.UTF8); Сообщить("Сообщение от " + ИдентификаторКлиента + " (" + РазмерДанных + " байт):" + Символы.ПС + ОтдельноеСообщение); Если (Данные.Размер - 4 - РазмерДанных) > 0 Тогда ОстатокДанных = Данные.Прочитать(4 + РазмерДанных, Данные.Размер - 4 - РазмерДанных); ВывестиСообщение(ОстатокДанных, ИдентификаторКлиента); КонецЕсли; Исключение ДанныеСообщения = Данные.Прочитать(0, Данные.Размер); ДД = ПолучитьДвоичныеДанныеИзБуфераДвоичныхДанных(ДанныеСообщения); ОтдельноеСообщение = ПолучитьСтрокуИзДвоичныхДанных(ДД, КодировкаТекста.UTF8); Сообщить("Сообщение от " + ИдентификаторКлиента + " (" + Данные.Размер + " байт):" + Символы.ПС + ОтдельноеСообщение); КонецПопытки; КонецПроцедуры Процедура СерверПолучилДанные() Экспорт АргументыСобытия = МС.АргументыСобытия; Данные = АргументыСобытия.Данные; // Данные, полученные сервером, доступны нам как тип БуферДвоичныхДанных (BinaryDataBuffer). // Если с сервером будет взаимодействовать клиент, который формирует сообщения по оговоренным заранее правилам, // появляется возможность делить данные на отдельные сообщения и кроме того знать тип данных отдельного сообщения. // Как частный случай можно на стороне клиента отправлять в сетевой поток сначала размер сообщения (четыре байта) // а затем само сообщение. В этом примере так и сделано. // Разобъем полученные сервером данные на отдельные сообщения. ВывестиСообщение(Данные, АргументыСобытия.ИдентификаторКлиента); // Отправим всем строку. Сервер.ОтправитьВсем("От сервера всем: " + Символы.ПС + ПолучитьСтрокуИзБуфераДвоичныхДанных(Данные)); // Отправим клиенту. Сервер.ОтправитьКлиенту(АргументыСобытия.ИдентификаторКлиента, "От сервера клиенту " + АргументыСобытия.ИдентификаторКлиента + ": " + Символы.ПС + ПолучитьСтрокуИзБуфераДвоичныхДанных(Данные)); Сообщить("========================"); КонецПроцедуры Процедура ПриОтключенииКлиента() Экспорт АргументыСобытия = МС.АргументыСобытия; Сообщить("Клиент отключился: " + АргументыСобытия.ИдентификаторКлиента); Сообщить("Активных клиентов: " + Сервер.КоличествоАктивныхКлиентов); Сообщить("========================"); КонецПроцедуры Процедура ПриОшибкеСервера() Экспорт АргументыСобытия = МС.АргументыСобытия; Сообщить("ОшибкаСервера: " + АргументыСобытия.ОшибкаСервера); Сообщить("========================"); КонецПроцедуры ПодключитьВнешнююКомпоненту("C:\444\111\MultithreadedTCPServer\MultithreadedTCPServer\bin\Debug\MultithreadedTCPServer.dll"); МС = Новый МногопоточныйTCPСерверДляОдноСкрипта(); Сервер = МС.МногопоточныйСервер(8080); Сервер.ПриОшибкеСервера = МС.Действие(ЭтотОбъект, "ПриОшибкеСервера"); Сервер.ПриОтключенииКлиента = МС.Действие(ЭтотОбъект, "ПриОтключенииКлиента"); Сервер.СерверПолучилДанные = МС.Действие(ЭтотОбъект, "СерверПолучилДанные"); Сервер.ПриПодключенииКлиента = МС.Действие(ЭтотОбъект, "ПриПодключенииКлиента"); // // Для визуализации активности клиентов можно включить это свойство. // Сервер.ПроверятьАктивностьКлиента = Истина; Сервер.Начать(); Пока МС.Продолжать Цикл МС.ПолучитьСобытие().Выполнить(); КонецЦикла;
Сохраните этот код в файл с расширением ".os" и исполняйте в окне терминала.

Ограничений на способ реализации TCP клиента нет. Сервер можно настроить на протокол общения с любым клиентом. Проще всего использовать клиент из этой же библиотеки.

В этом примере создается клиент:


Перем МС; Процедура ВывестиСообщение(Данные) Попытка // В случае передачи в потоке перед самим сообщением размера сообщения используем этот вариант. РазмерДанных = Данные.ПрочитатьЦелое32(0); ДанныеСообщения = Данные.Прочитать(4, РазмерДанных); ДД = ПолучитьДвоичныеДанныеИзБуфераДвоичныхДанных(ДанныеСообщения); ОтдельноеСообщение = ПолучитьСтрокуИзДвоичныхДанных(ДД, КодировкаТекста.UTF8); Сообщить("Получено сообщение: " + " (" + РазмерДанных + " байт):" + Символы.ПС + ОтдельноеСообщение); Если (Данные.Размер - 4 - РазмерДанных) > 0 Тогда ОстатокДанных = Данные.Прочитать(4 + РазмерДанных, Данные.Размер - 4 - РазмерДанных); // Продолжаем делить данные на отдельные сообщения. ВывестиСообщение(ОстатокДанных); КонецЕсли; Исключение // В случае передачи в потоке никак не разделенных байтов используем этот вариант. ДанныеСообщения = Данные.Прочитать(0, Данные.Размер); ДД = ПолучитьДвоичныеДанныеИзБуфераДвоичныхДанных(ДанныеСообщения); ОтдельноеСообщение = ПолучитьСтрокуИзДвоичныхДанных(ДД, КодировкаТекста.UTF8); Сообщить("Получено сообщение: " + " (" + Данные.Размер + " байт):" + Символы.ПС + ОтдельноеСообщение); КонецПопытки; // Можно предусмотреть другие способы разделения потока байтов на отдельные сообщения, например посылка символа перевода строки. КонецПроцедуры Процедура КлиентПолучилДанные() Экспорт АргументыСобытия = МС.АргументыСобытия; Данные = АргументыСобытия.Данные; // Данные, полученные клиентом, доступны нам как тип БуферДвоичныхДанных (BinaryDataBuffer). // Если с клиентом будет взаимодействовать сервер, который формирует сообщения по оговоренным заранее правилам, // появляется возможность делить данные на отдельные сообщения и кроме того знать тип данных отдельного сообщения. // Как частный случай можно на стороне сервера отправлять в сетевой поток сначала размер сообщения (четыре байта) // а затем само сообщение. ВывестиСообщение(Данные); Сообщить("========================"); КонецПроцедуры ПодключитьВнешнююКомпоненту("C:\444\111\MultithreadedTCPServer\MultithreadedTCPServer\bin\Debug\MultithreadedTCPServer.dll"); МС = Новый МногопоточныйTCPСерверДляОдноСкрипта(); // Запустим клиента фоновым заданием. TCPПодключение1 = МС.ФоновыйTCPКлиент("127.0.0.1", 8080); // Назначим обработчик события. TCPПодключение1.КлиентПолучилДанные = МС.Действие(ЭтотОбъект, "КлиентПолучилДанные"); // Подождем пока клиент подключится. Пока Не TCPПодключение1.Подключен Цикл Приостановить(100); КонецЦикла; Сообщить("Подключен"); Сообщить("Печатайте и нажмите ENTER"); // // Можно отправлять данные. // БуферОтправки = ПолучитьБуферДвоичныхДанныхИзСтроки("Серверу от клиента ПРИВЕТ!"); // TCPПодключение1.Отправить(БуферОтправки); // Можно далее дополнять алгоритм сценария, фоновый TCP клиент не блокирует выполнение сценария. // Мы же не закроем подключение и остановимся в цикле ввода сообщений. Результат = Неопределено; Пока ВвестиСтроку(Результат, , , ) Цикл TCPПодключение1.Отправить(ПолучитьБуферДвоичныхДанныхИзСтроки(Результат)); КонецЦикла;
Сохраните этот код в файл с расширением ".os" и исполняйте в окне терминала.

Если потребуется организовать безопасный ввод пароля можно воспользоваться библиотекой Текстовый пользовательский интерфейс (TUI) для сценарного языка OneScript.

В этом примере показан безопасный ввод пароля:


Перем Стр; Процедура ЗапросПароля(параметр1) Экспорт Контекст = Новый Структура(); Контекст.Вставить("МояСтруктура", параметр1); ЗагрузитьСценарийИзСтроки(Стр, Контекст); КонецПроцедуры Стр = " |Перем ТФ, ПолеВвода1; | |Процедура ПолеВвода1_КлавишаНажата() Экспорт | Если ТФ.АргументыСобытия.Клавиша = ТФ.Клавиши.Enter Тогда | МояСтруктура.Пароль = ПолеВвода1.Текст; | ТФ.Завершить(); | КонецЕсли; |КонецПроцедуры | |ПодключитьВнешнююКомпоненту(""C:\444\111\OneScriptTerminalGui\OneScriptTerminalGui\bin\Debug\OneScriptTerminalGui.dll""); |ТФ = Новый ТерминалФормыДляОдноСкрипта(); | |ПолеВвода1 = ТФ.Верхний.Добавить(ТФ.ПолеВвода("""", , , 30)); |ПолеВвода1.Центр(); |ПолеВвода1.Секрет = Истина; |ПолеВвода1.КлавишаНажата = ТФ.Действие(ЭтотОбъект, ""ПолеВвода1_КлавишаНажата"", ПолеВвода1); | |ТФ.Запуск(); |"; МояСтруктура = Новый Структура("Пароль", ""); МассивПараметров = Новый Массив(1); МассивПараметров[0] = МояСтруктура; Задание = ФоновыеЗадания.Выполнить(ЭтотОбъект, "ЗапросПароля", МассивПараметров); Задание.ОжидатьЗавершения(); Сообщить("Пароль = " + МояСтруктура.Пароль); // Ожидаем пароль. Пока МояСтруктура.Пароль = "" Цикл Приостановить(1000); КонецЦикла; // // Если нужно не завершаем сценарий. // Пока Истина Цикл // Приостановить(1000); // КонецЦикла;

В библиотеке есть методы создания самоподписанного сертификата сроком на один год. Для защищенного соединения на стороне сервера нужен будет файл сертификата .pfx. На стороне клиента нужен будет файл сертификата .crt.

Файл сертификата .pfx генерируется методом МногопоточныйTCPСерверДляОдноСкрипта.СоздатьСамоподписанныйСертификат (OneScriptMultithreadedTCPServer.CreateSelfSignedCertificate).

Файл сертификата .crt извлекается их файла .pfx методом МногопоточныйTCPСерверДляОдноСкрипта.ИзвлечьCrtИзPfx (OneScriptMultithreadedTCPServer.ExtractCrtFromPfx).

Пример работы с сертификатами:


ПодключитьВнешнююКомпоненту("C:\444\111\MultithreadedTCPServer\MultithreadedTCPServer\bin\Debug\MultithreadedTCPServer.dll"); МС = Новый МногопоточныйTCPСерверДляОдноСкрипта(); МС.СоздатьСамоподписанныйСертификат("C:\111\certik.pfx", "OneScript", "123456"); МС.ИзвлечьCrtИзPfx("C:\111\certik.pfx", "123456", "C:\111\certik.crt");