Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.142.255.103] |
|
Сообщ.
#1
,
|
|
|
Мир вам. Подскажите, может кто сталкивался.
На форму кидаю TidSNTP и таймер. Устанавливаю свойства: idsntp.Host := '192.168.0.73'; idsntp.Port := 1234; idsntp.ReciveTimeout := 500; //1000; Таймер срабатывает с периодом в 10 секунд. В обработчике таймера происходит следующее: if idsntp.datetime <> 0 then begin //caption := inttostr(idsntp.sendtime) + ' '+inttostr(idsntp.rectime); statuslabel.Caption := 'Ok'; rounddelaylabel.Caption := inttostr(round (idsntp.RoundTripDelay * 24 * 3600 * 1000)) + ' ms'; adjustingtimelabel.Caption := inttostr(round (idsntp.AdjustmentTime * 24 * 3600 * 1000)) + ' ms'; Так вот, как правило, idsntp.datetime отрабатывает корректно и тогда значения RoundTripDelay лежат в интервале 4..300 мс. Но иногда/периодически возникает странная ситуация: idsntp.datetime отрабатывает вроде бы штатно, но RoundTripDelay составляет секунды, до 10 и более, и примерно на столько же увеличивается и AdjustmentTime. Обычно начинается с того, что первый при запуске программы вызов datetime отрабатывает с ошибкой(почему-то), а вслед за этим начинает возвращать некорректные значения RoundTripDelay и AdjustmentTime. Но такая ситуация иногда возникает и в процессе... И если datetime начинает выдавать неправильные значения, то так и продолжает. До перезапуска программы(как будто). Но иногда начинает работать как положено. Такой вот нестабильный глюк. Залез в компонент TidSNTPClient. Привожу часть метода datetime: Begin Result := 0.0; SetLength(LBuffer, SizeOf(TNTPGram)); FillBytes(LBuffer, SizeOf(TNTPGram), $00); LBuffer[0] := $1B; DateTimeToNTP(Now, LNTPDataGram.Xmit1, LNTPDataGram.Xmit2); CopyTIdUInt32(GStack.HostToNetwork(LNTPDataGram.Xmit1), LBuffer, 40); CopyTIdUInt32(GStack.HostToNetwork(LNTPDataGram.Xmit2), LBuffer, 44); //sendtime:=gettickcount; SendBuffer(LBuffer); //sendtime:=gettickcount-sendtime; //rectime:=gettickcount; ReceiveBuffer(LBuffer); //rectime:=gettickcount-rectime; // ... // corrected as per RFC 2030 errata FRoundTripDelay := (FDestinationTimestamp - FOriginateTimestamp) - (FTransmitTimestamp - FReceiveTimestamp); FLocalClockOffset := ((FReceiveTimestamp - FOriginateTimestamp) + (FTransmitTimestamp - FDestinationTimestamp)) / 2; Выяснил, что в случае правильной работы компонента, метод SendBuffer отрабатывает "мгновенно", а ReciveBuffer в течении 20..300 мс и фактически RoundTripDelay - это "время срабатывания" ReciveBuffer. Когда происходит глюк, вижу что ReciveBuffer начинает отрабатывать так же "мгновенно", как и SendBuffer. Ощущение, что где-то в приемном буфере остаётся мусор от предыдущего вызова ReciveBuffer и именно этот "хвост" ReciveBuffer читает. Но при этом возвращает ненулевое (и корректное) значение времени, то есть прочитанный пакет NTP проходит все проверки. Uлюк происходит где-то в недрах родительского класса. Что это и как от него избавиться. Я пока не пробовал создавать и уничтожать экземпляр TidSNTP в рантайме. Может быть это исправит ситуацию, но я хочу понять. Может, я что-то не так делаю. |
Сообщ.
#2
,
|
|
|
Тогда попробуйте в этот метод добавить дополнительный локальный буфер, в который скопируете значения исходные, а получение уже может сработать на сохраняемом глобальном LBuffer предварительно обнуленном.
И еще: А ничего, что длина у этих объектов разная? CopyTIdUInt32(GStack.HostToNetwork(LNTPDataGram.Xmit1), LBuffer, 40); CopyTIdUInt32(GStack.HostToNetwork(LNTPDataGram.Xmit2), LBuffer, 44); |
Сообщ.
#3
,
|
|
|
Это не размер, а индекс в буфере пакета по логике.
Не понял про локальный буфер. Попробую просто обнулить буфер перед вызовом ReciveBuffer. Хотя в случае глюка тогда я скорее всего буду получать ошибку datetime. Сейчас попробую. Добавлено Обнуление ничего не даёт. Глюк где-то в недрах родительских классов. Точнее, даёт, глюк стал появляться чаще. |
Сообщ.
#4
,
|
|
|
В локальных переменных объявите еще один SBuffer, обнулите его и используйте для отправки через SendBuffer. А для ReceiveBuffer оставьте этот LBuffer.
Добавлено У меня просто нету под рукой сейчас этого класса в Lazarus. Я бы сам проверил в чем дело. |
Сообщ.
#5
,
|
|
|
Кажется, он вылечился. Перед вызовом datetime устанавливаю IdSNTP.Active := true, а после сбрасываю. Таким образом, сокет инициализируется при каждом вызове datetime где-то там внутри. Так вроде работает. Тогда и создание TIdSNTP в рантайме будет иметь такой же эффект, по идее.
Увеличил таймаут по приему до 2000 мс, теперь и первый вызов отрабатывает как будто нормально. Будем посмотреть. Да, глюк пропал. А таймаут лучше увеличить секунд до 5. |