I've written a pair of PHP socket servers that listen around for commands and respond to them. The problem is that they do so by listening in an infinite loop, and thus are eating up CPU.
So how do I do this (1) without eating up CPU; and (2) without slowing down the socket commands, particularly if I have several come in in sequence?
$sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_set_option($sock, SOL_SOCKET, SO_REUSEADDR, 1);
socket_bind($sock, $address, $port);
socket_listen($sock);
$clients = array($sock);
$write = NULL;
$except = NULL;
while (true) {
$read = $clients;
if (socket_select($read, $write, $except, 0) < 1)
continue;
if (in_array($sock, $read)) {
$clients[] = socket_accept($sock);
$key = array_search($sock, $read);
unset($read[$key]);
}
foreach ($read as $read_sock) {
/* I tried putting a tiny sleep here, but if I run several socket connections for the same user sequentially, they see a notable slowdown */
$data = #socket_read($read_sock, 1024, PHP_NORMAL_READ);
if ($data === false) {
$key = array_search($read_sock, $clients);
unset($clients[$key]);
echo "client disconnected.\n";
continue;
}
$data = trim($data);
/* And this is the heart of my loop */
}
} // end of reading foreach
}
// close the listening socket
socket_close($sock);
Related
I am running script server.php where I am listening to IP and PORT. I simulate incoming message by running input.php.
Question: How can I listen to every port?
Note: I am trying to catch any message, that will go via TCP/IP protocol to my IP regardless on which port.
server.php
function writeToFile($strFilename, $strText)
{
if ($fp = #fopen($strFilename, "a+")) {
$contents = fwrite($fp, $strText . PHP_EOL);
fclose($fp);
return true;
} else {
return false;
}
}
$sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
$bind = socket_bind($sock, $address, $port);
socket_listen($sock, 5);
while ($con == 1) {
$client = socket_accept($sock);
$input = socket_read($client, 100);
$prefix = date('Y_m_d');
$data = $prefix . '_data.txt';
writeToFile($data, $input);
if ($input == 'exit') {
socket_close($sock);
$con = 0;
}
if ($con == 1) {
$word .= $input;
}
echo $input . PHP_EOL;
socket_write($client, $input . PHP_EOL);
}
input.php
<?php
$address = "192.168.0.103";
$port = 5503;
$randomString = substr(str_shuffle("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), 0, 10);
$fp = fsockopen($address, $port);
$bytes = fwrite($fp, $randomString);
if ($bytes == false) {
echo 'Send data: 0 Bytes';
} else {
echo 'Send data: ' . $bytes . ' Bytes';
}
fclose($fp);
exit;
Listening to all ports by creating a socket is not a good idea. Better monitor incoming SYN (synchronize) request and then bind to that particular port.
You can use tcpdump for monitoring incoming requests.
tcpdump -i eth0 -s 1500 port not 22 and '(tcp-syn|tcp-ack)!=0'
You can exclude ports by port not. Make sure to use correct interface name.
Execute above command with php function proc_open, since tcpdump gives continuous output.
$cmd = 'tcpdump -i eth1 -s 1500 port not 22 and "(tcp-syn|tcp-ack)!=0"';
$descriptorspec = array(
0 => array("pipe", "r"), // stdin is a pipe that the child will read from
1 => array("pipe", "w"), // stdout is a pipe that the child will write to
2 => array("pipe", "w") // stderr is a pipe that the child will write to
);
flush();
$process = proc_open($cmd, $descriptorspec, $pipes, realpath('./'), array());
if (is_resource($process)) {
while ($s = fgets($pipes[1])) {
print $s;
//make sure $s is a SYN request then create and listen to port
flush();
}
}
i have implemented a socket server in localhost
script i used is from http://www.sanwebe.com/2013/05/chat-using-websocket-php-socket
script is
$host = "localhost"; //host
$port = 9099; //port
if(isset($argv[1]))
{
$host = $argv[1];
}
if(isset($argv[2]))
{
$port = $argv[2];
}
$null = NULL; //null var
$ips=array();
//Create TCP/IP sream socket
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
//reuseable port
socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1);
//bind socket to specified host
socket_bind($socket, 0, $port);
//listen to port
socket_listen($socket);
//create & add listning socket to the list
$clients = array($socket);
$clients_ip=array();
//start endless loop, so that our script doesn't stop
while (true) {
//manage multipal connections
$changed = $clients;
//returns the socket resources in $changed array
socket_select($changed, $null, $null, 0, 10);
//check for new socket
if (in_array($socket, $changed)) {
$socket_new = socket_accept($socket); //accpet new socket
socket_getpeername($socket_new, $ip);
$clients[] = $socket_new; //add socket to client array
$clients_ip[$ip] = $socket_new;
$header = socket_read($socket_new, 1024); //read data sent by the socket
perform_handshaking($header, $socket_new, $host, $port); //perform websocket handshake
//get ip address of connected socket
$ips[]=$ip;
$response = mask(json_encode(array('ip'=>$ip,'type'=>'c', 'message'=>$ip.' connected','ips'=>$ips))); //prepare json data
send_message($response); //notify all users about new connection
//make room for new socket
$found_socket = array_search($socket, $changed);
unset($changed[$found_socket]);
}
//print_r($changed);exit;
if(count($changed)>0)
{
//loop through all connected sockets
foreach ($changed as $changed_socket) {
//check for any incomming data
while(socket_recv($changed_socket, $buf, 1024, 0) >= 1)
{
$received_text = unmask($buf); //unmask data
$tst_msg = json_decode($received_text); //json decode
//$user_name = $tst_msg->name; //sender name
//$user_message = $tst_msg->message; //message text
//$user_color = $tst_msg->color; //color
//prepare data to be sent to clientjson_encode(array('type'=>'usermsg', 'name'=>$user_name, 'message'=>$user_message, 'color'=>$user_color))
$response_text = mask($received_text);
if(isset($tst_msg->type))
{
if($tst_msg->type=="n")
{
#socket_write($clients_ip[$tst_msg->to_ip],$response_text,strlen($response_text));
}
}
//send_message($response_text); //send data
break 2; //exist this loop
}
$buf = #socket_read($changed_socket, 1024, PHP_NORMAL_READ);
if ($buf === false) { // check disconnected client
// remove client for $clients array
$found_socket = array_search($changed_socket, $clients);
socket_getpeername($changed_socket, $ip);
unset($clients[$found_socket]);
if (($key = array_search($ip, $ips)) !== false)
{
unset($ips[$key]);
}
$ips=array_values($ips);
//notify all users about disconnected connection
$response = mask(json_encode(array('ip'=>$ip,'type'=>'d', 'message'=>$ip.' disconnected','ips'=>$ips)));
send_message($response);
}
}
}
}
// close the listening socket
socket_close($sock);
function send_message($msg)
{
global $clients;
foreach($clients as $changed_socket)
{
#socket_write($changed_socket,$msg,strlen($msg));
}
return true;
}
//Unmask incoming framed message
function unmask($text) {
$length = ord($text[1]) & 127;
if($length == 126) {
$masks = substr($text, 4, 4);
$data = substr($text, 8);
}
elseif($length == 127) {
$masks = substr($text, 10, 4);
$data = substr($text, 14);
}
else {
$masks = substr($text, 2, 4);
$data = substr($text, 6);
}
$text = "";
for ($i = 0; $i < strlen($data); ++$i) {
$text .= $data[$i] ^ $masks[$i%4];
}
return $text;
}
//Encode message for transfer to client.
function mask($text)
{
$b1 = 0x80 | (0x1 & 0x0f);
$length = strlen($text);
if($length <= 125)
$header = pack('CC', $b1, $length);
elseif($length > 125 && $length < 65536)
$header = pack('CCn', $b1, 126, $length);
elseif($length >= 65536)
$header = pack('CCNN', $b1, 127, $length);
return $header.$text;
}
//handshake new client.
function perform_handshaking($receved_header,$client_conn, $host, $port)
{
$headers = array();
$lines = preg_split("/\r\n/", $receved_header);
foreach($lines as $line)
{
$line = chop($line);
if(preg_match('/\A(\S+): (.*)\z/', $line, $matches))
{
$headers[$matches[1]] = $matches[2];
}
}
$secKey = $headers['Sec-WebSocket-Key'];
$secAccept = base64_encode(pack('H*', sha1($secKey . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')));
//hand shaking header
$upgrade = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n" .
"Upgrade: websocket\r\n" .
"Connection: Upgrade\r\n" .
"WebSocket-Origin: $host\r\n" .
"WebSocket-Location: ws://$host:$port/demo/shout.php\r\n".
"Sec-WebSocket-Accept:$secAccept\r\n\r\n";
socket_write($client_conn,$upgrade,strlen($upgrade));
}
i run this program in xampp shell like
php -q path-to-server\server.php
i have a server with shell support
But when i run script
php -q path-to-server\server.php
it works but when shell is closed server will close automatically
so how to run this server continuously with out automatically closing?
i have a linux hosting package
Use this code,
php -f server.php
if you want to run continusely in banground you can use nohub
nohup php server.php &
if want to kill the process you use kill
kill processid
you can run in terminal
php filename.php
I'm guessing you are connecting to the server by ssh?
The server session is ending and all open proccesses are killed that is why your server instance is ending, you are running it from a non-privileged user.
So the way I use is to install screen on the remote server and use that.
https://www.gnu.org/software/screen/manual/screen.html
Or it looks like you might be running a windows server. If this is the case I would recomend using a Linux server as windows makes this a little harder. You will have to run your server instance as a system proccess.
you should run this command as a background proccess like
nohup php -f myBind.php > /dev/null &
Also you can put a simple sccript to crontab for checking your bind.php is up or not if its not run it again.
How to send binary data representing 01 (PHP)?
My Server code (sockets TCP, address is only example. I use my server address of course)
error_reporting(E_ALL);
set_time_limit(0);
ignore_user_abort(true);
$address = '11.111.111.111'; // example server address
$port = 9000; // example port
$sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_set_option($sock, SOL_SOCKET, SO_REUSEADDR, 1);
socket_bind($sock, $address, $port);
socket_listen($sock);
$clients = array($sock);
while(true) {
$read = $clients;
if (socket_select($read, $write = NULL, $except = NULL, 0) < 1) {
continue;
}
if (in_array($sock, $read)) {
$clients[] = $newsock = socket_accept($sock);
$key = array_search($sock, $read);
unset($read[$key]);
}
foreach ($read as $read_sock) {
$data = #socket_read($read_sock, 1024);
if ($data === false) {
// remove client for $clients array
$key = array_search($read_sock, $clients);
unset($clients[$key]);
echo "client disconnected.\n";
// continue to the next client to read from, if any
continue;
}
$data = trim($data);
// check if there is any data after trimming off the spaces
if (!empty($data)) {
// send this to all the clients in the $clients array (except the first one, which is a listening socket)
foreach ($clients as $send_sock) {
// if its the listening sock or the client that we got the message from, go to the next one in the list
if ($send_sock == $sock || $send_sock == $read_sock) {
continue;
}
$fp = fopen('socket_communication.txt', 'a');
fwrite($fp, date("Y-m-d H:i:s")." - DATA ".$data."\n");
fclose($fp);
$value = unpack('H*', "1");
$response = base_convert($value[1], 16, 2);
socket_write($send_sock, $response, 1);
} // end of broadcast foreach
}
}
}
echo "Closing sockets...";
socket_close($sock);
I would like to server sent binary data (01 or 1).
I use unpack function and convert it by base_convert but it doesnt works.
This code send response to client
$value = unpack('H*', "1");
$response = base_convert($value[1], 16, 2);
socket_write($send_sock, $response, 1);
i'm trying write asynchronous socket listener code in php. but listener response answer only for first request and for other requests it only can receive packets without response (i'm checking with sniffer) also i'm counting how many time loop was active and loop is active only for first request ...... i'll show my Code :
addr = '192.168.0.117';
$port = 7878;
$sock = socket_create(AF_INET, SOCK_STREAM, 0);
socket_bind($sock, $addr, $port) or die('Could not bind to address');
socket_listen($sock);
$null = NULL;
$clients = Array();
$cc = 0; // loop counter
while(true){
echo $cc."<br>";
$cc = $cc +1;
$read[0] = $sock;
$ready = socket_select($read,$null,$null,$null);
$client = socket_accept($sock);
$input = socket_read($client, 312);
echo $input;
if($input == "exit"){
socket_close($client);
socket_close($sock);
return false;
}
$output = 0x11;
socket_write($client,$output);
$input = "";
}
May be you are closing the listening socket right after the first client sends exit command. You should close only client socket when the client sends exit command. And you return false from the while loop. This means obviously it will process only one client.
if($input == "exit"){
socket_close($client);
socket_close($sock); // Think about this Line.
return false; // Think about this Line.
}
I have a gps simulator, which sends continuous location data (nmea strings) through tcpip to 192.168.0.178:2323. How do I get that data using tcp socket and write to DB (php & mysql)?
Thanks!
This is a loaded question. First you need to read the data. Then you have to put some structure to the data for it to be usable. It doesn't do you much good to just dump lat-lon to a database. You probably want to save it as a waypoint or part of a track etc.
So I have no answer to the DB question. Here is part of the PHP program I use to read GPS data off my phone connected to a CradlePoint router. It's modified from GoogleNav code.
function read_gps() {
set_time_limit(5);
$fp = fsockopen ("192.168.0.1", 8080, $errno, $errstr, 30);
if (!$fp) {
die ("$errstr ($errno)");
}
$point=false;
$status="";
$fix=0;
while (!$point) {
$string=#fgets($fp, 4096);
switch (substr($string,0,6)) {
case "\$GPRMC" :
list($sentence, $time, $status, $latitude, $NS, $longitude, $EW, $speed, $course, $date, $magvar, $magvarEW)= explode(",", trim($string));
$latd=convdec($latitude, $NS);
$lond=convdec($longitude, $EW);
break;
case "\$GPGGA" :
list($sentence, $time, $latitude, $NS, $longitude, $EW, $fix, $nbsat, $HDOP, $altitude,,,,,)= explode(",", trim($string));
$latd=convdec($latitude, $NS);
$lond=convdec($longitude, $EW);
break;
default :
break;
}
if ($status=="A" and $fix == 1){
$point=true;
}
}
...
?>
Start here: PHP Sockets
One of the user comments gives a helpful sample implementation of a TFTP client
<?php
function tftp_fetch($host, $filename)
{
$socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
// create the request packet
$packet = chr(0) . chr(1) . $filename . chr(0) . 'octet' . chr(0);
// UDP is connectionless, so we just send on it.
socket_sendto($socket, $packet, strlen($packet), 0x100, $host, 69);
$buffer = '';
$port = '';
$ret = '';
do
{
// $buffer and $port both come back with information for the ack
// 516 = 4 bytes for the header + 512 bytes of data
socket_recvfrom($socket, $buffer, 516, 0, $host, $port);
// add the block number from the data packet to the ack packet
$packet = chr(0) . chr(4) . substr($buffer, 2, 2);
// send ack
socket_sendto($socket, $packet, strlen($packet), 0, $host, $port);
// append the data to the return variable
// for large files this function should take a file handle as an arg
$ret .= substr($buffer, 4);
}
while(strlen($buffer) == 516); // the first non-full packet is the last.
return $ret;
}
?>