Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Indy 10 файл-сервер работает но както.... Простой файл-сервер с огр. доступом  
:(
    Опции темы
ochelot
  Дата 11.4.2013, 14:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 13
Регистрация: 3.11.2009

Репутация: нет
Всего: нет



Смысл кода в передаче файлов по сети от клиентов (в будущем с последующем доступом для клиентов (кому можно а кому нет)...)


<client>       <server>

-> user        <- user Ok
-> sendfile    <- ok; file name
-> 11.mkv    <- ok; file current
-> данные    <- next
....
-> закончили <- ok
-> exit             <- exit ok.

Т.е. в этом коде мы предполагаем что для обработки команд мы сначала отправляем user
и входим в стадию обработки команд для user (в будущем проверка на права).
И поле отправки мы остаемся и ожидаем следующую команду, только после exit вызываем Disconnect.

Но не пойму по всем описаниям в методе void __fastcall TForm1::ServerExecute(TIdContext *AContext)
мы не должны делать внутри цикл, для получения команд (типа пока нет Disconnect(a) Execute постоянно вызывается для клиента). 
Но если убрать цикл то сервер обрабатывает первую команду и на остальные уже не реагирует т.е. клиент отправил user получил ответ,  после отправил exit и сервер ни как не отреагировал.

Вопрос почему с циклом работает а без нет?  ???
Можно ли систему команд и по другому реализовать без цикла

:Server
Код

#define READ_BLOCK_SIZE 16384
void __fastcall TForm1::ServerExecute(TIdContext *AContext)
{
if(AContext->Connection->IOHandler->InputBufferIsEmpty())
       {
           AContext->Connection->IOHandler->CheckForDataOnSource(1);
           if (AContext->Connection->IOHandler->InputBufferIsEmpty()) return;
       }


  AnsiString Msg = AContext->Connection->IOHandler->ReadLn().LowerCase();
  if (Msg == "user")
   {
    AContext->Connection->IOHandler->WriteLn("user ok");

    while(1) // BEZ ETOGO CHIKLA RABOTAT NE BUDET
    {
      Msg = AContext->Connection->IOHandler->ReadLn().LowerCase();

      if (Msg == "exit") {AContext->Connection->IOHandler->WriteLn("exit ok.");break; }
      else
      if (Msg == "sendfile")
        {
           AContext->Connection->IOHandler->WriteLn("ok; file name");
           AnsiString FileName = AContext->Connection->IOHandler->ReadLn();
           SetCurrentDir(ExtractFileDir(Application->ExeName)); 
           FileName = ExpandFileName(FileName); 
           AnsiString FilePath = ExtractFileDir(FileName); 
           ForceDirectories(FilePath);
           AContext->Connection->IOHandler->WriteLn("ok; file current");

           int FileHandle = open(FileName.c_str(), O_CREAT | O_TRUNC | O_BINARY | O_RDWR, S_IREAD | S_IWRITE);

           TMemoryStream *Stream = new TMemoryStream();

           while (1)
           {
              Stream->Position = 0;
              Stream->SetSize(0);
              AContext->Connection->IOHandler->ReadStream(Stream);

              write(FileHandle, Stream->Memory, Stream->Size);

              if (Stream->Size >= READ_BLOCK_SIZE)
               {
                  AContext->Connection->IOHandler->WriteLn("next");
                  continue;
               }
              if (Stream->Size < READ_BLOCK_SIZE)
               {
                  AContext->Connection->IOHandler->WriteLn("ok");
                  break;
               }
           }

          delete Stream;
          close(FileHandle);
       }
      else
       AContext->Connection->IOHandler->WriteLn("error command");
    }
     AContext->Connection->Disconnect();
    }
}


Это сообщение отредактировал(а) ochelot - 12.4.2013, 08:46
PM MAIL   Вверх
Avazart
Дата 12.4.2013, 15:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 63
Регистрация: 6.4.2013

Репутация: нет
Всего: нет



Цитата

Вопрос почему с циклом работает а без нет?  ???

Ну а как бы почему должно работать?

Для каждого клиента  создается свой поток TIdThread наследованый от TThread, как я понимаю Execute() это ф-ция каждого потока. А значит и обработка должна вестись аналогично TThread по условию

Код

while( <условие>)
{


}

PM MAIL   Вверх
ochelot
  Дата 12.4.2013, 15:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 13
Регистрация: 3.11.2009

Репутация: нет
Всего: нет



Цитата(Avazart @ 12.4.2013,  15:05)
Цитата

Вопрос почему с циклом работает а без нет?  ???

Ну а как бы почему должно работать?

Для каждого клиента  создается свой поток TIdThread наследованый от TThread, как я понимаю Execute() это ф-ция каждого потока. А значит и обработка должна вестись аналогично TThread по условию

Код

while( <условие>)
{


}

Т.е. без цикла, при подключении клиента создается поток в котором вызывается Execute, выполняет его и по завершению закрывает поток (но не обрывает соединение (Disconnect)) и после Execute не вызывается, тем самым игнорируя последующие сообщения от клиента?
Я думал что поток завершается когда происходит Disconnect... 

PM MAIL   Вверх
Avazart
Дата 12.4.2013, 17:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 63
Регистрация: 6.4.2013

Репутация: нет
Всего: нет



Цитата

Т.е. без цикла, при подключении клиента создается поток в котором вызывается Execute, выполняет его и по завершению закрывает поток (но не обрывает соединение (Disconnect)) и после Execute не вызывается, тем самым игнорируя последующие сообщения от клиента?

А  что соединение не разрывается ?
Последующие сообщения недоходят ибо надо заного установить соединение... 
PM MAIL   Вверх
ochelot
  Дата 12.4.2013, 19:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 13
Регистрация: 3.11.2009

Репутация: нет
Всего: нет



Цитата(Avazart @ 12.4.2013,  17:38)
Цитата

Т.е. без цикла, при подключении клиента создается поток в котором вызывается Execute, выполняет его и по завершению закрывает поток (но не обрывает соединение (Disconnect)) и после Execute не вызывается, тем самым игнорируя последующие сообщения от клиента?

А  что соединение не разрывается ?
Последующие сообщения недоходят ибо надо заного установить соединение...

Ну во всяком случае событие TidTCPServer OnDisconnected не срабатывает если только вручную Disconected не вызвать. Следовательно он как бы не отключается.
А вообще где можно узнать как эти механизмы работают?

p.s. Читал Indy deep - так там как то поверхностно коснулись и то не 10 версии ИНДИ 
PM MAIL   Вверх
Avazart
Дата 12.4.2013, 20:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 63
Регистрация: 6.4.2013

Репутация: нет
Всего: нет



Документация и Исходники ...

Indy depf там только в общем ...

Надо пробовать... попробую отпишусь...
PM MAIL   Вверх
Avazart
Дата 12.4.2013, 23:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 63
Регистрация: 6.4.2013

Репутация: нет
Всего: нет



Смотрю в Indy in Depth стр 91 приводится пример и утверждается обратное что Execute() выполняется циклично, а соединение прерывается само если что-то не так, либо по команде:
Код

procedure TformMain.IdTCPServer1Execute(AThread: TIdPeerThread);
var
LCmd: string;
begin
with AThread.Connection do
begin
LCmd := Trim(ReadLn);
if SameText(LCmd, 'QUIT') then
begin
WriteLn('200 Good bye');
Disconnect;
end
else if SameText(LCmd, 'DATE') then
begin
WriteLn('200 ' + DateToStr(Date));
end
else
begin
WriteLn('400 Unknown command');
end;
end;
end;

user posted image


Это сообщение отредактировал(а) Avazart - 12.4.2013, 23:46
PM MAIL   Вверх
ochelot
Дата 13.4.2013, 09:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 13
Регистрация: 3.11.2009

Репутация: нет
Всего: нет



Вот именно, вызывается OnExecute, проверяется соединение (CheckConnection) и снова вызывается OnExecute, и такой цикл для каждого клиента в отдельном потоке.
В моем примере приходится вставлять в OnExecute еще цикл по условию  smile ...

В примере из книги OnExecute состоит из 
procedure TformMain.IdTCPServer1Execute(AThread: TIdPeerThread);

а в Builder с indy 10 OnExecute состоит из 
void __fastcall TForm1::ServerExecute(TIdContext *AContext)

отличия в параметрах...
Я так понимаю в книге описывается indy 9 а мы используем 10 версию... говорят они кардинально отличаются...

Могут ли у них и механизмы работы, что в диаграмме из книги работать по другому?


p.s. Мне тут жена говорит "Ну если и так (как в примере) работает хорошо и как нужно, нафига лезть глубоко и пытаться что то поменять", но хочется же докопаться до истины  smile 

Это сообщение отредактировал(а) ochelot - 13.4.2013, 10:15
PM MAIL   Вверх
ochelot
Дата 13.4.2013, 10:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 13
Регистрация: 3.11.2009

Репутация: нет
Всего: нет



Вот пример для indy 10 из официальной документации и вроде по описанию, диаграмма работы примерно такая же...

Код

TMyForm.MyServerExecute(AContext: TIdContext);
var
lCmd: string;
begin
lCmd := Trim(AContext.Connection.IOHandler.ReadLn); if AnsiSameText(lCmd, 'HELP') then
begin
          AContext.Connection.IOHandler.WriteLn('HELP');
          AContext.Connection.IOHandler.WriteLn('QUIT');
          AContext.Connection.IOHandler.WriteLn('GETTIMESTAMP');
          AContext.Connection.IOHandler.WriteLn('');
end
else if AnsiSameText(lCmd, 'QUIT') then begin
          AContext.Connection.IOHandler.WriteLn('Goodbye...');
          AContext.Connection.IOHandler.WriteLn('');
          AContext.Connection.Disconnect;
end
else if AnsiSameText(lCmd, 'GETTIMESTAMP') then begin
          AContext.Connection.IOHandler.WriteLn(
            FormatDateTime(Now, 'yyyy-mm-ddThh:nn:ss.zzz'));
AContext.Connection.IOHandler.WriteLn(''); end;
end;



Это сообщение отредактировал(а) ochelot - 13.4.2013, 10:16
PM MAIL   Вверх
Avazart
Дата 13.4.2013, 15:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 63
Регистрация: 6.4.2013

Репутация: нет
Всего: нет



Цитата

В моем примере приходится вставлять в OnExecute еще цикл по условию 

Да скорее всего у вас код не верный, читаете записываете неправильно ...
PM MAIL   Вверх
Avazart
Дата 13.4.2013, 17:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 63
Регистрация: 6.4.2013

Репутация: нет
Всего: нет



Вот мой пример сервера на скорую руку :
( без обработки команд, всегда отвечает клиенту "what?", добавил лог серверу но как-то криво вроде)
Код C++

Код

#include <IdSync.hpp>
//---------------------------------------------------------------------------
class TMyNotify: public TIdNotify
{
    String FLine;

    virtual void __fastcall DoNotify()
     {
       Form1->Memo1->Lines->Add(FLine);
     }

  public:
    __fastcall TMyNotify(String Line):TIdNotify(),FLine(Line) {}
};
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
   IdTCPServer1->DefaultPort= 2013;
   IdTCPServer1->Active= true;

   IdTCPServer1->Intercept= IdServerInterceptLogEvent1;
   IdServerInterceptLogEvent1->LogTime= true;
   IdServerInterceptLogEvent1->ReplaceCRLF= false;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::IdTCPServer1Execute(TIdContext *AContext)
{
   AContext->Connection->IOHandler->WriteLnRFC("What ?");
   String Line=  AContext->Connection->IOHandler->ReadLn(); // Line не используем - у нас есть лог для просмотра.
}
//---------------------------------------------------------------------------
void __fastcall TForm1::IdServerInterceptLogEvent1LogString(TIdServerInterceptLogEvent *ASender,
          const UnicodeString AText)
{
  // Судя из написанного в книге нужна синхронизация с основным потоком, а для сервера лучше всего подходит через IdNotify
  (new TMyNotify(AText))->Notify(); // в общем дикая запись, пытаться освобождать память не надо - само должно удалиться.
}
//---------------------------------------------------------------------------







Это сообщение отредактировал(а) Avazart - 13.4.2013, 18:07
PM MAIL   Вверх
ochelot
Дата 14.4.2013, 10:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 13
Регистрация: 3.11.2009

Репутация: нет
Всего: нет



Цитата(Avazart @ 13.4.2013,  17:57)
Вот мой пример сервера на скорую руку :
( без обработки команд, всегда отвечает клиенту "what?", добавил лог серверу но как-то криво вроде)
Код C++

Код

#include <IdSync.hpp>
//---------------------------------------------------------------------------
class TMyNotify: public TIdNotify
{
    String FLine;

    virtual void __fastcall DoNotify()
     {
       Form1->Memo1->Lines->Add(FLine);
     }

  public:
    __fastcall TMyNotify(String Line):TIdNotify(),FLine(Line) {}
};
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
   IdTCPServer1->DefaultPort= 2013;
   IdTCPServer1->Active= true;

   IdTCPServer1->Intercept= IdServerInterceptLogEvent1;
   IdServerInterceptLogEvent1->LogTime= true;
   IdServerInterceptLogEvent1->ReplaceCRLF= false;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::IdTCPServer1Execute(TIdContext *AContext)
{
   AContext->Connection->IOHandler->WriteLnRFC("What ?");
   String Line=  AContext->Connection->IOHandler->ReadLn(); // Line не используем - у нас есть лог для просмотра.
}
//---------------------------------------------------------------------------
void __fastcall TForm1::IdServerInterceptLogEvent1LogString(TIdServerInterceptLogEvent *ASender,
          const UnicodeString AText)
{
  // Судя из написанного в книге нужна синхронизация с основным потоком, а для сервера лучше всего подходит через IdNotify
  (new TMyNotify(AText))->Notify(); // в общем дикая запись, пытаться освобождать память не надо - само должно удалиться.
}
//---------------------------------------------------------------------------


Да, Вы правы... пробовал Ваш пример.. работает...  smile 

Возникли вопросики  smile 
1. А для чего нужен TIdNotify?

2. Почему порт выдает при коннекте не 2013 (как порт сервера) а в логе пишется что то типа 

127.0.0.1:2177 Recv 14.04.2013 11:51:22: USER

127.0.0.1:2177 Stat Disconnected.

0.0.0.0:0 Stat Disconnected.

127.0.0.1:2180 Stat Connected.

3. Как можно организовать проверку пользователя типа отправили user XXX и далее можно остальные команды и что по новой проверка только после Disconnect?

4.Какие потенциальные ошибки могут всплыть в моем примере при использовании множеством клиентов?

PM MAIL   Вверх
Avazart
Дата 14.4.2013, 16:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 63
Регистрация: 6.4.2013

Репутация: нет
Всего: нет



1. Читайте комментарии в коде - для синхронизации...
2. Возможно потому что 2177,2180  это не порт,  а возможно потому что порт настраивается как то не так.
3. В книге рекомендуется использовать не TIdTCPServer, а TIdCmdTCPServer  он удобнее для команд ...
4. Я не знаю код код писал наугад ...
PM MAIL   Вверх
ochelot
Дата 15.4.2013, 10:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 13
Регистрация: 3.11.2009

Репутация: нет
Всего: нет



Спасибо за ответы  smile 

А все таки если использовать OnExecute для верификации клиента, как теоретически организовать процедуру?

При соединении клиент отправляет USER ivanov#123# пользователь и пароль.
Сервер проверяет что такому пользователю разрешено выполнять такие то команды (например TIME).

И получается есть список команд:

DATE - Разрешено только клиенту ivanov 
TIME -  Разрешено только клиенту petrov  
LIST - Разрешено всем
USER - Разрешено всем

Единственное мне приходит в голову сохранять  данные где то о клиенте при прохождении проверки USER xxx , 
при каждом вызове OnExecute проверять проходил ли пользователь проверку и проверять что ему можно а что нет,
при OnDisconnect забываем данные о клиенте.
PM MAIL   Вверх
Avazart
Дата 15.4.2013, 16:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 63
Регистрация: 6.4.2013

Репутация: нет
Всего: нет



Лучше 
Код

999 ivanov#123#

Тогда не придется парсить и в коде можно использовать switch/case

Цитата

Единственное мне приходит в голову сохранять  данные где то о клиенте

Ну да, а еще видимо нужна будет БД содержащая список пользователей их права, - тут нужно будет обеспечить потокобезопасность.
PM MAIL   Вверх
Страницы: (3) Все [1] 2 3 
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++ Builder"
Rrader

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по С++ Builder обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Настоятельно рекомендуем заглянуть в DRKB (Delphi Russian Knowledge Base) - крупнейший в рунете сборник материалов по Дельфи


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Rrader.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C++ Builder | Следующая тема »


 




[ Время генерации скрипта: 0.0571 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.