LINUX.ORG.RU

[c + php] Передача данных в web-интерфейс


0

1

Всем доброго времени суток.

Возник такой занятный вопрос.

Есть программка на С, которая взаимодейтсвует с некоторым устройством (не суть важно, каким) по COM-порту. Получив от этого устройства сообщение о, например, нажатии кнопки, эта программа должна каким-то образом передать эти данные web-интрефейсу (apache развернут на той же машине, так что общаются они по localhost).

Сейчас проблему решил таким образом: на С написал socket-сервер, который принимает определенную команду от web-интерфейса и, по необходимости, отвечает ему о том, что кнопка нажата. В зависимости от ответа, в web-интерфейсе что-то изменяется (появляется надпись «Нажата кнопка»). Соответственно, для того, чтобы иметь более-менее realtime, мне приходится опрашивать С-шную программу каждую секунду.

С такой задачей столкнулся впервые и смог придумать только такое решение. Надеюсь, что подскажете что-нибудь более рациональное.

Заранее благодарю.

Чтобы быстро передать данные в браузер есть http://cometd.org/. Как альтернативу сокету с командами можно сделать статусный файл, который в определённом формате (JSON?) содержит нужную информацию по устройству и оперативно обновляется программой на С. Таким образом можно следить за изменением файла (inotify, ...) и слать инфу в браузер. Осталось совместить Cometd и оповещения о изменение файла.

roy ★★★★★ ()

имхо, все правильно сделал.

Инициировать опрос можно не по таймеру, а по какому-либо событию веб-интерфейса (в простейшем случае, если нажатие кнопки происходит только через веб-интерфейс)

Если кнопка нажимается на внешнем устройстве, можно управлять состоянием (вебинтерфейса), отслеживая код ответа http сервера (если ответил 200 - тут же обновить состояние, если отвалился по тайм-ауту — повторить запрос) (погугли, как пишут хтмл-чятики)

anonymous ()
Ответ на: комментарий от anonymous

Чтобы быстро передать данные в браузер есть http://cometd.org/.

Спасибо, ознакомлюсь.

Если кнопка нажимается на внешнем устройстве, можно управлять состоянием (вебинтерфейса), отслеживая код ответа http сервера

Проблема в том, что по нажатию кнопки на внешнем устройстве никаких запросов на сервер не идет. Грубо говоря, в программу на С приходит событие, только и всего. Но все-равно спасибо за идею.

solovey ★★ ()
Ответ на: комментарий от solovey

Проблема в том, что по нажатию кнопки на внешнем устройстве никаких запросов на сервер не идет

запрос шлет веб-форма и ждет ответ от сервера (здесь это апач+контроллер устройства). Сервер пытается ответить в течении некотого интервала (скажем, 30секунд), по истечении которого он сообщит об истечении периода ожидания, либо, если в течении этого времени у него появится содержательный ответ, сразу же отправит его в веб-форму.

веб-форма получает ответ сервера, анализирует его (и соответственно реагирует) и повторяет запрос.

взаимодействие апача и контроллера устройства не рассматриваю.

anonymous ()
Ответ на: комментарий от anonymous

А, понял. То есть, фактически, преимущество этого метода в том, что запрос будет отправляться не каждую секунду, а, допустим, каждые 30 секунд. Так?

Правда вопрос взаимодействия апача с Си так и остается открытым. Ведь все-равно придется постоянно мониторить программу на предмет появления событий от устройства. Но это уже отдельный вопрос...

solovey ★★ ()
Ответ на: комментарий от solovey

запрос будет отправляться не каждую секунду, а, допустим, каждые 30 секунд. Так?

Не совсем. Если у апача содержательный ответ будет, скажем, на 5 секунде, то он его тут же (не дожидаясь истечения оставшихся 25с) и отправит, и получит новый запрос. Ну а нет- будет ждать до упора, да.

Правда вопрос взаимодействия апача с Си так и остается открытым

Нуу, дядя, тут сам смотри, вариантов уж слишком дофига, от тривиального CGI до «написать собственный веб-сервер». С поворотами в «спец.модуль апача» и «контроллер на похапэ это глобально и надежно11»

anonymous ()
Ответ на: комментарий от anonymous

Не совсем. Если у апача содержательный ответ будет, скажем, на 5 секунде, то он его тут же (не дожидаясь истечения оставшихся 25с) и отправит, и получит новый запрос. Ну а нет- будет ждать до упора, да.

Ну да, это я и имел в виду.

По поводу вариантов взаимодействия - что-нибудь придумаю...

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

solovey ★★ ()
Ответ на: комментарий от solovey

По поводу вариантов взаимодействия

Я бы не стал смешивать контроллер устройства с веб-интефейсом. Вполне нормальный вариант, имхо, это писать данные в файл (или именованый пайп), а оттуда читать их уже каким-нибудь скриптом, да хоть тем же пхп.

anonymous ()
Ответ на: комментарий от anonymous

Дело в том, что socket-сервер там все-равно есть, потому что другого варианта связать php и Си я в свое время не придумал.

Конкретно для данной задачи думал использовать обычные файлы, но не срослось. Хотя, возможно, позже вернусь к этой идее.

solovey ★★ ()
Ответ на: комментарий от solovey

Не кроссбраузерно, имхо

Все современные поддерживают. Что еще нужно?

Полно народу, которые еще на IE8 сидят

Для таких - ссылочку, если не работают вебсокеты, вида «скачайте и установите любой из современных браузеров», все-таки, IE - это обычная качалка браузеров и ни что более.

А некоторые и с IE6 до сих пор

Им и функционал ваш не нужен

Eddy_Em ☆☆☆☆☆ ()
Ответ на: комментарий от solovey

И еще плюс вебсокетов в том, что всякие пыхпыхи нафиг не нужны будут.

Eddy_Em ☆☆☆☆☆ ()
Ответ на: комментарий от solovey

Дело в том, что socket-сервер там все-равно есть

ну, значит и ожидание-ответ на него возложить можно, минуя апач. А запрос на этот сокет слать ajax-ом, через XMLHttpRequest().

anonymous ()
Ответ на: комментарий от anonymous

В принципе, почти так... Только запрос шлю через JsHttpRequest. Но проблема в том, что он асинхронный. Соответственно, с учетом того, что запросы я шлю по таймеру, у меня запросы все-равно отправляются каждую секунду, несмотря на ожидание на socket-сервере.

Или я не понимаю Вашей идеи?

P.S.: Да, флеш меня тоже смутил...

solovey ★★ ()
Ответ на: комментарий от solovey

Или я не понимаю Вашей идеи?

Так тут либо по таймеру, либо по ответу, одн из двух, иначе каша получится.

http://xmlhttprequest.ru/

var xmlhttp = getXmlHttp()
xmlhttp.open('GET', '/xhr/test.html', false);
xmlhttp.send(null);
if(xmlhttp.status == 200) {
  alert(xmlhttp.responseText);
}

При синхронном запросе браузер «подвисает» и ждет на строчке 3, пока сервер не ответит на запрос. Когда ответ получен - выполняется строка 4, код ответа сравнивается с 200 (ОК), и при помощи alert печатается текст ответа сервера.

Естественно, вместо alert надо вызывать свою функцию. И проверять не только 200 код ответа, но и отвал по таймауту (код не помню). И запрос слать на свой сокет.

anonymous ()
Ответ на: комментарий от solovey

он асинхронный

и да, это не проблема ;)

anonymous ()
Ответ на: комментарий от anonymous

Так тут либо по таймеру, либо по ответу, одн из двух, иначе каша получится.

Под таймером я имею в виду:

<body onload="window.tmr = setInterval (myFunc, 1000)" onunload="clearInterval (window.tmr)">
Если убрать асинхронный режим, то будет отсылаться корректно? Надо проверить...

А вообще - не радует то, что браузер будет подвисать... Ведь в это время мне может потребоваться выполнять еще какие-то действия на странице (пример про фразу «Нажата кнопка» не совсем отражает задачу).

solovey ★★ ()
Ответ на: комментарий от solovey

Если убрать асинхронный режим, то будет отсылаться корректно? Надо проверить...

Если уж делать такую модель, то логичнее убрать таймер. Асинхронный режим (по ссылке описание есть ниже) оставить, все должно работать.

//ты бы сам таймаут взял, инфу переварить ;)

anonymous ()
Ответ на: комментарий от anonymous

Если уж делать такую модель, то логичнее убрать таймер.

А как тогда вызывать функцию регулярно, а не однократно???

Да, похоже тайм-аут нужен... Вообще, как говорится, работает - не трогай) Но уж очень не оптимальным мне кажется мой подход.

solovey ★★ ()
Ответ на: комментарий от solovey

Будет вызываться каждый раз, как приходит какой-либо ответ от сервера. Обработали его - и по новой

anonymous ()
Ответ на: комментарий от solovey

Js-прототип и флеш предоставляют слой совместимости. В современных браузерах этот код вообще не будет использоваться:

 if (window.WEB_SOCKET_FORCE_FLASH) {
    // Keeps going.
  } else if (window.WebSocket) {
    return;
  } else if (window.MozWebSocket) {
    // Firefox.
    window.WebSocket = MozWebSocket;
    return;
  }

gatsu ()
Ответ на: комментарий от anonymous

Практика показывает, что не будет...

Насколько я понимаю, там же принцип такой - без перезагрузки страницы отправляем запрос на сервер, а дальше в асинхронном режиме обрабатываем ответ от него.

Соответственно, если ничего не пошлем, то и обрабатывать нечего... Значит надо вызывать функцию.

Или мы с Вами опять говорим о разных вещах...

P.S.: Я сейчас все действия описываю для JsHttpRequest, но суть от этого сильно не меняется, потому что она использует, в частности, XmlHttpRequest...

solovey ★★ ()
Ответ на: комментарий от solovey

Практика показывает, что не будет..

Что же этому помешает?

без перезагрузки страницы отправляем запрос на сервер, а дальше в асинхронном режиме обрабатываем ответ от него.

Да. То есть проверяем код, если он=200, то что-то там делаем со страницей. После чего отправляем запрос. Снова. По-любому.

Соответственно, если ничего не пошлем, то и обрабатывать нечего... Значит надо вызывать функцию.

Не вижу проблемы. Или я что-то не понимаю?

anonymous ()
Ответ на: комментарий от anonymous

Все, понял =) Спасибо!!!

Какой-то я очень долгий нынче.

Обязательно попробую реализовать этот вариант.

solovey ★★ ()
Ответ на: комментарий от solovey

Перефразируя пример из http://xmlhttprequest.ru/ получаем что-то типа:

var xmlhttp = getXmlHttp()
xmlhttp.open('GET', '/xhr/test.html', true);
xmlhttp.onreadystatechange = function() {
  if (xmlhttp.readyState == 4) {
    my_handler(xmlhttp.status); // обрабатываем
    xmlhttp.send(null); // повторяем запрос
 //    if(xmlhttp.status == 200) {
 //      alert(xmlhttp.responseText);
 //        }
  }
};
xmlhttp.send(null);

anonymous ()
Ответ на: комментарий от anonymous

Да, еще раз спасибо!!!

xmlhttp.send(null); // повторяем запрос

Вот это мне в голову никак и не могло прийти. Неправильно мыслил, видимо.

solovey ★★ ()
Ответ на: комментарий от anonymous

Наконец-то проверил...

В принципе, работает, только вызывать send прямо из if у меня не получилось. Скорее всего, JsHttpRequest простотак не умеет. Пришлось сделать грязный хак:

if (req.readyState == 4) {
	...
	document.getElementById('f').submit ();
       ...
}
......
<form id="f" onsubmit="myFunc ()">
</form>

Так работает =)

solovey ★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.