Рубрика: Websockets

websocket сервер запуск скрипта на любом языке программирования

Здравствуйте давно ничего не писал 😉
не было много времени как всегда по свободе стараюсь что то написать сегодня речь пойдет о простом websocket сервере который готов работать с любым скриптом написаным на любом языке будь то php,perl,bash,c#,c,java,ruby,python или любом другом этот сервер имеет название websocketd скачать можно тут : http://websocketd.com/ есть для всех популярных ос даже для windows )) для запуска на FreeBSD или Linux готов из коробки )
посмотрим на то что он может дав команду websocketd —help :
Usage:

Export a single executable program a WebSocket server:
websocketd [options] COMMAND [command args]

Or, export an entire directory of executables as WebSocket endpoints:
websocketd [options] —dir=SOMEDIR

Options:

—port=PORT HTTP port to listen on.

—address=ADDRESS Address to bind to (multiple options allowed)
Use square brackets to specify IPv6 address.
Default: «» (all)

—sameorigin={true,false} Restrict (HTTP 403) protocol upgrades if the
Origin header does not match to requested HTTP
Host. Default: false.

—origin=host[:port][,host[:port]…]
Restrict (HTTP 403) protocol upgrades if the
Origin header does not match to one of the host
and port combinations listed. If the port is not
specified, any port number will match.
Default: «» (allow any origin)

—ssl Listen for HTTPS socket instead of HTTP.
—sslcert=FILE All three options must be used or all of
—sslkey=FILE them should be omitted.

—passenv VAR[,VAR…] Lists environment variables allowed to be
passed to executed scripts.

—reverselookup={true,false} Perform DNS reverse lookups on remote clients.
Default: true

—dir=DIR Allow all scripts in the local directory
to be accessed as WebSockets. If using this,
option, then the standard program and args
options should not be specified.

—staticdir=DIR Serve static files in this directory over HTTP.

—cgidir=DIR Serve CGI scripts in this directory over HTTP.

—header=»…» Set custom HTTP header to each answer. For
example: —header=»Server: someserver/0.0.1″

—header-ws=»….» Same as —header, just applies to only those
responses that indicate upgrade of TCP connection
to a WebSockets protocol.

—header-http=»….» Same as —header, just applies to only to plain
HTTP responses that do not indicate WebSockets
upgrade

—help Print help and exit.

—version Print version and exit.

—license Print license and exit.

—devconsole Enable interactive development console.
This enables you to access the websocketd
server with a web-browser and use a
user interface to quickly test WebSocket
endpoints. For example, to test an
endpoint at ws://[host]/foo, you can
visit http://[host]/foo in your browser.
This flag cannot be used in conjunction
with —staticdir or —cgidir.

—loglevel=LEVEL Log level to use (default access).
From most to least verbose:
debug, trace, access, info, error, fatal

Как видим опций не сильно много но очень много их и не надо 😉
для запуска достаточно ./websocketd —address 127.0.0.1 —port 9000 ./название вашего скрипа.расширение 😉

посмотрим на пример скрипта для php :
#!/usr/bin/env php

<?php

echo «Hello World !».»\n»;

?>

«\n» в конце обязательно должен быть.

пример html и javascript для просмотра работы:

<script>
var ws = new WebSocket(«ws://localhost:9000″);
ws.onmessage = function (evt) {
var t = document.getElementById(‘test’);
t.innerHTML =evt.data;
console.log(evt.data);
};
</script>
<div id=»test»>here is content</div>

Думаю дальше всем понятно как это работает 😉
теперь скажу лишь о возможности передачи сессий в php скрипт серверной стороны 😉
делается это костылем 🙂
в переменных которые доступны серверному скрипту есть $_SERVER[HTTP_COOKIE] оттуда вытаскиваем PHPSESSID и через session_id применяем его на серверной стороне, а что с этим можно соорудить решайте сами 😉
Скажу лишь то что данный сервер websockets очень удобная штука так как и https и http работает на ура =)
надеюсь вам было интересно !
с уважением всегда ваш Taras.Kramarets aka ~NiX~

Интеграция amocrm asterisk 1.8-13 проблемы не всплывает карточка

Здравствуйте товарищи !
Вашему вниманию хочу предложить свои услуги по инеграции asterisk и amocrm версия для меня не играет роли интегрирую в лучшем виде 😉

Так как amocrm довольно популярна но множество людей не могут решить проблемы которые возникают в ходе работы я помогу но понятное дело за денежное вознаграждение в сумме 40 у.е. Кого заинтересовало данное предложение милости прошу писать на taras@kramarets.net так же могу запустить websockets+webrtc телефоны с вплывающим окном для удобства пользования, окно всплывает из любого места главное что бы был открыт сам телефон.
Стоимость реализации с веб телефоном нового поколения сума 80 у.е. сюда входит настройка Astetisk,FreePBX,Freeswitch,Kamailio для работы websockets,webrtc если же нужна доп настройка обсуждаем дополнительно по задачам/стоимости.

Гарантия качества и результата !

Другие мои услуги можете посмотреть тут

freepbx и asterisk 13 websokets wss transport нету в меню

Здравствуйте уважаемые читатели !

Сегодня речь пойдет о том что во freepbx нету транспорта для websockets во всяком случае в релизах (

как же его добавить
нам нужно отредактировать файл admin/modules/core/functions.inc.php
ищем строку
if (version_compare($amp_conf[‘ASTVERSION’],’1.8′,’ge’)) {
unset($select);
$select[] = array(‘value’ => ‘udp,tcp,tls’, ‘text’ => _(‘All — UDP Primary’));
$select[] = array(‘value’ => ‘tcp,udp,tls’, ‘text’ => _(‘All — TCP Primary’));
$select[] = array(‘value’ => ‘tls,udp,tcp’, ‘text’ => _(‘All — TLS Primary’));
if (version_compare($amp_conf[‘ASTVERSION’],’11’,’ge’)) {
$select[] = array(‘value’ => ‘ws,udp,tcp,tls’, ‘text’ => _(‘All — WS Primary’));
//туда добавляем строку :

$select[] = array(‘value’ => ‘wss,udp,tcp,tls’, ‘text’ => _(‘All — WSS Primary’));
}
$select[] = array(‘value’ => ‘udp’, ‘text’ => _(‘UDP Only’));
$select[] = array(‘value’ => ‘tcp’, ‘text’ => _(‘TCP Only’));
$select[] = array(‘value’ => ‘tls’, ‘text’ => _(‘TLS Only’));
if (version_compare($amp_conf[‘ASTVERSION’],’11’,’ge’)) {
$select[] = array(‘value’ => ‘ws’, ‘text’ => _(‘WS Only’));
//и сюда :
$select[] = array(‘value’ => ‘wss,udp,tcp,tls’, ‘text’ => _(‘All — WSS Primary’));

}

Сохраняем и радуемся жизни.
На этом все всегда ваш боевой товарищ Taras Kramarets aka ~NiX~

PHP Websocket сервер и клиент SSL wss в одном обычный сервер и клиент ws 4 в 1 )

Доброго времени суток !

Товарищи захотелось поделиться опытом о Websockets те кто бились головой об стену как и я когда документации совсем не было сейчас выложу то что накропалось ещё давно но все руки не доходили описать данную реализацию так как в данный пример я только внес правки код не мой !

Итак начнем с того что все хотят работы через wss но не получется каменный цветок, а рекомендации на счет юзайте через прокси аля Nginx или Apache не выдерживают никакой критики так как Websockets стоит с ними почти на одном уровне с точки зрения модели OSI и как бы там ни было лишнее звено для отказа в такой красивой цепи как Websockets не хотелось держать в итоге было решено соорудить костыль который в на данный момент переписан на C++ и обвешан плюшками в виде многопоточности скажу сразу что производительность очень хороша мне нравиться ) но об C++ реализации сервера как то в другой раз и не на сонную голову ))

вообщем сам код сервера :

<?php

error_reporting(E_ALL); //Выводим все ошибки и предупреждения
set_time_limit(180); //Время выполнения скрипта ограничено 180 секундами
ob_implicit_flush(); //Включаем вывод без буферизации

$starttime = round(microtime(true),2);

echo «try to start…<br />»;

//  строчки ниже только для SSL(WSS) для WS не актуальны
$context = stream_context_create();

stream_context_set_option($context, ‘ssl’, ‘local_cert’, ‘/etc/ssl/cert.pem’);

stream_context_set_option($context, ‘ssl’, ‘passphrase’, »);

stream_context_set_option($context, ‘ssl’, ‘allow_self_signed’, true);

stream_context_set_option($context, ‘ssl’, ‘verify_peer’, false);

// для конекта по wss
$socket = stream_socket_server(«ssl://1.1.1.1:8000», $errno, $errstr,STREAM_SERVER_BIND|STREAM_SERVER_LISTEN, $context);

//для конекта по ws

$socket = stream_socket_server(«tcp://1.1.1.1:8000», $errno, $errstr);

 

if (!$socket) {
echo «socket unavailable<br />»;
die($errstr. «(» .$errno. «)\n»);
}
$connects = array();
while (true) {
echo «main while…<br />»;
//формируем массив прослушиваемых сокетов:
$read = $connects;
$read []= $socket;
$write = $except = null;

if (!stream_select($read, $write, $except, null)) {//ожидаем сокеты доступные для чтения (без таймаута)
break;
}

if (in_array($socket, $read)) {//есть новое соединение то обязательно делаем handshake
//принимаем новое соединение и производим рукопожатие:
if (($connect = stream_socket_accept($socket, -1)) && $info = handshake($connect)) {
// print_r($info);
// print_r($connect);
echo «new connection…<br />»;
echo «connect=».$connect.», info=».$info.»<br />OK<br />»;
//echo «info<br />»;
//var_dump($info);

$connects[] = $connect;//добавляем его в список необходимых для обработки
onOpen($connect, $info);//вызываем пользовательский сценарий
}
unset($read[ array_search($socket, $read) ]);
}

foreach($read as $connect) {//обрабатываем все соединения
$data = fread($connect, 100000);

if (!$data) { //соединение было закрыто
echo «connection closed…<br />»;
fclose($connect);
unset($connects[ array_search($connect, $connects) ]);
onClose($connect);//вызываем пользовательский сценарий
continue;
}

onMessage($connect, $data);//вызываем пользовательский сценарий
}

if( ( round(microtime(true),2) — $starttime) > 100) {
echo «time = «.(round(microtime(true),2) — $starttime);
echo «exit <br />\r\n»;
fclose($socket);
echo «connection closed OK<br />\r\n»;
exit();
}
}

fclose($socket);
function handshake($connect) { //Функция рукопожатия
$info = array();

$line = fgets($connect);
$header = explode(‘ ‘, $line);
$info[‘method’] = $header[0];
$info[‘uri’] = $header[1];
//print_r($header);
//считываем заголовки из соединения
while ($line = rtrim(fgets($connect))) {
if (preg_match(‘/\A(\S+): (.*)\z/’, $line, $matches)) {
$info[$matches[1]] = $matches[2];
} else {
break;
}
}
$address = explode(‘:’, stream_socket_get_name($connect, true)); //получаем адрес клиента
$info[‘ip’] = $address[0];
$info[‘port’] = $address[1];

if (empty($info[‘Sec-WebSocket-Key’])) {
return false;
}

//отправляем заголовок согласно протоколу вебсокета
$SecWebSocketAccept = base64_encode(pack(‘H*’, sha1($info[‘Sec-WebSocket-Key’] . ‘258EAFA5-E914-47DA-95CA-C5AB0DC85B11’)));
$upgrade = «HTTP/1.1 101 Web Socket Protocol Handshake\r\n» .
«Upgrade: websocket\r\n» .
«Connection: Upgrade\r\n» .
«Sec-WebSocket-Accept:».$SecWebSocketAccept.»\r\n\r\n»;
fwrite($connect, $upgrade);

return $info;
}

function encode($payload, $type = ‘text’, $masked = false)
{
$frameHead = array();
$payloadLength = strlen($payload);

switch ($type) {
case ‘text’:
// first byte indicates FIN, Text-Frame (10000001):
$frameHead[0] = 129;
break;

case ‘close’:
// first byte indicates FIN, Close Frame(10001000):
$frameHead[0] = 136;
break;

case ‘ping’:
// first byte indicates FIN, Ping frame (10001001):
$frameHead[0] = 137;
break;

case ‘pong’:
// first byte indicates FIN, Pong frame (10001010):
$frameHead[0] = 138;
break;
}

// set mask and payload length (using 1, 3 or 9 bytes)
if ($payloadLength > 65535) {
$payloadLengthBin = str_split(sprintf(‘%064b’, $payloadLength), 8);
$frameHead[1] = ($masked === true) ? 255 : 127;
for ($i = 0; $i < 8; $i++) {
$frameHead[$i + 2] = bindec($payloadLengthBin[$i]);
}
// most significant bit MUST be 0
if ($frameHead[2] > 127) {
return array(‘type’ => », ‘payload’ => », ‘error’ => ‘frame too large (1004)’);
}
} elseif ($payloadLength > 125) {
$payloadLengthBin = str_split(sprintf(‘%016b’, $payloadLength), 8);
$frameHead[1] = ($masked === true) ? 254 : 126;
$frameHead[2] = bindec($payloadLengthBin[0]);
$frameHead[3] = bindec($payloadLengthBin[1]);
} else {
$frameHead[1] = ($masked === true) ? $payloadLength + 128 : $payloadLength;
}

// convert frame-head to string:
foreach (array_keys($frameHead) as $i) {
$frameHead[$i] = chr($frameHead[$i]);
}
if ($masked === true) {
// generate a random mask:
$mask = array();
for ($i = 0; $i < 4; $i++) {
$mask[$i] = chr(rand(0, 255));
}

$frameHead = array_merge($frameHead, $mask);
}
$frame = implode(», $frameHead);

// append payload to frame:
for ($i = 0; $i < $payloadLength; $i++) {
$frame .= ($masked === true) ? $payload[$i] ^ $mask[$i % 4] : $payload[$i];
}

return $frame;
}

function decode($data)
{
$unmaskedPayload = »;
$decodedData = array();

// estimate frame type:
$firstByteBinary = sprintf(‘%08b’, ord($data[0]));
$secondByteBinary = sprintf(‘%08b’, ord($data[1]));
$opcode = bindec(substr($firstByteBinary, 4, 4));
$isMasked = ($secondByteBinary[0] == ‘1’) ? true : false;
$payloadLength = ord($data[1]) & 127;

// unmasked frame is received:
if (!$isMasked) {
return array(‘type’ => », ‘payload’ => », ‘error’ => ‘protocol error (1002)’);
}

switch ($opcode) {
// text frame:
case 1:
$decodedData[‘type’] = ‘text’;
break;

case 2:
$decodedData[‘type’] = ‘binary’;
break;

// connection close frame:
case 8:
$decodedData[‘type’] = ‘close’;
break;

// ping frame:
case 9:
$decodedData[‘type’] = ‘ping’;
break;

// pong frame:
case 10:
$decodedData[‘type’] = ‘pong’;
break;

default:
return array(‘type’ => », ‘payload’ => », ‘error’ => ‘unknown opcode (1003)’);
}

if ($payloadLength === 126) {
$mask = substr($data, 4, 4);
$payloadOffset = 8;
$dataLength = bindec(sprintf(‘%08b’, ord($data[2])) . sprintf(‘%08b’, ord($data[3]))) + $payloadOffset;
} elseif ($payloadLength === 127) {
$mask = substr($data, 10, 4);
$payloadOffset = 14;
$tmp = »;
for ($i = 0; $i < 8; $i++) {
$tmp .= sprintf(‘%08b’, ord($data[$i + 2]));
}
$dataLength = bindec($tmp) + $payloadOffset;
unset($tmp);
} else {
$mask = substr($data, 2, 4);
$payloadOffset = 6;
$dataLength = $payloadLength + $payloadOffset;
}

/**
* We have to check for large frames here. socket_recv cuts at 1024 bytes
* so if websocket-frame is > 1024 bytes we have to wait until whole
* data is transferd.
*/
if (strlen($data) < $dataLength) {
return false;
}

if ($isMasked) {
for ($i = $payloadOffset; $i < $dataLength; $i++) {
$j = $i — $payloadOffset;
if (isset($data[$i])) {
$unmaskedPayload .= $data[$i] ^ $mask[$j % 4];
}
}
$decodedData[‘payload’] = $unmaskedPayload;
} else {
$payloadOffset = $payloadOffset — 4;
$decodedData[‘payload’] = substr($data, $payloadOffset);
}

return $decodedData;
}

//пользовательские сценарии:

function onOpen($connect, $info) {
echo «open OK<br />\n»;
// fwrite($connect, encode(‘Привет, мы соеденены’));
fwrite($connect, encode(«$date»));
}

}

function onClose($connect) {
echo «close OK<br />\n»;
}

function onMessage($connect, $data) {
$f = decode($data);
echo «Message:»;
echo $f[‘payload’] . «<br />\n»;
fwrite($connect, encode($f[‘payload’]));
}

?>

Теперь код клиента в данном случае wss(ssl) если нужно просто то указываем ws:

<!DOCTYPE html>
<html>
<head>
<meta charset=»UTF-8″ />
<title>Siple Web-Socket Client</title>
</head>
<body>
<br /><br />

<script src=»socket.js» type=»text/javascript»></script>

Server address:
<input id=»sock-addr» type=»text» value=»wss://domainname.com:8000″><br />
Message:
<input id=»sock-msg» type=»text»>

<input id=»sock-send-butt» type=»button» value=»send»>
<br />
<br />
<input id=»sock-recon-butt» type=»button» value=»reconnect»><input id=»sock-disc-butt» type=»button» value=»disconnect»>
<br />
<br />

Полученные сообщения от веб-сокета:
<div id=»sock-info» style=»border: 1px solid»> </div>

</body>

Кто то спросит зачем при конекте писать домен вместо ип все просто сертификат выдается на домен, а не на ип !!! это запомните раз и на всю жизнь 😉

и теперь простой js скрипт для обработки :

«use strict»; //All my JavaScript written in Strict Mode http://ecma262-5.com/ELS5_HTML.htm#Annex_C

(function () {
// ======== private vars ========
var socket;

////////////////////////////////////////////////////////////////////////////
var init = function () {

socket = new WebSocket(document.getElementById(«sock-addr»).value);

socket.onopen = connectionOpen;
socket.onmessage = messageReceived;
//socket.onerror = errorOccurred;
//socket.onopen = connectionClosed;

document.getElementById(«sock-send-butt»).onclick = function () {
socket.send(document.getElementById(«sock-msg»).value);
};
document.getElementById(«sock-disc-butt»).onclick = function () {
connectionClose();
};

document.getElementById(«sock-recon-butt»).onclick = function () {
socket = new WebSocket(document.getElementById(«sock-addr»).value);
socket.onopen = connectionOpen;
socket.onmessage = messageReceived;
};

};
function connectionOpen() {
socket.send(«Connection with \»»+document.getElementById(«sock-addr»).value+»\» Подключение установлено обоюдно, отлично!»);
}

function messageReceived(e) {
console.log(«Ответ сервера: » + e.data);
document.getElementById(«sock-info»).innerHTML += (e.data+»<br />»);
}

function connectionClose() {
socket.close();
document.getElementById(«sock-info»).innerHTML += «Соединение закрыто <br />»;

}
return {
////////////////////////////////////////////////////////////////////////////
// —- onload event —-
load : function () {
window.addEventListener(‘load’, function () {
init();
}, false);
}
}
})().load();

 

На этом все тестируйте 😉

P.s. сервер можно запускать как из консоли так и с веба то есть юзать можно даже на простых хостингах но ограничено !

Всегда ваш боевой товарищ  Тарас Крамарец aka ~NiX~