C++Builder
  Начало   Форум   Помощь Войти Регистрация  
Страниц: [1] 2 3   Вниз
  Печать  
Автор Тема: IdTCPServer синхронизировать с клиентом  (Прочитано 55668 раз)
Лена
Гость
« : 03 октября 2008, 12:46:02 »

Помогите разобраться со следующей проблемой:
Есть прибор, который шлет на сервер в определенный порт сигнал по GPRS /TCP/IP. К этому прибору идет специальная программа. При запуске этой программы на сервере она начинает принимать сигналы, идущие от прибора.
Я написала программу, которую тоже расположила на сервере. Моя программа использует тот же порт для прослушивания. Используется INDY IdTCPServer. Выключаю программу, которая идет в поставке к прибору, и запускаю свою программу для прослушивания порта. Если я посылаю самостоятельно пакет в этот порт, моя программа успешно его принимает, однако сигналы от прибора она принимать не хочет.
Из документации к прибору есть такая информация:
IntelliTrac unit это прибор
base station это сервер
When you develop your own socket base station software, remember to echo the same
Synchronization message to the IntelliTrac unit when the base station software received
Synchronization message from the IntelliTrac unit. If the IntelliTrac units have not received
the echo Synchronization Message more than 3 times, the IntelliTrac unit will disconnect
GPRS communication and retry to connect to the GPRS network again.

Synchronization message format
typedef struct
{
WORD SyncHeader;
WORD SyncID;
DWORD UnitID;
} SyncStruct;

SyncHeader is always 0xf8fa
SyncID is a message sequence number
UnitID is the unit identification number

For example, received message is
0xFA 0xF8 0x1B 0x01 0x81 0x60 0x33 0x3C
SyncHeader = 0xF8 0xFA
SyncID = 0x01 0x1B (Decimal = 283)
UnitID = 0x3C 0x33 0x60 0x81 (Decimal = 1010000001) – это номер прибора

Это все что написано для разработки собственного софта для прибора…

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


Записан
Лена
Гость
« Ответ #1 : 03 октября 2008, 20:15:20 »

Пригодилось событие OnConnect. Оно срабатывает просто надо сначала запустить софт и потом прибор.
Подскажите, как правильно пришедшую структуру принять и передать прибору?
В каком формате принять структуру?
Вот так читаю пришедший сигнал как строку:
AnsiString Echo = AContext->Connection->IOHandler->ReadLn();
Однако, как я понимаю, пришедшую структуру:
typedef struct
{
WORD SyncHeader;
WORD SyncID;
DWORD UnitID;
} SyncStruct;
надо принять не как строку. Как ее правильно принять и разложить по полям структуры, чтобы потом отправить прибору?
Может надо читать как-то так:
AContext->Connection->IOHandler->ReadStream(….)
?

На рисунке вижу сигнал в точке остонова (рис.прилагаю). Правда номер прибора 0, но может это потому что я читаю стуктуру не правильно???
Записан
Zor
Глобальный модератор
***

Сказали спасибо: +158/-30
Offline Offline

Сообщений: 2946


« Ответ #2 : 03 октября 2008, 21:20:04 »

будем пинать инди до победного конца  Рот на замке
бинарные данные нельзя читать реадлн-ом, выгребите их ReadBuffer или ReadChar-ом (и выкидывать WriteBuffer-ом)
потоки памяти врядли помогут - только если заранее знать размер данных от железки
Записан
Лена
Гость
« Ответ #3 : 06 октября 2008, 11:47:59 »

>только если заранее знать размер данных от железки


Размер данных идущий от прибора для подтверждения соединения с ним, всегда, согласно документации такой:
0xFA 0xF8 0x1B 0x01 0x81 0x60 0x33 0x3C
SyncHeader = 0xF8 0xFA - это постоянный заголовок
SyncID = 0x01 0x1B (Decimal = 283) - тут может быть 1 или 2 или 3 и т.д.
UnitID = 0x3C 0x33 0x60 0x81 (Decimal = 1010000001) – здесь будет другой номер, например 1010000002
Подскажите как правильно используя ReadBuffer прочитать эту стуктуру:
typedef struct
{
WORD SyncHeader;
WORD SyncID;
DWORD UnitID;
} SyncStruct;
и отправить ее обратно прибору для подтверждения соединения?
Перед отправкой также хочется сделать проверку, что пришел правильный заголовок SyncHeader равный 0xF8 0xFA.



« Последнее редактирование: 06 октября 2008, 14:06:13 от Лена » Записан
Лена
Гость
« Ответ #4 : 06 октября 2008, 14:51:30 »

Вот такое наваяла: Рот на замке
Код
TMemoryStream* er; //глобальная переменная
void __fastcall TFormListenPort::IdTCPServer1Connect(TIdContext *AContext)
{
IdTCPClient1->Port = AContext->Connection->Socket->Binding->PeerPort;
IdTCPClient1->Host = AContext->Connection->Socket->Binding->PeerIP;
TByteDynArray IDunit;
AContext->Connection->IOHandler->ReadBytes(IDunit, 8, false);
//int Result = IDunit.Length;
if((IDunit[0] == 0xFA && IDunit[1] == 0xF8) || (IDunit[0] == 0xF8 && IDunit[1] == 0xFA));
{
  try
    {
         try
         {
          IdTCPClient1->Connect();
          IdTCPClient1->IOHandler->Write(IDunit);
         }
         catch(...)
         {
          TDateTime T(Now());
          TStringList * ListWatchCatch = new TStringList();
          AnsiString Log = ExtractFilePath(Application->ExeName);
          Log = Log + "uniterror.txt";
          er->Seek(0, soFromEnd);
          ListWatchCatch->Add("Ошибка отправки эхо: " + AnsiString(IDunit[0]) + " " +
          AnsiString(IDunit[1]) + " " +
          AnsiString(IDunit[2]) + " " +
          AnsiString(IDunit[3]) + " " + T.DateTimeString());
          ListWatchCatch->SaveToStream(er);
          er->SaveToFile(Log);
          delete ListWatchCatch;
         }
     }
    __finally
    {
     IdTCPClient1->Disconnect();
    }
 
}
}
 

На сколько это правильно?
Почему-то DWORD UnitID которое равно IDunit[3] равно 0...
IDunit[3] должно равняться номеру прибора. В моем случае это цифра 1010000002. Не понятна проблема...
« Последнее редактирование: 06 октября 2008, 15:43:17 от Лена » Записан
Zor
Глобальный модератор
***

Сказали спасибо: +158/-30
Offline Offline

Сообщений: 2946


« Ответ #5 : 06 октября 2008, 16:15:02 »

для начала немного изменений в записи структуры, иначе глюки ловить будете очень долго:
Код:
#pragma pack(push, 1)
struct SyncStruct
{
WORD SyncHeader;
WORD SyncID;
DWORD UnitID;
};
#pragma pack(pop)

пример для 9-го инди:
Код:
void __fastcall TFormListenPort::IdTCPServer1Connect (TIdPeerThread *AThread)
{
SyncStruct Sync;
AThread->Connection->ReadBuffer(Sync, sizeof(Sync));
// тут проверка что данные - это Sync пакет. если все ok, отвечаем:
if (Sync.SyncHeader != 0xF8FA) return;
AThread->Connection->WriteBuffer(Sync, sizeof(Sync)); // соединение переустанавливать не надо!!!
// тут пишем логи, ets
}

Записан
Лена
Гость
« Ответ #6 : 06 октября 2008, 17:39:47 »

>AThread->Connection->ReadBuffer(Sync, sizeof(Sync));

Ваш обработчик понятен. Но в 10 INDY нет метода ReadBuffer (рис). Это вызывает у меня проблемы...
void __fastcall TForm1::IdTCPServer1Connect(TIdContext *AContext) тут нет TIdPeerThread *AThread
и соотвественно:
AContext->Connection->IOHandler->методы чтения на рисунке:

P.S.
Зачем мы пишем #pragma pack(push, 1)?
« Последнее редактирование: 09 октября 2008, 11:49:35 от Лена » Записан
Zor
Глобальный модератор
***

Сказали спасибо: +158/-30
Offline Offline

Сообщений: 2946


« Ответ #7 : 06 октября 2008, 21:40:48 »

очень похоже что
(v9) AThread->Connection->ReadBuffer(Sync, sizeof(Sync));
==
(v10) AContext->Connection->IOHandler->ReadBytes(Sync, sizeof(Sync), false);
+все данные, считанные/записываемые теперь идут через TIdBytes (новая фишка ака дурость v10)
« Последнее редактирование: 06 октября 2008, 22:01:30 от Zor » Записан
Лена
Гость
« Ответ #8 : 07 октября 2008, 11:46:53 »

Вот здесь нашла про ReadBuffer в INDY 10: http://groups.google.com/group/borland.public.cppbuilder.internet.socket/browse_thread/thread/b74f9f50d42f1dea
Пользователь Gambit это из тех.поддрежки INDY. Там создается класс: TBufferStream : public TCustomMemoryStream
но раз вы говорите что метод:
AContext->Connection->IOHandler->ReadBytes(Sync, sizeof(Sync), false);
делает свое дело, то мне эта ссылка не пригодиться?

Зачем мы пишем #pragma pack(push, 1) и нужна ли эта строка при компиляции релиза?

В конечном итоге мой код должен быть в IdTCPServer1Execute а не в IdTCPServer1Connect?

А так не правильнее будет:
AContext->Connection->IOHandler->ReadBytes(IDunit, 8, false);
?
Тогда не надо стуктуру объявлять в программе...


Записан
Лена
Гость
« Ответ #9 : 07 октября 2008, 13:40:23 »

Zor, подскажи, пожалуйста, как решить такую проблему:
Итак, первоначально прибор присылает стуктуру, котору надо отправить ему обратно. После этого прибор начинает присылать строки типа: 101000002,20030217132813,121.646060,25.061725,20,157,133,7,0,11,15,0.096,0.000
Как в IdTCPServer1Execute прочитать стуктуру и затем начать читать строки. Ведь так нельзя:
Код
void __fastcall TFormListenPort::IdTCPServer1Execute(TIdContext *AContext)
{
//------------- блок кода отвечающий за прием стуктуры ------------------
 IdTCPClient2->Port = AContext->Connection->Socket->Binding->PeerPort;
 IdTCPClient2->Host = AContext->Connection->Socket->Binding->PeerIP;
 TByteDynArray IDunit;
 AContext->Connection->IOHandler->ReadBytes(IDunit, sizeof(SyncStruct), false);
 if((IDunit[0] == 0xFA && IDunit[1] == 0xF8) || (IDunit[0] == 0xF8 && IDunit[1] == 0xFA))
 {
  try
   {
       try
       {
        IdTCPClient2->Connect();
        IdTCPClient2->IOHandler->Write(IDunit);//отправим стуктуру прибору для потвеждения соединения
       }
          catch(...)
          {
           //запишем в файл ошибку
          }
   }
   __finally
   {
    IdTCPClient2->Disconnect();
   }
 
 }
//------------- конец блока кода отвечающий за прием стуктуры --------------
 
//теперь будут приходит постоянно от прибора строки типа:
//101000002,20030217132813,121.646060,25.061725,20,157,133,7,0,11,15,0.096,0.000
//надо их читать и складывать в базу данных:
 
AnsiString S = AContext->Connection->IOHandler->ReadLn();
и т.д.
 
}
 
 

В одном обработчике нельзя два раза прочитать: AContext->Connection->IOHandler->
Как быть?
Записан
Zor
Глобальный модератор
***

Сказали спасибо: +158/-30
Offline Offline

Сообщений: 2946


« Ответ #10 : 07 октября 2008, 15:55:42 »

1. "прибор присылает стуктуру" - это типа handshake, и делать его надо именно в OnConnect (1 раз) (пример был)
2. "начинает присылать строки" - это вычитываем уже в OnExecute, например
Код:
void __fastcall TFormListenPort::IdTCPServer1Execute(TIdContext *AContext)
{
//теперь будут приходит постоянно от прибора строки типа:
//101000002,20030217132813,121.646060,25.061725,20,157,133,7,0,11,15,0.096,0.000
//надо их читать и складывать в базу данных:
AnsiString S = AContext->Connection->IOHandler->ReadLn();
// тут разбираем и куда то складываем...
}

3. #pragma pack(push, 1) // запрещает компилятору оптимизировать/выравнивать поля структуры
4. А так не правильнее будет: AContext->Connection->IOHandler->ReadBytes(IDunit, 8, false); ? Тогда не надо стуктуру объявлять в программе...

можно и так. это уже личные предпочтения Улыбка можно еще и так:

SyncHeader = AContext->Connection->IOHandler->ReadSmallInt();
SyncID = AContext->Connection->IOHandler->ReadSmallInt();
UnitID = AContext->Connection->IOHandler->ReadInteger();

по это уже изврат



Записан
Лена
Гость
« Ответ #11 : 07 октября 2008, 16:30:08 »

Большое спасибо за объяснения!

1. "прибор присылает стуктуру" - это типа handshake, и делать его надо именно в OnConnect (1 раз) (пример был)

Вот тут как раз и проблема.
Делаю так. Пишу тестовый код:
Код
void __fastcall TFormListenPort::Button1Click(TObject *Sender)
{
try
{
 try
 {
  IdTCPClient1->Connect();
  IdTCPClient1->IOHandler->WriteLn("111,20030217132813,121.646060,25.061725,20,157,133,7,0,11,15,0.096,0.000");
  }
 catch(...)
 {
  ShowMessage("Ошибка соединения при отправке");
 }
}
__finally
{
 IdTCPClient1->Disconnect();
}
 
}

При каждом нажатии кнопки сначал происходит OnConnect и потом IdTCPServer1Execute. Я думала OnConnect будет вызван только один раз.
Если прибор начнет слать строки то, что при приходе каждой строки будет возникать OnConnect или все же это произойдет один раз?

Но даже если в идеальном случае OnConnect произойдет один раз. То смотрим, что получается при первом приходе стуктуры:
Стуктура пришла мы ее приняли в OnConnect, по любому возникает затем событие IdTCPServer1Execute и мы снова пытаемся принять стуктуру но уже как строку. Получается чтение два раза, это ведь не правильно для Indy?
Записан
Лена
Гость
« Ответ #12 : 07 октября 2008, 16:51:39 »

Только что проверила:
Код
void __fastcall TFormListenPort::IdTCPServer1Connect(TIdContext *AContext)
{
 TByteDynArray IDunit;
 AContext->Connection->IOHandler->ReadBytes(IDunit, sizeof(SyncStruct), false);//тут точка остонова
}
 
void __fastcall TFormListenPort::IdTCPServer1Execute(TIdContext *AContext)
{
TStringList * ListWatch = new TStringList(); //тут точка остонова
// далее другой код

При включении прибора, поподаю во все точки остонова...
Может IdTCPServer1Execute не возникнет если ответить прибору?
Просто я пока не могу ответить прибору. Сигналы от него принимаю, а отправить ему не могу. Сис админ разбирается. Но факт остается: cрабатывают обе точки останова при приходе стуктуры...
Записан
Zor
Глобальный модератор
***

Сказали спасибо: +158/-30
Offline Offline

Сообщений: 2946


« Ответ #13 : 07 октября 2008, 16:52:30 »

нда, явное недопонимание работы сети Улыбка

объясняю
1. мы подключились кабелем к железу (прибор)
2. прибор просек что к нему подключились (или что его включили) и пытается подключиться к серверу снаружи
3. (и, если ваша программа работает) это ему удается
4. (после этого) на стророне сервера возникает OnConnect + handshake с железом, принимаем и отправляем назад 8 байт структуры, соединение сохраняется
5. затем на стороне сервера вызываться OnExecute
6. в ней мы ждем прихода строки от железа и обрабатываем ее, соединение сохраняется
7. см п.5

это для случая, когда железо подключается 1 раз и после этого держит соединение.
я надеюсь, у вас так? (тут начинаем лихорадочно читать документацию...)
иначе надо флажками регулировать, кого куда.

картинка из мануала. для более ясного, так сказать. цепочка событий OnConnect/OnExecute/OnDisconnect возникает всегда при подключени клиента.

« Последнее редактирование: 07 октября 2008, 17:02:16 от Zor » Записан
Лена
Гость
« Ответ #14 : 07 октября 2008, 17:08:10 »


это для случая, когда железо подключается 1 раз и после этого держит соединение.
я надеюсь, у вас так?

Прибор стоит на автомобиле. Когда на него подают 12 вольт (включают), он начинает слать стуктуру согласно документации так:
IntelliTrac unit это прибор
base station это сервер
When you develop your own socket base station software, remember to echo the same
Synchronization message to the IntelliTrac unit when the base station software received
Synchronization message from the IntelliTrac unit. If the IntelliTrac units have not received
the echo Synchronization Message more than 3 times, the IntelliTrac unit will disconnect
GPRS communication and retry to connect to the GPRS network again.

Synchronization message format
typedef struct
{
WORD SyncHeader;
WORD SyncID;
DWORD UnitID;
} SyncStruct;

Из прочитаного поняла что мой код должен быть таким:
Надо ответить прибору той же стуктурой. После этого он начнет слать свои координаты...
Код
void __fastcall TFormListenPort::IdTCPServer1Connect(TIdContext *AContext)
{
 IdTCPClient2->Port = AContext->Connection->Socket->Binding->PeerPort;
 IdTCPClient2->Host = AContext->Connection->Socket->Binding->PeerIP;
 TByteDynArray IDunit;
 AContext->Connection->IOHandler->ReadBytes(IDunit, sizeof(SyncStruct), false);
 
 if((IDunit[0] == 0xFA && IDunit[1] == 0xF8) || (IDunit[0] == 0xF8 && IDunit[1] == 0xFA))
 {
  try
{
 try
 {
  IdTCPClient2->Connect();
  IdTCPClient2->IOHandler->Write(IDunit);
 }
 catch(...)
 {
                                        //запишем в файл ошибку
 }
}
__finally
{
 IdTCPClient2->Disconnect();
}
 
 }
}
 
 
Строки:
IdTCPClient2->Connect();
IdTCPClient2->IOHandler->Write(IDunit);
у меня пока закомментированы, потому что я пока не могу отправить прибору. Сис админ разбирается.

Я не совсем понимаю термин OnConnect + handshake.
Отсюда вопросы:
1. Мой код корректен?
2. Когда будет обратная связь с прибором и я уберу комментарии со строк:
IdTCPClient2->Connect();
IdTCPClient2->IOHandler->Write(IDunit);
то при подключении IdTCPServer1Connect произойдет ровно один раз и не произойдет IdTCPServer1Execute (это ваш пункт 4).
IdTCPServer1Execute начнет возникать только после установки связи с прибором.

Сейчас происходят оба события...


P.S.
И еще вопрос в помощь нашему сис админу.Улыбка
Стуктура от прибора успешно приходит при включении прибора. Из строк:
IdTCPClient2->Port = AContext->Connection->Socket->Binding->PeerPort;
IdTCPClient2->Host = AContext->Connection->Socket->Binding->PeerIP;
я получаю информацию куда переслать стуктуру. При каждом включении/выключении прибора значения:
IdTCPClient2->Port
IdTCPClient2->Host
меняются. Видимо они устанавливаются динамически при включении прибора и выхода его в сеть.
Вопрос такой почему удается принять сигналы, но вот отправить не получается. На строке:
IdTCPClient2->Connect(); возникает time out.
В чем может буть проблема?
Сис админ у себя видит следующую картину (может у него снифер):
Я ставлю точку останова на строке:
if((IDunit[0] == 0xFA && IDunit[1] == 0xF8) || (IDunit[0] == 0xF8 && IDunit[1] == 0xFA))
все включаем. Происходит OnConnect и поподаю на точку останова. Сис админ видит у себя правильные
IdTCPClient2->Port
IdTCPClient2->Host
они такие же как у меня в программе. Еще он говорит что пришли с моего компа еще какие-то данные. Наверное это Windows шлет ведь я стаю на точке остонова и ничего не отправляю?
В любом случае IdTCPClient2->Connect(); возникает time out.
Может что подскажете?  Подмигивающий



« Последнее редактирование: 07 октября 2008, 18:15:30 от Лена » Записан
Zor
Глобальный модератор
***

Сказали спасибо: +158/-30
Offline Offline

Сообщений: 2946


« Ответ #15 : 07 октября 2008, 21:11:00 »

у меня уже дежа вю Улыбка
повторяю: делать связь "назад" не надо! IOhandler - это уже открытый канал в ОБЕ стороны, вы УЖЕ подключены к прибору!
все ваши "Connect/Disconnect" - стираете нафиг.
// разумеется вы получаете тайм аут - с той стороны клиент стоит, а не сервер, некуда подключаться.

OnExecute после OnConnect придет в любом случае - это стандартный режим работы. (ну если в OnConnect ничего критического не произойдет)
Записан
Лена
Гость
« Ответ #16 : 08 октября 2008, 12:52:22 »

>у меня уже дежа вю

А у меня прединфаркт от этого прибора.  Веселый


Последовательность действий:
Включаю прибор. Программой идущей в комплекте к прибору задаю ему слать координаты каждые 10 секунд. По индекатору вижу, что все нормально прибор начинает слать координаты. Выключаю программу идущую в комплекте с прибором.
Запускаю свою программу. Теперь код такой:
Код
void __fastcall TFormListenPort::IdTCPServer1Connect(TIdContext *AContext)
{
TByteDynArray IDunit;
AContext->Connection->IOHandler->ReadBytes(IDunit, sizeof(SyncStruct), false);//точка останова
}
 
В точке останова вижу что событие происходит и приходит стуктура.

Далее сразу происходит событие:
Код
void __fastcall TFormListenPort::IdTCPServer1Execute(TIdContext *AContext)
{
//-------------  тестовая запись в файл --------------
TStringList * ListWatch = new TStringList();
AnsiString S = AContext->Connection->IOHandler->ReadLn();
TStringList * ListWatchCatch = new TStringList(); //точка останова
AnsiString Log = ExtractFilePath(Application->ExeName);
Log = Log + "logport.txt";
pms->Seek(0, soFromEnd);
ListWatchCatch->Add(S);
ListWatchCatch->SaveToStream(pms);
pms->SaveToFile(Log);
delete ListWatchCatch;
delete ListWatch;
 
//------------ конец тестовой записи -----------------
}
 

В точке останова вижу, что пришла таже стуктура. Только ss.UnitID рано 0, но это естествнно, ведь я читаю стуктуру как строку. Рисунок того что происходит в точке останова прилагаю.
После этого событие IdTCPServer1Execute больше не наступает. Прибор мигает лампочками, которые говорят что он не может соединиться.
Как начать получать координаты? Непонимающий

P.S.
И все таки трудности моего перевода:  Улыбка
When you develop your own socket base station software, remember to echo the same
Synchronization message to the IntelliTrac unit when the base station software received
Synchronization message from the IntelliTrac unit. If the IntelliTrac units have not received
the echo Synchronization Message more than 3 times, the IntelliTrac unit will disconnect
GPRS communication and retry to connect to the GPRS network again.

Вот поэтому думала что надо ответить прибору... в любом случае как начать получать координаты?

« Последнее редактирование: 09 октября 2008, 11:50:06 от Лена » Записан
Лена
Гость
« Ответ #17 : 08 октября 2008, 14:12:17 »

Вот, что у меня записывается в файл при длительной работе мой программы:
ъш ‚`3<ъш ‚`3<ъш ‚`3<ъш ‚`3<ъш ‚`3<ъш ‚`3<ъш ‚`3<ъш    ‚`3<ъш

ъш это заголовок стуктуры...

Может строка:
AContext->Connection->IOHandler->ReadBytes(IDunit, sizeof(SyncStruct), false);
не верно устанавливает канал связи?
Записан
Zor
Глобальный модератор
***

Сказали спасибо: +158/-30
Offline Offline

Сообщений: 2946


« Ответ #18 : 08 октября 2008, 15:23:56 »

а может, все-таки, ответить ему?

void __fastcall TFormListenPort::IdTCPServer1Connect(TIdContext *AContext)
{
TIdBytes Buffer;
AContext->Connection->IOHandler->ReadBytes(Buffer, sizeof(SyncStruct), false); // читаем структуру
// тут неплохо бы вывести ее куда нибудь или проверить корректность
// if ((Buffer[0] != 0xFA) || (Buffer[1] != 0xF8)) return;
AContext->Connection->IOHandler->Write(Buffer); // кидаем назад прибору
}
Записан
Лена
Гость
« Ответ #19 : 08 октября 2008, 15:31:23 »

Cейчас попробую. Улыбка
А почему лучше  TIdBytes Buffer;
а не TByteDynArray Buffer;
Это существенно?
Записан
Zor
Глобальный модератор
***

Сказали спасибо: +158/-30
Offline Offline

Сообщений: 2946


« Ответ #20 : 08 октября 2008, 16:06:38 »

это как в документации
Записан
Лена
Гость
« Ответ #21 : 08 октября 2008, 16:26:22 »

РАБОТАЕТ!  Смеющийся
Причем оба варианта и TIdBytes и TByteDynArray...
Вот так, буржуинская адская машинка стала слать свои координаты: Веселый
Код
void __fastcall TFormListenPort::IdTCPServer1Connect(TIdContext *AContext)
{
 TByteDynArray IDunit;
 try
 {
  AContext->Connection->IOHandler->ReadBytes(IDunit, sizeof(SyncStruct), false);
  if ((IDunit[0] != 0xFA) || (IDunit[1] != 0xF8))
  {
return;
      }
  AContext->Connection->IOHandler->Write(IDunit);
 }
  catch(...)
{
  AnsiString Log = ExtractFilePath(Application->ExeName);
  Log = Log + "uniterror.txt";
if(FileExists(Log))
  {
  SyncStruct ss;
  unsigned int i;
  unsigned short sh[2];
  unsigned char ch[4];
  for(int j = 0; j<4; j++) ch[j] = IDunit[j];
  memcpy(sh,ch,4);
  for(int j = 0; j<4; j++) ch[j] = IDunit[j+4];
  memcpy(&i,ch,4);
  ss.SyncHeader = sh[0];
  ss.SyncID = sh[1];
  ss.UnitID = i;
 
  er->LoadFromFile(Log);
  er->Seek(0, soFromEnd);
  TDateTime T(Now());
  TStringList * ListWatchCatch = new TStringList();
  ListWatchCatch->Add("Ошибка отправки/приема эхо: " + AnsiString(ss.SyncHeader) + " " +
  AnsiString(ss.SyncID) + " " +
  AnsiString(ss.UnitID) + " " + T.DateTimeString());
  ListWatchCatch->SaveToStream(er);
  er->SaveToFile(Log);
  delete ListWatchCatch;
 }
}
 
 
}
 
 

Тестовое чтение в файл:
Код
void __fastcall TFormListenPort::IdTCPServer1Execute(TIdContext *AContext)
{
 
AnsiString S = AContext->Connection->IOHandler->ReadLn();
AnsiString Log = ExtractFilePath(Application->ExeName);
Log = Log + "logport.txt";
pms->LoadFromFile(Log);
pms->Seek(0, soFromEnd);
 
TStringList * ListWatchCatch = new TStringList();
ListWatchCatch->Add(S);
ListWatchCatch->SaveToStream(pms);
pms->SaveToFile(Log);
delete ListWatchCatch;
}
 
 

Zor, большое спасибо!  Целующий Целующий Целующий
Записан
Лена
Гость
« Ответ #22 : 08 октября 2008, 16:45:36 »

Zor, еще вопросик:
В книге Архангельского сказано, что после приема данных в IdTCPServer1Execute надо всегда писать:
__finally
 {
  AContext->Connection->Disconnect();
 }
В моем случае это не приемлемо?
Записан
Zor
Глобальный модератор
***

Сказали спасибо: +158/-30
Offline Offline

Сообщений: 2946


« Ответ #23 : 08 октября 2008, 17:21:47 »

Нет, конечно.
Книгу эту не читал, но это скорее пример протокола типа "коннект - одна команда-один ответ - дисконнект"

Записан
Лена
Гость
« Ответ #24 : 08 октября 2008, 17:35:14 »

Нет, конечно.

Все ясно. Спасибо!
Записан
Лена
Гость
« Ответ #25 : 09 октября 2008, 11:52:04 »

Zor, как вы думаете, мой код и INDY 10 справяться с задачей если, например, приборов будет штук 50 и каждый будет слать сигнал, например, каждые 10 секунд?
Записан
Zor
Глобальный модератор
***

Сказали спасибо: +158/-30
Offline Offline

Сообщений: 2946


« Ответ #26 : 09 октября 2008, 15:34:32 »

80 байт строка x 50 штук / 10 с = 400 байт/с. 400 байт для современных машин... не, не справится  Рот на замке шутк.
а вот код ведения лога я бы переписал - там буквально в 5 строк можно уложится

Записан
Лена
Гость
« Ответ #27 : 09 октября 2008, 16:04:15 »

а вот код ведения лога я бы переписал - там буквально в 5 строк можно уложится

А как бы выглядел ваш вариант? Строит глазки
Записан
oxotnik
Глобальный модератор
***

Сказали спасибо: +100/-15
Offline Offline

Сообщений: 2425


« Ответ #28 : 09 октября 2008, 16:13:00 »

Код
   TFileStream *fsLogFile;
if (!FileExists(LogFile)) fsLogFile = new TFileStream(LogFile, fmCreate);
else fsLogFile = new TFileStream(LogFile, fmOpenWrite);
fsLogFile->Seek(0, soFromEnd);
AnsiString LogStr = /*Лог-строка*/ + "\r\n";
fsLogFile->Write(LogStr.c_str(), LogStr.Length());
delete fsLogFile;
 
Записан
Zor
Глобальный модератор
***

Сказали спасибо: +158/-30
Offline Offline

Сообщений: 2946


« Ответ #29 : 09 октября 2008, 16:30:25 »

Очень похоже Улыбка
// Seek можно выкинуть, открыв в режиме Append.
НО ведение логов должно быть потокобезопасным, если железок  > 1. А это значит + CriticalSection к коду
Записан
Страниц: [1] 2 3   Вверх
  Печать  
 
Перейти в: