I implemented Websockets in my server, it works great to communicate with the server itself, but it cannot connect directly do my Delhpi application, so I thought, "I'll just make Delphi send info to PHP, then make PHP push info to the client via Websocket!", GREAT! but it doesn't work.
I'm not sure why, but I think it has something to do with 2 sockets cannot be listening at the same time, so I think I need to use Threads or something like that.
On paper it looks easy, it looks like I just need to start a Thread with my function listening my Delphi application socket, and when it receives a message, I would send this to the parent process to push the message via websocket, but I cant help it but feel like there is something wrong with this tactic.
This is the code that reads from the socket of my Delphi app:
<?php
/* Cliente */
function enviarPct($skt, $pacote){
$msg = "$pacote\n";
socket_write($skt, $msg, strlen($msg));
echo "TX: $msg";
}
error_reporting(E_ALL);
echo "Conexao TCP/IP em PHP\n";
$address = "192.168.2.26";
$port = 63333;
$sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_connect($sock, $address, $port);
socket_set_option($sock, SOL_SOCKET, SO_KEEPALIVE, 1);
echo "Conexao: $address:$port\n\n";
enviarPct($sock,"login||20||");
//$msg = "login||20||\n";
//echo socket_write($sock, $msg, strlen($msg));
//echo socket_write($sock, utf8_encode($msg), mb_strlen($msg, 'utf-8'));
echo "Reading response:\n\n";
while ($out = socket_read($sock, 2048)) {
echo "RX: $out";
$pct = explode('||', $out);
if($pct[0]=='sucessoLogin'){
if($pct[1]!= '-1'){
enviarPct($sock, "solicitaControladoras||||");
}
}
}
//echo socket_read($sock, 2048);
echo "Fechando\n";
socket_close($sock);
?>
And Within the websocket aplication class, this funcion push messeges to the client, more specificaly that looping with "Im Waiting X Seconds"
/**
* Start a child process for pushing data
* #param unknown_type $client
*/
private function startProcess($client) {
$this->console("Start a client process");
$pid = pcntl_fork();
if($pid == -1) {
die('could not fork');
}
elseif($pid) { // process
$client->setPid($pid);
}
else {
// we are the child
while(true) {
// check if the client is connected
if(!$client->isConnected()){
break;
}
// push something to the client
$seconds = rand(2, 5);
$this->send($client, "I am waiting {$seconds} seconds");
sleep($seconds);
}
}
}
So thats it, if somebody have an idea of what would work best for me I would be glad to listen.
Related
i have a question about Sockets in PHP. My Environment Looks like follows:
one Server VM with Ubuntu 22.04 , and one VM with Windows 10. On The net is Global Cache IP2SL Adapter, on that interface is an Monitor with serial Line connected to this IP2SL.
The Goal should be , to send HEX Codes to the IP2SL which will be send to the Monitor. Some of These Codes have an Answer i.e. some Parameters like Brighness or Situation. In The end , on The Ubuntu is an Website where u can read and change those values . Therefore i've build some small testscripts to Check the Communication. To Monitor the line i use Wireshark, and both VM Linux and Windows run in a Parallels Environment on a Mac.
The Problem:
Did i send the hex code from windows to The IP2SL Adapter, anything looks fine, the command where send to the Monitor and the Monitor answer as expected. Did i send the same via php the command where send , and The Monitor Works with it as expected, if the commmand has no answer, i.e. PowerOn/Poweroff working like a charm, but if the Monitor should send an answer like brightness : XX% there come an "504 gateway TimeOut" After 60s on the Ubuntu System . did i do the same with IP2SL test App , the answer is correctly. In Wireshark is the Communication as expected. my php code Looks like follows
<?php
error_reporting(E_ALL);
ini_set('display_errors',1);
$port = '4999';
$adr = "192.168.100.34";
$sendStr = array('E5', 'TARGET', '20', '86');//hexadecimal data
$target = "05";
function makeValue($v)
{
return pack('H*',dechex($v));
}
function toSend($adr,$port,$target,$cmd)
{
ob_implicit_flush();
// find target
for($i=0;$i < count($cmd);$i++)
{
if($cmd[$i] === "TARGET")
{
$cmd[$i] = hexdec($target);
}
else
{
$cmd[$i] = hexdec($cmd[$i]);
}
}
// build the CRC
$cmd[] = hexdec('FF') - array_sum($cmd) & hexdec('FF');
//var_dump($cmd);
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
//socket_set_nonblock($socket);
if ($socket === false) {
echo "socket_create() fehlgeschlagen: Grund: " . socket_strerror(socket_last_error()) . "\n";
} else {
echo "Socket erstellt OK.\r\n";
}
echo "Versuche, zu '$adr' auf Port '$port' zu verbinden ...";
$result = socket_connect($socket, $adr, $port);
if ($result === false) {
echo "socket_connect() fehlgeschlagen.\nGrund: ($result) " . socket_strerror(socket_last_error($socket)) . "\n";
} else {
echo "Socket verbunden OK.\r\n";
}
$chars = array_map('makeValue',$cmd);
$out = join($chars);
$length = strlen($out);
//var_dump($out);
if(socket_write($socket, $out,$length))
{
usleep(25000);
$input = stream_get_contents($socket,1024);
socket_close($socket);
var_dump($input);
}
//socket_close($socket);
/*
if($input === FALSE || strcmp($input,'') == 0) {
$code = socket_last_error($socket);
socket_clear_error($socket);
socket_close($socket);
} else {
echo "Answer : ". bin2hex($input);
socket_close($socket);
}
*/
}
toSend($adr,$port,$target,$sendStr);
?>
Solution: The Solution is the array_map function 'makeValue'. The php pack command has an Format 'h*' and 'H*' , if the value is an Single Byte , the 'H*' converts it to the higher nibble , so the value '7' will Converted to '0x70'
function makeValue($v)
{
if(strlen($v)>1)
{
return pack('H*',dechex($v));
}
return pack('h*',dexhex($v));
}
this Solves the Problem
This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 9 years ago.
What i'm trying to do is implement a SIP client which listens for SIP messages.Ok so i have run the SIP client on a server 192.168.0.246 and the SIP server is running on 192.168.2.40.Now have a look at the below screen shot.
Its a trace file of the server running the client code on 192.168.0.246. As u can see the server receives messages from 192.168.2.40 using SIP/SDP protocol but when the client program running on 192.168.0.246 sends back message to 192.168.2.40 using UDP protocol its shown as UDP protocol, which is correct.But no response from 192.168.2.40 after this.
So i'm assuming it has something to do with the protocol shown as UDP.So if i'm rite i should get that to SIP/SDP.
So my question is how to make this UDP change to SIP/SDP.
And here is my php code:
<?php
//Reduce errors
error_reporting(~E_WARNING);
//Create a UDP socket
if(!($sock = socket_create(AF_INET, SOCK_DGRAM, 0)))
{
$errorcode = socket_last_error();
$errormsg = socket_strerror($errorcode);
die("Couldn't create socket: [$errorcode] $errormsg \n");
}
echo "Socket created \n";
// Bind the source address
if( !socket_bind($sock, "192.168.0.246" , 5060) )
{
$errorcode = socket_last_error();
$errormsg = socket_strerror($errorcode);
die("Could not bind socket : [$errorcode] $errormsg \n");
}
echo "Socket bind OK \n";
//Do some communication, this loop can handle multiple clients
function GetBranchValue($message)
{
$data = "";
if(preg_match('/branch=.*/i', $message, $output))
$data = explode("=",$output[0]);
if(sizeOf($data)>1)
return $data[1];
else
return "None";
}
function GetTag($message)
{
$data = "";
if(preg_match('/tag=.*/i',$message, $output))
$data = explode("=", $output[0]);
if(sizeOf($data)>1)
return $data[1];
else
return "None";
}
function GetCallId($message)
{
$data = "";
if(preg_match('/Call-ID:.*/i', $message, $output))
$data = explode(":",$output[0]);
if(sizeOf($data)>1)
return $data[1];
else
return "None";
}
function GetCSeq($message)
{
$data = "";
if(preg_match('/CSeq:.*/i', $message, $output))
{
$data = explode(":", $output[0]);
$data = explode(" ",$data[1]);
}
if(sizeOf($data[1])>0)
return $data[1];
else
return "None";
}
function CreateResponse($message)
{
$msg = "SIP/2.0 302 Moved temporarily
Via:SIP/2.0/UDP 192.168.2.40:5060;branch=".GetBranchValue($message)."
From: <sip:+12012030008#192.168.2.40:5060>;tag=".GetTag($message)."
To:<sip:+17066458407#192.168.0.246:5060;user=phone>;tag=883069368-1363286882583
Call-ID:".GetCallId($message)."
CSeq:".GetCSeq($message)." INVITE
Contact:<sip:+17066458407#192.168.0.246:5060;user=phone>;q=0.5,<sip:+17066458407#192.168.0.246:5060;user=phone>;q=0.25
Content-Length:0";
return $msg;
}
function Create300Response($message)
{
$msg = "SIP/2.0 300 Multiple Choices
Via: SIP/2.0/UDP 192.168.2.40:5060;branch=".GetBranchValue($message)."
From: <sip:+12012030008#192.168.2.40:5060>;tag=".GetTag($message).";isup-oli;isup-oli=00
To:<sip:+17066458407#192.168.0.246:5060;user=phone>;tag=123
Contact: <sip: +17066458407#192.168.0.246:5060;dtg=16>
Contact: <sip: +17066458407#192.168.0.246:5060;dtg=16>
Contact: <sip: +17066458407#192.168.0.246:5060;dtg=16>
Contact: <sip: +17066458407#192.168.0.246:5060;dtg=16>";
return $msg;
}
while(1)
{
echo "Waiting for data ... \n";
//Receive some data
$r = socket_recvfrom($sock, $buf, 512, 0, $remote_ip, $remote_port);
echo "$remote_ip : $remote_port -- " . $buf;
file_put_contents("Log.txt","\n",FILE_APPEND);
file_put_contents("Log.txt","Received Response------\n",FILE_APPEND);
file_put_contents("Log.txt",$buf,FILE_APPEND);
$respMessage = Create300Response($buf);
//Send back the data to the client
socket_sendto($sock, "OK " . $respMessage , 100 , 0 , $remote_ip , $remote_port);
file_put_contents("Log.txt","\n",FILE_APPEND);
file_put_contents("Log.txt","\n",FILE_APPEND);
file_put_contents("Log.txt",$respMessage,FILE_APPEND);
}
socket_close($sock);
socket_sendto($sock, "OK " . $respMessage , 100 , 0 , $remote_ip , $remote_port);
// ^^ remove this
The OK you are sending is not valid, it is a SIP protocol violation, and as a result the in-built SIP decoder in Wireshark does not recognise the message as a valid SIP packet.
You should just be responding with $respMessage
Also I highly recommend you use a proper parser for incoming messages and a proper object-oriented writer for constructing outgoing messages. SIP is a (some might say needlessly) complex protocol, you will need more than the small nuggets of information you are extracting to build an endpoint that can do anything even remotely useful.
This small library of mine might make a good base for your parser, and indeed this one almost does exactly what you want if you replace HTTP with SIP.
I'm running a php server based on the one provided by a tutorial by Raymond Fain on kirupa:
http://www.kirupa.com/developer/flash8/php5sockets_flash8_3.htm
It works great, up to a point. The thing is that when it receives certain messages, it then does some stuff to that message then sends it out to all connected clients. The problem here is that once the number of clients reaches the atmospheric heights of around 12, the loop that sends the message to all clients can take a while (like 4 seconds), and any subsequent messages sent during that 4 second period get queued up and eventually we get timeouts.
This is the loop that sends a message to all clients:
function send_Message($allclient, $socket, $buf)
{
$now = microtime(true);
echo 'sending message to '.count($allclient).' clients ';
$msg = "<mbFeed>$buf</mbFeed>\n\0";
foreach($allclient as $client)
{
socket_write($client, $msg, strlen($msg));
}
$end = microtime(true);
echo 'time was '.($end - $now);
}
You'll notice I've been echoing the time it takes by comparing microtimes. The thing is that the echo claims that the whole process takes a tiny amount of time, like 0.003 seconds, which is what I would have expected, but when I have this script running in the terminal, I see the little spinning icon going for the four seconds, during which everything gets unresponsive.
My questions are as follows: does anyone know what the script is doing during that time? Is there anything I can do it to stop it doing that? Is there a more efficient way to send a message to all connected sockets?
Here's the code for the whole socket file, if you need it, but I'm hoping this is something that might be familiar to somebody...
#!/usr/bin/php -q
<?php
/*
Raymond Fain
Used for PHP5 Sockets with Flash 8 Tutorial for Kirupa.com
For any questions or concerns, email me at ray#obi-graphics.com
or simply visit the site, www.php.net, to see if you can find an answer.
*/
//ini_set('display_errors',1);
ini_set('display_startup_errors',1);
error_reporting(E_ALL);
//ini_set('error_log', 'socket_errors.log');
ini_set('log_errors', 'On');
ini_set('display_errors', '1');
error_log('testing');
stream_set_timeout(1,0);
set_time_limit(0);
ob_implicit_flush();
$address = 'xxx.xxx.x.xxx';
$port = xxxx;
function send_Message($allclient, $socket, $buf)
{
$now = microtime(true);
echo 'sending message to '.count($allclient).' clients ';
$msg = "<mbFeed>$buf</mbFeed>\n\0";
foreach($allclient as $client)
{
socket_write($client, $msg, strlen($msg));
}
$end = microtime(true);
echo 'time was '.($end - $now);
}
echo "connecting...
";
//---- Start Socket creation for PHP 5 Socket Server -------------------------------------
if (($master = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) < 0)
{
echo "socket_create() failed, reason: " . socket_strerror($master) . "\n";
}
socket_set_option($master, SOL_SOCKET,SO_REUSEADDR, 1);
socket_set_nonblock($master);
if (($ret = socket_bind($master, $address, $port)) < 0)
{
echo "socket_bind() failed, reason: " . socket_strerror($ret) . "\n";
}
echo 'socket bind successfull.
';
if (($ret = socket_listen($master, 5)) < 0)
{
echo "socket_listen() failed, reason: " . socket_strerror($ret) . "\n";
}
$read_sockets = array($master);
echo "connected.";
//---- Create Persistent Loop to continuously handle incoming socket messages ---------------------
while (true)
{
$changed_sockets = $read_sockets;
$num_changed_sockets = socket_select($changed_sockets, $write = NULL, $except = NULL, NULL);
echo 'changed sockets length: '.(count($changed_sockets));
foreach($changed_sockets as $key => $socket)
{
if ($socket == $master)
{
if (($client = socket_accept($master)) < 0)
{
echo "socket_accept() failed: reason: " . socket_strerror($msgsock) . "\n";
continue;
}
else
{
socket_set_nonblock($client);
array_push($read_sockets, $client);
}
}
else
{
$bytes = socket_recv($socket, $buffer, 8192, 0);
if ($bytes == 0)
{
unset($read_sockets[$key]);
unset($changed_sockets[$key]);
socket_close($socket);
}
else
{
if (substr($buffer, 0, 3) == "<->")
{
unset($read_sockets[$key]);
unset($changed_sockets[$key]);
socket_close($socket);
$buffer = substr($buffer, 3);
}
$allclients = $read_sockets;
array_shift($allclients);
if (substr($buffer, 0, 3) == ":::") handleSpecial(substr($buffer, 3));
else
{
echo 'allclients length: '.(count($allclients));
send_Message($allclients, $socket, str_replace("\0","",$buffer));
}
}
}
}
}
?>
I would like to recommend you to look at ZeroMQ its like sockets on steroids
ØMQ in a Hundred Words
ØMQ (also seen as ZeroMQ, 0MQ, zmq) looks like an embeddable networking library but acts like a concurrency framework. It gives you sockets that carry atomic messages across various transports like in-process, inter-process, TCP, and multicast. You can connect sockets N-to-N with patterns like fanout, pub-sub, task distribution, and request-reply. It's fast enough to be the fabric for clustered products. Its asynchronous I/O model gives you scalable multicore applications, built as asynchronous message-processing tasks. It has a score of language APIs and runs on most operating systems. ØMQ is from iMatix and is LGPLv3 open source.
using ZMQ::SOCKET_PUB and ZMQ::SOCKET_PULL the same chat server can be as simple as
$ctx = new ZMQContext();
$pub = $ctx->getSocket(ZMQ::SOCKET_PUB);
$pub->bind('tcp://*:5566');
$pull = $ctx->getSocket(ZMQ::SOCKET_PULL);
$pull->bind('tcp://*:5567');
echo "Chat Server Start ", PHP_EOL;
while(true) {
$message = $pull->recv();
echo "Got ", $message, PHP_EOL;
$pub->send($message);
}
This can easily handle10,000 push request per min on a simple system as oppose to your current server implementation.
With ZmqSocket you can talk to zmq sockets from your JavaScript code. You can connect, send and receive string messages. As JavaScript does not support raw TCP connections, it uses Flash as a bridge
Simple JavaScript Bridge Example you can also look at zmqsocket-as which allows you to talk to zmq-sockets from ActionScript code.
Trying to make a little script that will turn on server. I found few examples on the net, but wanted to keep this basic/simple also to get better hold of how it all fits together. But this doesn't work, I realize I've to specify subnet 255 255 255 0 somewhere...
any ideas?
<?php
//check if server is up and running
$alive = fsockopen("XXX.168.1.1", 80, $errno, $errstr, 2);
if (!$alive) {
echo "<h1>Server is Down!</h1>";
echo "I will try to turn it on now...";
//Creating magic packet
$mac_address = str_repeat("XXX5XXXX5XXX", 16);
$msg = "FFFFFFFFFFFF " . "$mac_address" . "000000000000";
$host_addr = "XXX.168.1.1";
$host_port = "X";
//Connect send and close connection
$socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
$socket_data = socket_send($socket, $msg, strlen($msg), 0, $host_addr, $host_port);
socket_close($socket);
//testing
//echo
} else {
echo "<h1>Server is Up!</h1>";
fclose($alive);
}
?>
Check this: http://www.php.net/manual/en/function.socket-sendto.php#57746
And this: http://www.php.net/manual/en/function.socket-send.php#58574
Maybe even this: http://www.codeproject.com/Articles/11469/Wake-On-LAN-WOL
You'll find out that you need to set the ip address argument to '255.255.255.255' to make a broadcast :)
I need to check if a group of servers, routers and switches is alive. I have been searching for something reliable that would work with IPs and ports for over an hour now, could anyone help?
Ended up using
function ping($addr, $port='') {
if(empty($port)) {
ob_start();
system('ping -c1 -w1 '.$addr, $return);
ob_end_clean();
if($return == 0) {
return true;
} else {
return false;
}
} else {
$fp = fsockopen("udp://{$addr}", $port, $errno, $errstr);
if (!$fp) {
return false;
} else {
return true;
}
}
}
Servers, routers and switches...the one commonality that all of them share is the ability to accept SNMP requests if an SNMP service is running. Sounds like what you are trying to do is implement a funny workaround to a monitoring system (nagios, etc....)
As per: http://php.net/manual/en/book.snmp.php
<?php
$endpoints = array('10.0.0.1','10.0.0.2','10.0.0.3','10.0.0.4','10.0.0.5');
foreach ($endpoints as $endpoint) {
$session = new SNMP(SNMP::VERSION_2c, $endpoint, 'boguscommunity');
var_dump($session->getError());
// do something with the $session->getError() if it exists else, endpoint is up
}
?>
This will tell you if the endpoint is alive and the SNMP service is running. Specific to seeing if the port is available / open, you can use fsockopen():
http://php.net/manual/en/function.fsockopen.php
<?php
$fp = fsockopen("udp://127.0.0.1", 13, $errno, $errstr);
if (!$fp) {
echo "ERROR: $errno - $errstr<br />\n";
}
?>
$ip = "123.456.789.0";
$ping = exec("ping -c 1 -s 64 -t 64 ".$ip);
var_dump($ping);
// and so forth.
if you are checking for mysql you can use something like
if (mysqli_ping($ip)) echo "sweet!";
else echo "oh dam";
I would be a little concerned using the ping option as that can be blocked, and out of no where ...