USR1 протокол

From SunFlurry wiki
Jump to: navigation, search

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

Для создания сервера, работающего по данному протоколу, можно добавить дополнительный раздел текста в ini-файл клиента (консольного или визуального), либо использовать функцию ListenUSR1.

//Раздел инициализации USR1 сервера в ini-файле клиента.
[TCPServer]
Ports="13522"
Password="xxxxxxxxxxx"

Протокол выделяет понятие команда. Пакет с командой занимает 4 байта и содержит заранее определенное слово и 4 латинских букв. Для обмена командами можно использовать функции SendCmd и ReceiveCmd. В протоколе можно использовать шифрование (как и для любого TCP соединения), однако, шифрование можно включить только после инициации приветствия, что ограничивает использование протокола для обмена конфиденциальной информацией.

Последовательность действий при обмене по USR1 протоколу:

  • Клиентская часть вызывает функцию ConnectUSR1 и получает TCP объект, с помощью которого ведется обмен.
  • Клиентская часть использует конструкцию .SendCmd("USR1"), для инициализации USR1 протокола после соединения с сервером.
  • Клиентская часть получает ответ с помощью функции .ReceiveCmd(). В ответ сервер может:
  1. Разорвать соединение (USR1 не поддерживается)
  2. Отдать команду "BUSY" (сервер занят обслуживанием другого клиента или максимального количества клиентов)
  3. Отдать команду "OK  " (сервер готов к обслуживанию по USR1 протоколу)
  • Клиентская часть использует конструкцию .SendStr(<Строка>), для пересылки любой начальной информации для сервера.
  • При необходимости отсылки группы файлов вместе с начальной информацией, клиент для каждого из файлов последовательно отсылает команду "RECV" (.SendCmd("RECV")) и отсылает файл с помощью .SendFile.
    • После того, как последний файл будет отослан (либо отсылка файлов не производилась вообще), клиент отсылает команду "FNSH".
  • В сервеной части запускается выполнение события OnUsr1Connection, которое на основании текущего состояния системы должно ответить командой "OK  " (обмен инициирован), "BUSY" (север уже занят обслуживанием одного или максимального количества клиентов) или разорвать соединение.
  • Клиентская часть получает ответ с помощью функции .ReceiveCmd() и, руководствуясь им, продолжает или заканчивает обмен.
  • Дальнейший протокол обмена задается программно.

Примеры

Исходный код с примерами серверной и клиентской частей:

//Исходный код примера клиентской части
Function ПровестиОбмен()
  Сокет:=IPConnection.ConnectUSR1("127.0.0.1:13777");//Инициация соединения
  If not Сокет.isConnected() Then
    Message("Сервер не отвечает","!");
    Exit 0;
  EndIf;
  СтрОшибка:="";
  Try
    СтрОшибка:="Сервер не принял режим USR1 (1)!";
    Сокет.SendCmd("USR1");
    Комм:=Сокет.ReceiveCmd();
    If Комм="BUSY" Then
      Message("Сервер занят!","!");
      Exit 0;
    EndIf;
    If Комм<>"OK  " Then
      Message("Сервер не принял режим USR1 (2)!","!");
      Exit 0;
    EndIf;

    СтрОшибка:="Ошибка при обмене!";
    Сокет.SendStr("Hello, this is client!");
    //Отсылка текстового файла C:\file.txt
    Сокет.SendCmd("RECV");
    Сокет.SendFile("C:\file.txt",1);

    //Окончание обмена файлами
    Сокет.SendCmd("FNSH");

    Комм:=Сокет.ReceiveCmd();
    If Комм<>"OK  " Then
      Exit 0;
    EndIf;
    Стр:="Любая информация для обмена";
    Сокет.SendStr(Стр,1);
    Сокет.ReceiveStr(Стр,1);
    Message("Сервер прислал информацию: "+Стр);
    //Далее следует обмен любой другой информацией
  Except
    If СтрОшибка<>"" Then
      Message(СтрОшибка,"!");
    Else
      Message(PopError(),"!");
    EndIf;
    Exit 0;
  EndTry
  Exit 1;
EndFunction


//Исходный код примера серверной части
Function OnUsr1Connection(Сокет,Параметр,FList)
  Try
    Message("Клиент при соединении использовал параметр: "+Параметр);
    If ThreadCount()>1 Then
      //Данный сервер не будет принимать новых клиентов, пока предыдущий запрос не обработан в полной мере
      Сокет.SendCmd("BUSY");
      Exit;
    EndIf;
    Сокет.SendCmd("OK  ");
    For i:=1 To FList.Size() Do
      Message("Клиент прислал файл: "+FList.Get(i));
      Message("  Размер файла: "+File.GetFileSize(FList.Get(i)));
    EndDo;
    Стр:=Сокет.ReceiveStr(Стр,1);
    Message("Клиент прислал информацию: "+Стр);
    Стр:="Ответ на любую информацию";
    Сокет.SendStr(Стр,1);
    //Далее следует обмен любой другой информацией
  Finally
    //Разрываем соединение, чтобы система не ждала продолжения
    SuppressException();
    Сокет.Disconnect();
  EndTry;
EndFunction