I have a weird issue and I can't seem to find a solution or anything closer to the issue I am having ,
Here is the thing , I have a scoket script run via php on command line, it accepts connection and reads data in json format from mobile app clients and sends appropriate response in json.
Everything works fine except the number of connection does not go above 256 connection.
I would like to know why is that, and how can I solve it ? I have been It on so many days, but no luck!
Here is the script snippet
<?php
date_default_timezone_set("UTC");
$server = stream_socket_server("tcp://192.168.1.77:25003", $errno, $errorMessage);
if (!$server) {
die("$errstr ($errno)");
}
echo "Server started..";
echo "\r\n";
$client_socks = array();
while (true) {
//prepare readable sockets
$read_socks = $client_socks;
$read_socks[] = $server;
//start reading and use a large timeout
if (!stream_select ($read_socks, $write, $except, 10000)) {
die('something went wrong while selecting');
}
//new client
if (in_array($server, $read_socks)) {
$new_client = stream_socket_accept($server);
if ($new_client) {
//print remote client information, ip and port number
echo 'Connection accepted from ' . stream_socket_get_name($new_client, true);
echo "\r\n";
$client_socks[] = $new_client;
echo "Now there are total ". count($client_socks) . " clients";
echo "\r\n";
}
// echo stream_socket_get_name($new_client, true);
//delete the server socket from the read sockets
unset($read_socks[array_search($server, $read_socks)]);
}
$data = '';
$res = '';
//message from existing client
foreach($read_socks as $sock) {
stream_set_timeout($sock, 1000);
while($resp = fread($sock, 25000)) {
$data .= $resp;
if (strpos($data, "\n") !== false) {
break;
}
}
$info = stream_get_meta_data($sock);
if ($info['timed_out']) {
unset($client_socks[array_search($sock, $client_socks)]);
#fclose($sock);
echo 'Connection timed out!';
continue;
}
$client = stream_socket_get_name($sock, true);
if (!$data) {
unset($client_socks[array_search($sock, $client_socks)]);
#fclose($sock);
echo "$client got disconnected";
echo "\r\n";
continue;
}
//send the message back to client
$decode = json_decode($data);
$encode = json_encode($res);
fwrite($sock,$encode."\n");
}
}
P.S.: What I did is, extensive search on the topic, and went over article like these,
http://smallvoid.com/article/winnt-tcpip-max-limit.html and two dozens others.
I have a windows 7 running this thing + wamp 2.5 which runs php 5.5.12
It's nothing to do with your code, it's a "feature" of MS Windows to make you buy the server edition (or upgrade to a different OS). Functionally there's no difference between the server and desktop editions of the NT kernel (some different optimization tweaks) its just a means of ensuring you are complying with the terms of the licence.
Related
I am trying to use a PHP to read data from the local server localhost, but it seems no data is returned from it. Here is my full script.
<?php
$address = "localhost";
echo "Attempting to open the socket at ".$address."...\n";
$fp = fsockopen($address, 49801, $errno, $errstr, 10);
echo "Error number is "; echo $errno; echo ".\n";
echo "Error string is ".$errstr.".\n";
echo "Attempt complete.\n";
if ($fp) {
print "Socket in now open.\n";
syslog(LOG_INFO, "socket.php: Reaching the specified address...");
print "Writing requests...\n"; //Hangs for about 1-2 minutes
fwrite($fp, "POST / HTTP/1.0\r\nUser-Agent: PHP XMLRPC 1.0\r\nHost: ".$address."Content-Type: text/xml\r\nContent-Length: ".strlen($payload)."\r\n\r\n");
$msg = "";
while($data = fread($fp, 32768)) {
$msg= $msg.$data;
}
if (strlen($msg) != 0) {
print "Final message: ***".$msg."***\n";
} else {
print "There is no data received from '".$address."'\n";
}
fclose($fp);
} else {
print "Error\n";
}
?>
Here is the output I am getting in the terminal:
Attempting to open the socket at localhost...
Error number is 0.
Error string is .
Attempt complete.
Socket in now open.
Writing requests...
There is no data received from 'localhost'
As mentioned in the script above, the second last line Writing requests... hangs for about 1 or 2 minutes, then an empty string is appended.
I think it is rather curious because this script works well on HTTP's port 80 or on SSH's port 22. I have restricted access to localhost:49801's configuration, and thus am not able to make any changes to the server's config.
I was however wondering if something was wrong with the server's config so that I don't have to tear out my hair for another day.
By the way, I am running PHP 5.4 on CentOS 7.
Edit
The '111' in "Content-Length: 111" is an arbitrary number that depends on the payload's string length.
Thanks your your help!
You got no reply from your server because he is waiting 111 bytes of data from you.
if you send the right amount of data to your server he will respond accordingly.
Below is working example where I change the Content-Length to 9
and then I send the 9 bites of data using fwrite:
<?php
$address = "localhost";
$payload = "Some data";
echo "Attempting to open the socket at ".$address."...\n";
$fp = fsockopen($address, 49801, $errno, $errstr, 10);
echo "Error number is "; echo $errno; echo ".\n";
echo "Error string is ".$errstr.".\n";
echo "Attempt complete.\n";
if ($fp) {
print "Socket in now open.\n";
syslog(LOG_INFO, "socket.php: Reaching the specified address...");
print "Writing requests...\n";
fwrite($fp, "POST / HTTP/1.0\r\nUser-Agent: PHP XMLRPC 1.0\r\nHost: ".$address.
"\r\nContent-Type: text/xml\r\nContent-Length: ". strlen($payload) ."\r\n\r\n");
//We send the data to the server
fwrite($fp, $payload);
$msg = "";
while($data = fread($fp, 32768)) {
$msg= $msg.$data;
}
if (strlen($msg) != 0) {
print "Final message: ***".$msg."***\n";
} else {
print "There is no data received from '".$address."'\n";
}
fclose($fp);
} else {
print "Error\n";
}
?>
I am trying to learn about sockets in PHP and lots of reading has brought me down the route of stream_socket_server().
I got a basic chat working between two terminals in linux using code similar to what is below and was hoping my next step would be to build a chat or a notification system on the web.
What I expected to happen:
The event listener in eventSource.html would listen for an event in the while loop and output the message received from a linux terminal that was running server.php
What is happening:
Everything from the point of view of eventSource.html is working as it should. So if I was to take away the entire purpose of this and just replace the message with a standard string Hello World then this succesfully outputs <li>message:{Hello World}</li> every second.
However once I try and read data from the terminal nothing is appearing except <li>message: {}</li> every second. It is worth noting that when I run server.php it waits for the client, and when I then run eventSource.html it sucessfully connects.
I am misunderstanding how this works? I assumed that every second in the while loop it would look out for data in that stream.
Or am I going down a completely wrong road in terms of learning sockets.
server.php (I load this from the terminal in linux)
<?php
$PORT = 20226; //chat port
$ADDRESS = "localhost"; //adress
$ssock; //server socket
$csock; //chat socket
$uin; //user input file descriptor
$ssock = stream_socket_server("tcp://$ADDRESS:$PORT"); //creating the server sock
echo "Waiting for client...\n";
$csock = stream_socket_accept($ssock); //waiting for the client to connect
//$csock will be used as the chat socket
echo "Connection established\n";
$uin = fopen("php://stdin", "r"); //opening a standart input file stream
$conOpen = true; //we run the read loop until other side closes connection
while($conOpen) { //the read loop
$r = array($csock, $uin); //file streams to select from
$w = NULL; //no streams to write to
$e = NULL; //no special stuff handling
$t = NULL; //no timeout for waiting
if(0 < stream_select($r, $w, $e, $t)) { //if select didn't throw an error
foreach($r as $i => $fd) { //checking every socket in list to see who's ready
if($fd == $uin) { //the stdin is ready for reading
$text = fgets($uin);
fwrite($csock, $text);
}
else { //the socket is ready for reading
$text = fgets($csock);
if($text == "") { //a 0 length string is read -> connection closed
echo "Connection closed by peer\n";
$conOpen = false;
fclose($csock);
break;
}
echo "[Client says] " .$text;
}
}
}
}
client.php gets loaded from eventSource.html below
<?php
date_default_timezone_set("America/New_York");
header("Content-Type: text/event-stream\n\n");
$PORT = 20226; //chat port
$ADDRESS = "localhost"; //adress
$sock = stream_socket_client("tcp://$ADDRESS:$PORT");
$uin = fopen("php://stdin", "r");
while (1) {
$text = fgets($uin);
echo 'data: {'.$text.'}';
echo "\n\n";
ob_end_flush();
flush();
sleep(1);
}
eventSource.html
<script>
var evtSource = new EventSource("client.php");
evtSource.onmessage = function(e) {
var newElement = document.createElement("li");
newElement.innerHTML = "message: " + e.data;
var div = document.getElementById('events');
div.appendChild(newElement);
}
</script>
<div id="events">
</div>
Here is the issue. I'm working on a tracking script with a China tracking unit (not important). The two files I have is as follows:
7778.php
#!/usr/bin/php -q
<?php
error_reporting(0);
set_time_limit(0);
$address = 'SERVER IP';
$port = 7778;
$q_count = 1;
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);
if (($ret = socket_bind($master, $address, $port)) < 0)
{
echo "socket_bind() failed, reason: " . socket_strerror($ret) . "\n";
}
if (($ret = socket_listen($master, SOMAXCONN)) < 0)
{
echo "socket_listen() failed, reason: " . socket_strerror($ret) . "\n";
}
$read_sockets = array($master);
//---- 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);
foreach($changed_sockets as $socket)
{
if ($socket == $master)
{
if (($client = socket_accept($master)) < 0)
{
echo "socket_accept() failed: reason: " . socket_strerror($msgsock) . "\n";
continue;
}
else
{
array_push($read_sockets, $client);
print "[".date('Y-m-d H:i:s')."] ".$client." CONNECTED "."(".count($read_sockets)."/".SOMAXCONN.")\r\n";
}
}
else
{
$bytes = #socket_recv($socket, $buffer, 2048, 0);
if ($bytes == 0)
{
$index = array_search($socket, $read_sockets);
unset($read_sockets[$index]);
if (socket_close($client))
{
print "Connection closed\r\n";
}
}
else
{
print $buffer."\r\n";
}
print "All Done\r\n";
print "---------------------------------------------------------------------------------------------------------\r\n";
$index = array_search($socket, $read_sockets);
unset($read_sockets[$index]);
if (socket_close($client))
{
print "Connection closed\r\n";
}
}
}
}
?>
and then
port_start.sh with code:
#!/bin/sh
cd /home/path/to/script/
if netstat -tulpn | grep 7778 > /dev/null
then
echo 7778 - Online
else
./7778.php
fi
Now what I would do to test the script is ssh onto my server, navigate to the file directory and type "./7778.php". This will then start my php file, which will open port 7778, my unit will then connect, and my script will dump the data/buffer on the screen. Even if I start the script from the .sh file by typing the following "./port_start.sh" everything works perfect. I can also use Putty and open a RAW connection to my server and the port, and it works. No how it must work is as follows. The unit will make a connection, the script will accept it and receive the data, and then close the connection. My problem occurs when I open the port by running the .sh file from my cronjob with the following code "*/1 * * * * /home/path/to/file/port_start.sh > /dev/null". It will open it, and I can verify that its open, but nothing can connect to it. Why would that be?
When working from cronjob, computer cannot locate the command program. If the program inside /home/root/bin directory, you should call it like/home/root/bin/netstat ... you can locate the progrma by running "locate netstat" and "locate grep". This may solve your problem.
Thank you so much Isa for your response. In my case this was not the problem. Everything opens and works as it should. But I have a little script to check if the port is open. My problem happened there. When I ran the script, it would keep the port open but would kill my script. That's why I could see that the port was still open but nothing would be happening.
The script I use to check the port is as follows if someone ever sits with the same problem:
$errno = "";
$errstr = "";
$fp = #fsockopen($domain, $port, $errno, $errstr, 2);
$status = "";
if (!$fp) {
$status = "<img src='red.gif' alt='Status: Down, Domain: $domain, Port: $port ($errstr)'>\n";
}
else
{
$status = "<img src='green.gif' alt='Status: Up, Domain: $domain, Port: $port'>\n";
}
#fclose($fp);
But again Isa your response made sense but didn't apply to me
I've written a database application using MySQL and PHP on the server side, and Flex on the client side. I use a php socket to have it automatically update all clients whenever changes are made to the database.
The whole system works swimmingly, but every now and then the socket seems to stop responding. The strange thing is that the connection is still good – any changes a client performs are implemented, but the socket doesn't broadcast the message. The socket file isn't throwing any errors (though when I run error_log from the socket those messages appear). Memory use of the socket doesn't change on the server, and no disconnect signal is sent. Stranger still, eventually the socket starts working again, after about half an hour or so. If I restart the socket that also solves the problem.
I'm working on a hacky solution allowing the client to restart the socket if it becomes unresponsive, but that's unsatisfying and open to mistakes. What I'd really like is to learn why this might be happening. Does the socket somehow get "saturated" after a certain number of connections? Should I be doing something to clean up the socket server? I've tried three different physical servers (one local and two online) and the same thing happens, so it's definitely me.
I feel like there's something basic that I'm doing wrong. Here's the code I'm using for the socket server (it's a slightly modified version of socket written by Raymond Fain on kirupa.com, so I've left his original comment at the top):
#!/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', 'Off');
set_time_limit(0);
ob_implicit_flush();
error_log('testing');
$address = 'xxx.xxx.xx.xx';
$port = xxxxx;
function send_Message($allclient, $socket, $buf)
{
$buf = str_replace("\0","",$buf);
//echo "<mbFeed>$buf</mbFeed>\n\0";
foreach($allclient as $client)
{
socket_write($client, "<mbFeed>$buf</mbFeed>\n\0");
}
}
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);
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);
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
{
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
{
$allclients = $read_sockets;
array_shift($allclients);
//any messages starting with ::: are not to be broadcast, and may be used for other things. This message
//usually comes from the client.
if (substr($buffer, 0, 3) == ":::") handleSpecial(substr($buffer, 3));
else
{
//otherwise the message comes from a php file that will be closed, so the socket needs to be closed.
unset($read_sockets[$key]);
unset($changed_sockets[$key]);
socket_close($socket);
send_Message($allclients, $socket, $buffer);
}
}
}
}
}
function handleSpecial($message)
{
error_log($message);
}
?>
As the sockets in use seem to be blocking the call to socket_recv() might not return until the amount of data requested was read. And with this does not handle any other reading sockets, including the accecpting socket.
To get around this use socket_set_nonblock() to make the sockets unblocking. Please note that a call to socket_recv() on a non-blocking socket might return having read less bytes than requested, and therefore the amount of data read shall be tracked for each socket.
I have a problem implementing an API that works with Java, but fails to work with cURL. We've gone through everything so far and there must be something that is different between the requests that Java makes and what we make.
In PHP we can get header data by looking at $_SERVER['HTTP_*'] variables and we can get request body from file_get_contents('php://input'); But we cannot get the exact data sent from user agent to client.
Is it possible to get the full request, that user agent sends, with PHP? Headers and body included? If so, then how?
The only example I found is here, but this one gets the body the way I mentioned, while it gets headers by parsing through $_SERVER, which seems like a hack since it's never 100% of what was actually sent.
All help and tips are appreciated!
for headers you can try apache_request_headers() and for body I dont know other method than file_get_contents('php://input');
Old question, but for anyone needing to do this in the future... The best (probably only) way would be to take full control of the server by being the server.
Set up a socket server listening on port 80 (if this is all you need the server to do), or any other port if 80 is not available.
That way you can capture the request completely unmodified. Examples of basic socket servers are plentiful, here is a simplified version of the latest one I implemented, which will print the full request:
<?php
//Read the port number from first parameter on the command line if set
$port = (isset($argv[1])) ? intval($argv[1]) : 80;
//Just a helper
function dlog($string) {
echo '[' . date('Y-m-d H:i:s') . '] ' . $string . "\n";
}
//Create socket
while (($sock = #socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) === false) {
dlog("socket_create() failed: reason: " . socket_strerror(socket_last_error()));
sleep(1);
}
//Reduce blocking if previous connections weren't ended correctly
if (!socket_set_option($sock, SOL_SOCKET, SO_REUSEADDR, 1)) {
dlog("socket_set_option() failed: reason: " . socket_strerror(socket_last_error($sock)));
exit;
}
//Bind to port
$tries = 0;
while (#socket_bind($sock, 0, $port) === false) {
dlog("socket_bind() failed: reason: " . socket_strerror(socket_last_error($sock)));
sleep(1);
$tries++;
if ($tries>30) {
dlog("socket_bind() failed 30 times giving up...");
exit;
}
}
//Start listening
while (#socket_listen($sock, 5) === false) {
dlog("socket_listen() failed: reason: " . socket_strerror(socket_last_error($sock)));
sleep(1);
}
//Makes it possible to accept several simultaneous connections
socket_set_nonblock($sock);
//Keeps track of active connections
$clients = array();
dlog("server started...");
while(true) {
//Accept new connections
while (($msgsock = #socket_accept($sock)) !== false) {
//Prevent blocking
socket_set_nonblock($msgsock);
//Get IP - just for logging
socket_getpeername($msgsock, $remote_address);
//Add new client to array
$clients[] = array('sock' => $msgsock, 'timeout' => time()+30, 'ip' => $remote_address);
dlog("$remote_address connected, client count: ".count($clients));
}
//Loop existing clients and read input
foreach($clients as $key => $client) {
$rec = '';
$buf = '';
while (true) {
//Read 2 kb into buffer
$buf = socket_read($clients[$key]['sock'], 2048, PHP_BINARY_READ);
//Break if error reading
if ($buf === false) break;
//Append buffer to input
$rec .= $buf;
//If no more data is available socket read returns an empty string - break
if ($buf === '') break;
}
if ($rec=='') {
//If nothing was received from this client for 30 seconds then end the connection
if ($clients[$key]['timeout']<time()) {
dlog('No data from ' . $clients[$key]['ip'] . ' for 30 seconds. Ending connection');
//Close socket
socket_close($client['sock']);
//Clean up clients array
unset($clients[$key]);
}
} else {
//If something was received increase the timeout
$clients[$key]['timeout']=time()+30;
//And.... DO SOMETHING
dlog('Raw data received from ' . $clients[$key]['ip'] . "\n------\n" . $rec . "\n------");
}
}
//Allow the server to do other stuff by sleeping for 50 ms on each iteration
usleep(50000);
}
//We'll never reach here, but some logic should be implemented to correctly end the server
foreach($clients as $key => $client) {
socket_close($client['sock']);
}
#socket_close($sock);
exit;
To start the server on port 8080 just run php filename.php 8080 from a shell.
These aren't "with php" but you might find them useful for your purposes nevertheless
ssldump http://ssldump.sourceforge.net/
mod_dumpio http://httpd.apache.org/docs/2.2/mod/mod_dumpio.html
mod_dumpost https://github.com/danghvu/mod_dumpost