Страница 1 из 1

TCP сервер и ошибка

Добавлено: Вт май 26, 2015 16:34:42
Pooher
Всем привет! Волей случая, в общеобразовательных целях решил заняться написанием WEB сервиса для своей игрушки. Общаться хочу по TCP.
Поставил дэнвер, написал простой сервер из примера php.net, и столкнулся с первой проблемой - никак не запустить его, постоянно выкидывает ошибку:
unable to bind address [0]: Обычно разрешается только одно использование адреса сокета (протокол/сетевой адрес/порт)
Дело встало, моих скудных познаний катастрофически не хватает для того, чтобы понять в чём дело.
Подскажите, пожалуйста, в какую сторону хоть копать-то)

Код: Выделить всё

#!/usr/local/bin/php -q
<?php
error_reporting(E_ALL);

/* Позволить сценарию зависнуть вокруг ожидания подключений */
set_time_limit(0);

/* Включить неявный вывод, так что мы видим то, что мы получаем
 * когда это приходит . */
ob_implicit_flush();

$address = '127.0.0.1';
$port = 86;

if (($sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) < 0) {
    echo "socket_create() failed: reason: " . socket_strerror($sock) . "\n";
}

if (($ret = socket_bind($sock, $address, $port)) < 0) {
    echo "socket_bind() failed: reason: " . socket_strerror($ret) . "\n";
}

if (($ret = socket_listen($sock, 5)) < 0) {
    echo "socket_listen() failed: reason: " . socket_strerror($ret) . "\n";
}

do {
    if (($msgsock = socket_accept($sock)) < 0) {
        echo "socket_accept() failed: reason: " . socket_strerror($msgsock) . "\n";
        break;
    }
    /* Send instructions. */
    $msg = "\nWelcome to the PHP Test Server. \n" .
        "To quit, type 'quit'. To shut down the server type 'shutdown'.\n";
    socket_write($msgsock, $msg, strlen($msg));

    do {
        if (false === ($buf = socket_read($msgsock, 2048, PHP_NORMAL_READ))) {
            echo "socket_read() failed: reason: " . socket_strerror($ret) . "\n";
            break 2;
        }
        if (!$buf = trim($buf)) {
            continue;
        }
        if ($buf == 'quit') {
            break;
        }
        if ($buf == 'shutdown') {
            socket_close($msgsock);
            break 2;
        }
        $talkback = "PHP: You said '$buf'.\n";
        socket_write($msgsock, $talkback, strlen($talkback));
        echo "$buf\n";
    } while (true);
    socket_close($msgsock);
} while (true);

socket_close($sock);
?>
ЗЫ:Скрипт лежит в папке www. Запускаю в браузере localhost/script.php. Может не так надо? Просто я пока немного недопонимаю всей сути. Для меня это всё тёмный лес, в инете всё перерыл, инфы очень мало.

Re: TCP сервер и ошибка

Добавлено: Ср май 27, 2015 17:22:51
diafour
Эта ошибка означает, что на порту 86 уже слушает другой процесс, скорее всего ранее запущенный. Есть такой флаг у сокета: SO_REUSEADDR, его нужно выставить, чтобы после того, как один процесс умер, не закрыв порт, второй мог переоткрыть порт. Вот по ссылке первый пример: http://php.net/manual/en/function.socket-set-option.php

А что за игрушка и почему не использовать готовый сервер, тот же апач из денвера, скрипт будет проще?

P.S. под web-сервисом обычно понимают общение по протоколу HTTP с SOAP сообщениями - для игрушек это точно overkill.

Re: TCP сервер и ошибка

Добавлено: Чт май 28, 2015 04:28:51
kalobyte
сегодня для таких задач используют фреймворки и пхп не заточен для написание подобных штук, лучше node.js или питон
но на пхп есть фреймворк для вебсокетов
http://www.phpbuilder.com/articles/appl ... ckets.html
вот фреймворк http://socketo.me/

вебсокеты работают в реальном времени и открывается только одно соединение на одного клиента
в ютубе есть 3 урока от "специалист" и там делают чат на вебсокете с сервером на .нет и чистом яваскрипте

Re: TCP сервер и ошибка

Добавлено: Чт май 28, 2015 18:47:22
Pooher
Спасибо огромное за наводку! Буду копать SOAP.
ЗЫ: Давно не чувствовал себя нубом))

Re: TCP сервер и ошибка

Добавлено: Чт май 28, 2015 20:42:57
diafour
Не-не-не, не надо soap, поберегите мозг :) Расскажите, что хотите от серверной части и что за игрушка? Тут вот про web-сокеты разговор зашёл - это для браузерной игры подойдёт. Про такую игру речь? Браузерная многопользовательская?

Re: TCP сервер и ошибка

Добавлено: Чт май 28, 2015 21:56:10
Pooher
Не буду углубляться. Есть термостат, у него есть некоторое количество параметров. Мне надо отображать их на веб странице, и иметь возможность их поменять. Это задача-минимум. Доступ к сети обеспечивает sim900. Мне нужна концепция, и чтоб мозги по забору не развесить при освоении. PHP я выбрал, только по тому, что это первое, что попалось мне на глаза, и показалось не очень сложным. Ведь после многих лет асма на изучение си у меня ушло всего дня 2, но мк, скажу я вам, - это очень узко))

ЗЫ: SOAP - мозги закипают) Мне кажется для моей задачи всё должно быть гораздо проще (HTML форма<->сервер<-TCP->клиент)

Re: TCP сервер и ошибка

Добавлено: Чт май 28, 2015 23:06:14
diafour
Sim 900 в термостате? Если мк у термостата какой-нибудь арм, можно попробовать сервер на нём же и поднять, сделать интерфейс как у домашних роутеров.

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

Например, апач на адресе 10.10.0.3 и в корне лежит файл с параметрами p.txt. тогда термостат открывает соединение с 10.10.0.3 и передаёт такую строку:
GET /p.txt HTTP/1.0\n\n

В ответ получает содержимое файла, например, параметры через запятую:
10,45,,67
Т.е. 4 параметра, 3ий не установлен.

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

Re: TCP сервер и ошибка

Добавлено: Чт май 28, 2015 23:07:34
kalobyte
так ты бы сразу сказал, что тебе конкретно надо
для твоей задачи естественно сокеты на пхп это как по воробьям из пушки
твой сим должен открыть тцп сокет и соединиться по адресу на 80й порт
при этом послать в сокет такую строку

Код: Выделить всё

GET http://www.site.ru/temp.php?mode=get HTTP/1.0\r\n
Host: www.site.ru\r\n\r\n
далее пишеш тупо на пхп и сервер тебе не нужен, есть готовый апач, к которому пхп прикручен
твой пхп должен в ответ выдать температуру типа t=25
что-то типа echo $temp;
твой код в контроллере находит паттерн t= и понимает следущее число как температуру

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

как установить термостат?
посылаеш

Код: Выделить всё

GET http://www.site.ru/temp.php?mode=set&temp=30 HTTP/1.0\r\n
Host: www.site.ru\r\n\r\n
Host: http://www.site.ru надо передавать, чтобы апач понял, что обращаются к виртуальному хосту, коих на одном ип может быть целая куча

как распарсить запрос?
когда мы делаем GET http://www.s, то переменные будут храниться в глобальной переменной $_GET
например $mode = $_GET["mode"] в котором будет get или set
$temp = $_GET["temp"] и там будет число

естественно надо все это гавно проверить на правильность

для эмуляции работы твоего скрипта тебе надо плагин для браузера
http://restclient.net/

если ты хочеш делать все современно и круто, то есть готовые пхп фреймворки, которые за тебя делают 95% унылой работы, ты только должен написать логику работы твоего приложения
для твоей задачи нужен простой фреймворк
https://www.youtube.com/watch?v=0p6UDIiqWEg
почитай концепцию restful api, на хабре есть

что касается вебморды, то для современного стиля обычно используют яваскрипт фреймворк jquery
это обертка, которая упрощает написание всякого гимора
тебе нужно читать jquery ajax + валидатор на стороне клиента, чтобы клиент не ввел левое
это типа правила хорошего тона, но на сервере тоже нужна валидация, там фреймворк вроде делает базовую валидацию входящих данных

в ютубе есть видосы по жквери, за час-два разберешся
еще есть готовые модули визуальные для рисования вебинтерфейса
эта библиотека бесплатна, если твой проект некоммерческий
http://www.jqwidgets.com/jquery-widgets ... /index.htm
http://www.jqwidgets.com/jquery-widgets ... nality.htm

Re: TCP сервер и ошибка

Добавлено: Пт май 29, 2015 13:28:45
Pooher
Спасибо всем огромное! Буду пробовать разбираться. Очень надеюсь на вашу дальнейшую помощь.
Как говорится - первый раз всегда больно))

Re: TCP сервер и ошибка

Добавлено: Пт май 29, 2015 17:14:29
Мурик
Если сервер на своем компе, то можно написать его на чем угодно. Пример градусника с доступом через интернет.

Re: TCP сервер и ошибка

Добавлено: Вс май 31, 2015 11:45:34
Pooher
На данный момент я вижу выполнение моей задачи так:

sim900 делает запрос типа www.site.ru/postParameters.php?temp1=xx
скрипт обрабатывает переменную temp1 и пишет её значение в БД.

для доступа к изменению параметров термостата, со стороны sim900 я запускаю сервер, передаю его ip и порт http://www.site.ru/postParameters.php?i ... xx?port=xx

для онлайн отображения информации от термостата надо использовать ajax. Скрипт периодически считывает параметры из БД и выводит на страницу.

Поправьте, пожалуйста, если не так, или подскажите, может проще можно?

Re: TCP сервер и ошибка

Добавлено: Вс май 31, 2015 12:09:48
Мурик
А разве можно вот так взять и задать произвольный IP серверу?

Re: TCP сервер и ошибка

Добавлено: Вс май 31, 2015 20:10:39
Pooher
IP выдаст сотовый оператор.

Re: TCP сервер и ошибка

Добавлено: Вс май 31, 2015 23:22:34
Tolmi
Pooher писал(а): может проще можно?
Мне кажется, что городить отдельный сервер занятие в данном случае бессмысленное. Если sim900 на регулярной основе делает запросы web-серверу, то изменение параметров можно просто передавать внутри ответов на эти запросы. т.е. в ответ на запрос www.site.ru/postParameters.php?temp1=xx на веб сервере во-первых записывается температура в бд, а во-вторых проверяется не нужно ли передать sim900 команды на изменение параметров. А потом в ответе сервера кроме 200 OK обычным текстом передавать PARAM_XXX=Value,PARAM_YYY=Value и т.д. Разбор такого ответа будет тривиальным занятием даже на примитивных железках. И не нужно городить отдельный сервер.
Единственный параметр, который не сменить таким образом - это адрес самого www.site.ru, вернее, и это можно, если работают одновременно и старый, и новый сервер.

Re: TCP сервер и ошибка

Добавлено: Пн июн 01, 2015 08:02:20
Pooher
Смысл поднятия сервера на SIM900 в том, чтобы параметры изменялись "моментально", и сразу после отправки пользователь мог получить ответ, приняты ли данные, всё ли в порядке с железкой. Без сервера на SIM я решения не увидел.

Re: TCP сервер и ошибка

Добавлено: Пн июн 01, 2015 08:58:05
kalobyte
Pooher писал(а):Без сервера на SIM я решения не увидел.
вебсокеты http://en.wikipedia.org/wiki/WebSocket
твой сим будет клиентом, который открывает тцп сокет и шлет определенную пургу а ля хттп
только тебе тогда лучше взять питон, я вчера на гитхабе смотре серверы вебсокетов на питоне
заодно вебморду сделаеш так же, будет все в реальном времени

http://metroui.org.ua/ вот даже годный цсс фреймворк нашел, мне метро нравится
или http://webix.com/

Re: TCP сервер и ошибка

Добавлено: Пн июн 01, 2015 11:58:34
diafour
Pooher писал(а):На данный момент я вижу выполнение моей задачи так:

sim900 делает запрос типа http://www.site.ru/postParameters.php?temp1=xx
скрипт обрабатывает переменную temp1 и пишет её значение в БД.

для доступа к изменению параметров термостата, со стороны sim900 я запускаю сервер, передаю его ip и порт http://www.site.ru/postParameters.php?i ... xx?port=xx

для онлайн отображения информации от термостата надо использовать ajax. Скрипт периодически считывает параметры из БД и выводит на страницу.

Поправьте, пожалуйста, если не так, или подскажите, может проще можно?
Схема вполне нормальная, количество компонентов упростить можно только перенеся http сервер непосредственно в термостат, но это похоже не вариант?

Код: Выделить всё

Desktop/Mobile            site.ru               gprs-dynamic-ip
+----------+           +-------------+          +------------+
|          |           |             |          |            |
| Браузер  |   80      | HTTP сервер |   8000   | Термостат  |
|          |<--------->| php         |<-------->|            |
| JS       |           |             |          | SIM900     |
|          |           | DB          |          |            |
+----------+           +-------------+          +------------+
В этой схеме можно немного упростить взаимодействие, если учесть тот факт, что http сервер всегда знает ip адрес с которого пришёл запрос (реверсивные прокси и нат пока оставим за рамками). Поэтому, зафиксировав порт термостата, скажем 8000, достаточно будет периодически отправлять запрос с показаниями (http://www.site.ru/postParameters.php?temp1=xx), сервер же при разборе запроса будет сохранять в БД сразу и temp1 из query строки и ip адрес из свойств запроса.

В случае вебсокетов взаимодействие совсем упрощается, серверу не надо знать ip и порт для обратного коннекта. Между термостатом и http-сервером по сути открывается канал для передачи от термостата показаний, а от сервера - команд на изменение параметров. Если соединение рвётся, то термостат просто переподключается. Браузер тоже может открывать веб-сокет к тому же скрипту и обновлять показания по команде от сервера вместо периодического ajax опроса. В скрипте на сервере нужно будет получать показания из сокета термостата и отправлять их в сокеты браузеров и наоборот: получать команды на изменение параметров от браузеров и отправлять их в термостат. В промежутке можно сохранять данные в БД. Т.е. у скрипта будет два набора сокетов, между которыми он перекидывает сообщения. Надо будет только разделить сокеты на «термостатные» и «браузерные», но это тоже не слишком сложно, достаточно при коннекте передавать какой-нибудь простенький идентификатор типа "termo" и "browser". Данная схема масштабируется как по клиентам, так и по термостатам =) Ещё про вебсокеты можно сказать, что в случае их использования не будет тратиться время на установление tcp-соединений, т.е. от нажатия на кнопку в браузере до смены параметра в устройстве будет проходить минимально возможное время.

В дополнение к ссылкам на питон — исходники для ардуины: https://github.com/adik/webgsmcontrol


Не ясны возможности термостата. Какой там МК? А то может там линукс и всё на баш-скриптах можно сделать %)

P.S. kalobyte спасибо за webix, попробую где-нибудь, на вид шустрее, чем extjs.