Название: IdTCPServer синхронизировать с клиентом Отправлено: Лена от 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. :( Подскажите, пожалуйста, как синхронизировать работу прибора и моей программы на основе это информации, а то я не понимаю, что от меня требуется. Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: Лена от 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, но может это потому что я читаю стуктуру не правильно??? Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: Zor от 03 октября 2008, 21:20:04 будем пинать инди до победного конца :-X
бинарные данные нельзя читать реадлн-ом, выгребите их ReadBuffer или ReadChar-ом (и выкидывать WriteBuffer-ом) потоки памяти врядли помогут - только если заранее знать размер данных от железки Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: Лена от 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. Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: Лена от 06 октября 2008, 14:51:30 Вот такое наваяла: :-X
Код TMemoryStream* er; //глобальная переменная На сколько это правильно? Почему-то DWORD UnitID которое равно IDunit[3] равно 0... IDunit[3] должно равняться номеру прибора. В моем случае это цифра 1010000002. Не понятна проблема... Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: Zor от 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 } Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: Лена от 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)? Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: Zor от 06 октября 2008, 21:40:48 очень похоже что
(v9) AThread->Connection->ReadBuffer(Sync, sizeof(Sync)); == (v10) AContext->Connection->IOHandler->ReadBytes(Sync, sizeof(Sync), false); +все данные, считанные/записываемые теперь идут через TIdBytes (новая фишка ака дурость v10) Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: Лена от 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); ? Тогда не надо стуктуру объявлять в программе... Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: Лена от 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) В одном обработчике нельзя два раза прочитать: AContext->Connection->IOHandler-> Как быть? Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: Zor от 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(); по это уже изврат Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: Лена от 07 октября 2008, 16:30:08 Большое спасибо за объяснения!
1. "прибор присылает стуктуру" - это типа handshake, и делать его надо именно в OnConnect (1 раз) (пример был) Вот тут как раз и проблема. Делаю так. Пишу тестовый код: Код void __fastcall TFormListenPort::Button1Click(TObject *Sender) При каждом нажатии кнопки сначал происходит OnConnect и потом IdTCPServer1Execute. Я думала OnConnect будет вызван только один раз. Если прибор начнет слать строки то, что при приходе каждой строки будет возникать OnConnect или все же это произойдет один раз? Но даже если в идеальном случае OnConnect произойдет один раз. То смотрим, что получается при первом приходе стуктуры: Стуктура пришла мы ее приняли в OnConnect, по любому возникает затем событие IdTCPServer1Execute и мы снова пытаемся принять стуктуру но уже как строку. Получается чтение два раза, это ведь не правильно для Indy? Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: Лена от 07 октября 2008, 16:51:39 Только что проверила:
Код void __fastcall TFormListenPort::IdTCPServer1Connect(TIdContext *AContext) При включении прибора, поподаю во все точки остонова... Может IdTCPServer1Execute не возникнет если ответить прибору? Просто я пока не могу ответить прибору. Сигналы от него принимаю, а отправить ему не могу. Сис админ разбирается. Но факт остается: cрабатывают обе точки останова при приходе стуктуры... Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: Zor от 07 октября 2008, 16:52:30 нда, явное недопонимание работы сети :)
объясняю 1. мы подключились кабелем к железу (прибор) 2. прибор просек что к нему подключились (или что его включили) и пытается подключиться к серверу снаружи 3. (и, если ваша программа работает) это ему удается 4. (после этого) на стророне сервера возникает OnConnect + handshake с железом, принимаем и отправляем назад 8 байт структуры, соединение сохраняется 5. затем на стороне сервера вызываться OnExecute 6. в ней мы ждем прихода строки от железа и обрабатываем ее, соединение сохраняется 7. см п.5 это для случая, когда железо подключается 1 раз и после этого держит соединение. я надеюсь, у вас так? (тут начинаем лихорадочно читать документацию...) иначе надо флажками регулировать, кого куда. картинка из мануала. для более ясного, так сказать. цепочка событий OnConnect/OnExecute/OnDisconnect возникает всегда при подключени клиента. Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: Лена от 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->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. Может что подскажете? ;) Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: Zor от 07 октября 2008, 21:11:00 у меня уже дежа вю :)
повторяю: делать связь "назад" не надо! IOhandler - это уже открытый канал в ОБЕ стороны, вы УЖЕ подключены к прибору! все ваши "Connect/Disconnect" - стираете нафиг. // разумеется вы получаете тайм аут - с той стороны клиент стоит, а не сервер, некуда подключаться. OnExecute после OnConnect придет в любом случае - это стандартный режим работы. (ну если в OnConnect ничего критического не произойдет) Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: Лена от 08 октября 2008, 12:52:22 >у меня уже дежа вю
А у меня прединфаркт от этого прибора. :D Последовательность действий: Включаю прибор. Программой идущей в комплекте к прибору задаю ему слать координаты каждые 10 секунд. По индекатору вижу, что все нормально прибор начинает слать координаты. Выключаю программу идущую в комплекте с прибором. Запускаю свою программу. Теперь код такой: Код void __fastcall TFormListenPort::IdTCPServer1Connect(TIdContext *AContext)В точке останова вижу что событие происходит и приходит стуктура. Далее сразу происходит событие: Код void __fastcall TFormListenPort::IdTCPServer1Execute(TIdContext *AContext) В точке останова вижу, что пришла таже стуктура. Только 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. Вот поэтому думала что надо ответить прибору... в любом случае как начать получать координаты? Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: Лена от 08 октября 2008, 14:12:17 Вот, что у меня записывается в файл при длительной работе мой программы:
ъш ‚`3<ъш ‚`3<ъш ‚`3<ъш ‚`3<ъш ‚`3<ъш ‚`3<ъш ‚`3<ъш ‚`3<ъш ъш это заголовок стуктуры... Может строка: AContext->Connection->IOHandler->ReadBytes(IDunit, sizeof(SyncStruct), false); не верно устанавливает канал связи? Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: Zor от 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); // кидаем назад прибору } Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: Лена от 08 октября 2008, 15:31:23 Cейчас попробую. :)
А почему лучше TIdBytes Buffer; а не TByteDynArray Buffer; Это существенно? Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: Zor от 08 октября 2008, 16:06:38 это как в документации
Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: Лена от 08 октября 2008, 16:26:22 РАБОТАЕТ! ;D
Причем оба варианта и TIdBytes и TByteDynArray... Вот так, буржуинская адская машинка стала слать свои координаты: :D Код void __fastcall TFormListenPort::IdTCPServer1Connect(TIdContext *AContext) Тестовое чтение в файл: Код void __fastcall TFormListenPort::IdTCPServer1Execute(TIdContext *AContext) Zor, большое спасибо! :-* :-* :-* Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: Лена от 08 октября 2008, 16:45:36 Zor, еще вопросик:
В книге Архангельского сказано, что после приема данных в IdTCPServer1Execute надо всегда писать: __finally { AContext->Connection->Disconnect(); } В моем случае это не приемлемо? Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: Zor от 08 октября 2008, 17:21:47 Нет, конечно.
Книгу эту не читал, но это скорее пример протокола типа "коннект - одна команда-один ответ - дисконнект" Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: Лена от 08 октября 2008, 17:35:14 Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: Лена от 09 октября 2008, 11:52:04 Zor, как вы думаете, мой код и INDY 10 справяться с задачей если, например, приборов будет штук 50 и каждый будет слать сигнал, например, каждые 10 секунд?
Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: Zor от 09 октября 2008, 15:34:32 80 байт строка x 50 штук / 10 с = 400 байт/с. 400 байт для современных машин... не, не справится :-X шутк.
а вот код ведения лога я бы переписал - там буквально в 5 строк можно уложится Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: Лена от 09 октября 2008, 16:04:15 а вот код ведения лога я бы переписал - там буквально в 5 строк можно уложится А как бы выглядел ваш вариант? ::) Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: oxotnik от 09 октября 2008, 16:13:00 Код TFileStream *fsLogFile; Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: Zor от 09 октября 2008, 16:30:25 Очень похоже :)
// Seek можно выкинуть, открыв в режиме Append. НО ведение логов должно быть потокобезопасным, если железок > 1. А это значит + CriticalSection к коду Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: oxotnik от 09 октября 2008, 16:42:58 Очень похоже :) а кто мешает все это в очередь выстраивать, и писать в соответствии с очерёдностью?// Seek можно выкинуть, открыв в режиме Append. НО ведение логов должно быть потокобезопасным, если железок > 1. А это значит + CriticalSection к коду Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: Лена от 09 октября 2008, 17:29:11 а кто мешает все это в очередь выстраивать, и писать в соответствии с очерёдностью? А это как? А зачем CriticalSection? Ведь ИНДИ для каждого соединения использует новый поток. Почему могут быть конфилкты? Что разные потоки не могут писать в один текстовый файл одновременно? Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: oxotnik от 09 октября 2008, 17:51:16 а кто мешает все это в очередь выстраивать, и писать в соответствии с очерёдностью? А это как? А зачем CriticalSection? Ведь ИНДИ для каждого соединения использует новый поток. Почему могут быть конфилкты? Что разные потоки не могут писать в один текстовый файл одновременно? очередность... это примерно так: Код: Главный поток чтения данных() { // читаем данные // опа... сбой какой то // смотрим что у нас делает поток записи лога GetExitCodeProcess // если exitCode == STILL_ACTIVE ждем пока не освободится (WaitForSingleObject(...)) // если свободен, то вызываем поток записи лога } либо можно ошибку помещать в некий контейнер (стэк) а в потоке записи лога брать из этого контейнера самую первую (последнюю) запись и выводить её в файл Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: oxotnik от 09 октября 2008, 18:01:37 вот пример - печать документов в строгом соответствии со списком:
Код DWORD hStartPrnProc; Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: Лена от 09 октября 2008, 18:35:21 Cпасибо, попробую реализовать.
Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: Лена от 09 октября 2008, 19:42:32 Поставила прибору слать данные каждую минуту, а не 10 секунд.
Обнаружился глюк, не понятного происхождения. Может он и раньше бы когда интервал был 10 секунд. Я не заметила. Все работало, данные принималась. Потом заметила, что данные не приходят. Посмотрела в точке останова, что IdTCPServer1Execute стала приходит структура, вместо координат. Помог перезапуск прибора. Потом опять это началось. Пробовала таким кодом в IdTCPServer1Execute обработать эту ситуацию: Код AnsiString S = AContext->Connection->IOHandler->ReadLn(); После этого один раз приходят координаты, а потом снова стуктура и так по кругу. Может надо подкурутить, в смысле увеличить в инспекторе объектов свойство TerminateWaitTime которое сейчас равно 5000 у IdTCPServer? Если да, то сколько туда влупить чтобы с запасом? ;) P.S. 5000 это 5 секунд. Поставила 70000 - не помогло. ??? P.S. Такое впечателение что при включении моей программы прибор грузит в нее все что в нем накопилось в кеше, а когда надо прислать свежую строку, он ее присылает, а потом в IdTCPServer1Execute приходит стуктура... Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: Zor от 09 октября 2008, 23:47:07 Ну тут без прибора в наличии не помочь, звиняйте.
охотник тяж. детство, VisualBasic... :D в чем смысл подобной многозадачности? все равно строго друг за другом идут. простой цикл и все. крит секция проще и надежнее получается. Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: oxotnik от 10 октября 2008, 09:38:50 в чем смысл подобной многозадачности? все равно строго друг за другом идут. простой цикл и все. ну не скажи... что касается печати, то быстрей в очередь печати помещается тот файл который меньше, следовательно очередь нарушается (если пускать отдельный процесс на каждый файл)крит секция проще и надежнее получается. я тоже думал что все будет печататься так как есть, пока меня носом не ткнули, пришлось вставлять вот такой "костыль" - уж сильно не ругай... децтво нормальное было, времени подумать мало было - писал не думая а что касается лога, то по моему разумению там тоже очередь важна, ведь не хорошо получится если сначала запишем данные со временем 12:00:00 а потом с 11:59:00... за такой лог по головке не погладят ЗЫ: вижуал бейсик не знаю вообще, и на бейсике писал одну программу всего в жизни где то лет 20 назад ;) Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: Лена от 13 октября 2008, 18:06:54 Подскажите, почему при включенном Code Guard после кода я получаю ошибку:
Код void __fastcall TFormListenPort::IdTCPServer1Connect(TIdContext *AContext) Error 00090. 0x310000 (Thread 0x0CF4): Bad parameter: A bad memory block (0xF4E508) has been passed to the function. free(0x00F4E508) | d:\program files\codegear\rad studio\5.0\include\vcl\sysdyn.h line 383: | int* p_i = (int*)Data; | p_i -= 2; |> free(p_i); | Data = 0; | } Call Tree: 0x004077C9(=ProjectListenPort.exe:0x01:0067C9) d:\program files\codegear\rad studio\5.0\include\vcl\sysdyn.h#383 0x00407740(=ProjectListenPort.exe:0x01:006740) d:\program files\codegear\rad studio\5.0\include\vcl\sysdyn.h#320 0x004076AA(=ProjectListenPort.exe:0x01:0066AA) d:\program files\codegear\rad studio\5.0\include\vcl\sysdyn.h#159 0x00407484(=ProjectListenPort.exe:0x01:006484) UnitListenPort.cpp#456 0x00484CA9(=ProjectListenPort.exe:0x01:083CA9) 0x00419573(=ProjectListenPort.exe:0x01:018573) ------------------------------------------ Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: Zor от 13 октября 2008, 23:14:24 в коде dynamic_arrays ошибок не видно. значит, глючит CG
Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: Лена от 14 октября 2008, 11:33:02 Cпасибо, Zor! 8)
Я спросила тех.поддрежку производителя, почему прибор периодически отсоединяется и пытается снова соединиться и присылает стуктуру. Вот что мне ответили: For connecting to the unit, you should implement the software to reply the SAME SYNC MESSAGE received to the unit EACH and EVERY TIME. Zor, подскажите, пожалуйста, с учетом этой рекомендации, как должен выглядеть мой теперешний код? Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: Zor от 14 октября 2008, 13:23:56 // какой странный английский (ну, на мой взгляд...) индусы какие нибудь пишут или китайцы?
то есть, в художественном переводе: "для работы с устройством программа должна отправлять sync пакет каждый раз" Код: TIdBytes SyncPacket; // глобальный void __fastcall TFormListenPort::IdTCPServer1Connect (TIdContext *AContext) { AContext->Connection->IOHandler->ReadBytes(SyncPacket, sizeof(SyncStruct), false); // читаем структуру if ((Buffer[0] != 0xFA) || (Buffer[1] != 0xF8)) return; // или Disconnect(); , ведь продолжать незачем } void __fastcall TFormListenPort::IdTCPServer1Execute (TIdContext *AContext) { try { AContext->Connection->IOHandler->Write(SyncPacket); // напоминаем железке, что о ней не забыли AnsiString S = AContext->Connection->IOHandler->ReadLn(); // ловим ответ // тут делаем еще что-то. } catch (...) {} } Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: Лена от 14 октября 2008, 14:01:58 >индусы какие нибудь пишут или китайцы?
Тайванцы. :-X Спасибо за код! Сейчас попробую. Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: Лена от 14 октября 2008, 14:18:38 Zor, надо ли также вставлять проверку и в IdTCPServer1Execute перед записью стуктуры:
Код void __fastcall TFormListenPort::IdTCPServer1Execute(TIdContext *AContext) Не стоит ли помень метод ReadLn на метод ReadLnWait? Все таки, что правильнее в IdTCPServer1Connect return или Disconnect ? Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: Zor от 14 октября 2008, 14:44:42 по умолчанию, ReadLn = ReadLnWait, то есть тоже ждет пока не считает всю строку.
return или Disconnect - если пришли явно неверные данные или битый пакет, зачем продолжать? делайте AContext->Connection->Disconnect(); и все. ну а проверять или нет - зависит от наличия Disconnect выше :) Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: Лена от 14 октября 2008, 14:56:24 >ReadLn = ReadLnWait
ReadLn вроде может считать пустую строку, а ReadLnWait вроде отбрасывает пустые строки и работает если пришла не пустая строка? Значит окончательно будет так? Код TIdBytes SyncPacket; Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: Лена от 15 октября 2008, 16:07:33 У нас TIdBytes SyncPacket; глобальная...
Мы все время пытаемся передать стуктуру которая была один раз проинициализирована, но у каждого нового сигнала хоть и постоянный заголовок ((SyncPacket[0] == 0xFA) || (SyncPacket[1] == 0xF8)), но все время меняется SyncID! typedef struct { WORD SyncHeader; WORD SyncID; DWORD UnitID; } SyncStruct; SyncID is a message sequence number 1, 2, 3 и т.д. Cледовательно мы отсылаем не ту стуктуру, а старую? Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: Zor от 15 октября 2008, 18:07:49 // снова онлайн :)
ну да, старую. вы вроде никогда и не говорили что пакет надо обновлять? тогда получается (OnExecute): AContext->Connection->IOHandler->Write(SyncPacket); AnsiString S = AContext->Connection->IOHandler->ReadLn(); // тут парсим строку и обновляем Id в синкпакете. дополнительный вопрос - что будет когда оно переполнится? +++ так у вас оказывается есть описание протокола, вот с этого и надо было начинать. положите на depositfiles.com, ссылку - сюда. а то окажется что все работает соооооооовсем не так как предполагается... Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: Лена от 15 октября 2008, 18:27:01 >тогда получается (OnExecute):
Что не работает. Все время получаю стуктуру... Опытным путем и мучениями родидся код, который похоже работает... OnConnect оказался нужным. Без него не работало... Код void __fastcall TFormListenPort::IdTCPServer1Connect(TIdContext *AContext) Не знаю уже радоваться мне или нет. ;) Предварительные тесты показывают, что все вроде нормально работает. Ждемс глюка. :-X Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: Лена от 15 октября 2008, 18:28:35 >так у вас оказывается есть описание протокола, вот с этого и надо было начинать. положите на depositfiles.com
Сейчас выложу. Но там только список команд, а все что касается написания собственной программы я скопировала в первый пост этого топика... Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: Лена от 15 октября 2008, 19:42:11 Похоже обнаружен недочет.
Если программа считывающие данные выключена, то в приборе накапливаются строки с координатами и при включении прибора он высылает их сразу все после потверждения. На рисунке видно, что пришли строки разделенные \r\n Как организовать цикл разбивки чтобы записать каждую строку в базу данных? Без этого цикла я теряю данные которые накопил прибор. После приема всей порции записей которые накопились в приборе, прибор уже начнет высылать текущие координаты по одной строке. Без цикла было бы удобно просто читать строки: AnsiString S = AContext->Connection->IOHandler->ReadLn(); но в этом случае мы не сможем отправить прибору подтверждение, т.к. реально читаем строкой: AContext->Connection->IOHandler->ReadBytes(SyncPacket, -1, false); и затем отправляем прибору SyncPacket. Как должен выглядеть цикл приема скопившихся строк? Может можно в какой-то удобный контейнер сложить накопившиеся в приборе строки и потом из этого контейнера складывать строки в базу данных? P.S. База данных также подтверждает, что я теряю без цикла данные которые накопил прибор пока программа была выключена. Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: Лена от 15 октября 2008, 21:04:41 А если так:
Код SyncPacket.set_length(SyncPacket.Length+1); На сколько быстр этот код? А если данные накопяться дней за 5-10? Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: oxotnik от 16 октября 2008, 10:01:48 \r\n это символ переноса на другую строку, грузишь это все в TStringList и они там сами по строкам ложатся
Код TStringList *lst = new TStringList();а в базу отправлять (если через INSERT) лучше не по одной стоке, а заполнять T...Query::SQL множеством строк (штук по 50-100) и единым пакетом засылать на сервер. Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: Лена от 16 октября 2008, 10:41:47 Да, я вставляю через INSERT, а как заполнять ADOQuery множеством строк?
Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: oxotnik от 16 октября 2008, 10:49:41 Код for (....) Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: Лена от 16 октября 2008, 12:23:21 Спасибо!
Вот так правильнее? Код ADOQuery1->SQL->Clear(); Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: Лена от 16 октября 2008, 12:31:57 Если цикл не произойдет то не вызовет ли ошибку строка:
ADOQuery->ExecSQL(); ведь запрос пустой? Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: oxotnik от 16 октября 2008, 14:04:42 Код ADOQuery1->SQL->Clear(); Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: Лена от 16 октября 2008, 14:50:25 Большое спасибо!
Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: Лена от 16 октября 2008, 15:51:19 Пакетная отправка в базу не работает у меня :(
Вижу, что в цикле в точке останова, к примеру, цикл должен выполниться четыре раза. Однако счетчик (ADOQuery->SQL->Count > 0) показывает всегда единицу и в результате отправляется не 4 записи, а одна. В теле цикла у меня так: AnsiString SQLvBazy = "INSERT INTO тра та та ADOQuery1->SQL->Add(SQLvBazy) Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: oxotnik от 16 октября 2008, 16:04:35 а TStringList::Count сколько показывает?
Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: Лена от 16 октября 2008, 16:23:23 а TStringList::Count сколько показывает? 4 Такое впечатление что ADOQuery->SQL->Add перезатирает предыдущий запрос. Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: oxotnik от 16 октября 2008, 16:37:30 так попробуй:
в цикле ADOQuery->SQL->Text += "здесь текст сформированного запроса" + " "; Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: Лена от 17 октября 2008, 14:32:15 Полностью поменялась идеология приема сигнала в порт и их считывания. Теперь цикл не нужен так как удалось читать по строчно буфер и не надо также применять OnConnect:
Код void __fastcall TFormListenPort::IdTCPServer1Execute(TIdContext *AContext)Похоже приборчик окончательно побежден т.к. вроде все работает. ;) Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: Zor от 17 октября 2008, 19:51:18 праздравля! :)
Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: Лена от 20 октября 2008, 11:53:34 праздравля! :) Вам спасибо! :-* Без совместных усилий эту технику победить было не возможно. ;) Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: Лена от 20 октября 2008, 15:33:31 Блин, все действительно работает по полной программе! Я в шоке! Адская тайваньская машинка побеждена!!! :-X
Zory малиновые штаны, мне желтые, за победу над планетой Флюк! :D Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: Лена от 20 октября 2008, 16:33:14 Забыла добавить, пользователю AVK отдельное спасибо! Стукрута базы данных, ее логика и связи полностью подсказаны AVK и это то, что нужно! Тайванский приборчик вписался в базу как родной!!! :)
Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: Zor от 20 октября 2008, 21:45:30 желтые штаны уходят в китай :)
Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: qosimmax от 18 августа 2009, 10:06:14 Помогите разобраться со следующей проблемой:
Есть прибор IntelliTrac X8 , который шлет на сервер в определенный порт сигнал по GPRS /TCP/IP. К этому прибору идет специальная программа. При запуске этой программы на сервере она начинает принимать сигналы, идущие от прибора. Я написал программу, которую тоже расположила на сервере. Мое программа использует тот же порт для прослушивания. Используется INDY IdTCPServer (DELPHI 7). Выключаю программу, которая идет в поставке к прибору, и запускаю свою программу для прослушивания порта. Если я посылаю самостоятельно пакет в этот порт, моя программа успешно его принимает, однако сигналы от прибора вот таком виде ú ø " ‡ ` 3 < ú ø # ‡ ` 3 < что можно сделать или я не правильно обрабатываю помогите пожалуйста Заранее спасибо Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: oxotnik от 18 августа 2009, 10:11:31 Помогите разобраться со следующей проблемой: очевидно, что надо узнать протокол обмена данными, иначе гадать можно до бесконечностиЕсть прибор IntelliTrac X8 , который шлет на сервер в определенный порт сигнал по GPRS /TCP/IP. К этому прибору идет специальная программа. При запуске этой программы на сервере она начинает принимать сигналы, идущие от прибора. Я написал программу, которую тоже расположила на сервере. Мое программа использует тот же порт для прослушивания. Используется INDY IdTCPServer (DELPHI 7). Выключаю программу, которая идет в поставке к прибору, и запускаю свою программу для прослушивания порта. Если я посылаю самостоятельно пакет в этот порт, моя программа успешно его принимает, однако сигналы от прибора вот таком виде ú ø " ‡ ` 3 < ú ø # ‡ ` 3 < что можно сделать или я не правильно обрабатываю помогите пожалуйста Заранее спасибо Название: Re: IdTCPServer синхронизировать с клиентом Отправлено: qosimmax от 19 сентября 2009, 08:34:16 У меня такой код.
#pragma pack(push, 1) struct SyncStruct { WORD SyncHeader; WORD SyncID; DWORD UnitID; }; #pragma pack(pop) 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); } 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; } 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; } } } Почему не роботает. От IntelliTrac X8 немогу получат координаты. |