I created a PHP Socket Server with PHP_NORMAL_READ mode. So, a message to the server is read when it ends with \n or \r. I tried it by connecting to the server with multiple telnet instances, and it works great.
However, when I connect to the server with 1 flash application and 1 telnet application (I first start the flash one), the flash one seems to make the server hang - the server is getting stuck somewhere and no longer receiving data from eg. the telnet client.
Because anyone can code a flash client, this has to be fixed server side. The server's code:
<?php
// config
$timelimit = 60; // amount of seconds the server should run for, 0 = run indefintely
$port = 9000; // the port to listen on
$address = $_SERVER['SERVER_ADDR']; // the server's external IP
$backlog = SOMAXCONN; // the maximum of backlog incoming connections that will be queued for processing
// configure custom PHP settings
error_reporting(1); // report all errors
ini_set('display_errors', 1); // display all errors
set_time_limit($timelimit); // timeout after x seconds
ob_implicit_flush(); // results in a flush operation after every output call
//create master IPv4 based TCP socket
if (!($master = socket_create(AF_INET, SOCK_STREAM, SOL_TCP))) die("Could not create master socket, error: ".socket_strerror(socket_last_error()));
// set socket options (local addresses can be reused)
if (!socket_set_option($master, SOL_SOCKET, SO_REUSEADDR, 1)) die("Could not set socket options, error: ".socket_strerror(socket_last_error()));
// bind to socket server
if (!socket_bind($master, $address, $port)) die("Could not bind to socket server, error: ".socket_strerror(socket_last_error()));
// start listening
if (!socket_listen($master, $backlog)) die("Could not start listening to socket, error: ".socket_strerror(socket_last_error()));
//display startup information
echo "[".date('Y-m-d H:i:s')."] SERVER CREATED (MAXCONN: ".SOMAXCONN.").\n"; //max connections is a kernel variable and can be adjusted with sysctl
echo "[".date('Y-m-d H:i:s')."] Listening on ".$address.":".$port.".\n";
$time = time(); //set startup timestamp
// init read sockets array
$read_sockets = array($master);
// continuously handle incoming socket messages, or close if time limit has been reached
while ((!$timelimit) or (time() - $time < $timelimit)) {
$changed_sockets = $read_sockets;
socket_select($changed_sockets, $write = null, $except = null, null);
foreach($changed_sockets as $socket) {
if ($socket == $master) {
if (($client = socket_accept($master)) < 0) {
continue;
} else {
array_push($read_sockets, $client);
}
} else {
$data = #socket_read($socket, 1024, PHP_NORMAL_READ); //read a maximum of 1024 bytes until a new line has been sent
if ($data === false) { //the client disconnected
$index = array_search($socket, $read_sockets);
unset($read_sockets[$index]);
socket_close($socket);
} elseif ($data = trim($data)) { //remove whitespace and continue only if the message is not empty
echo "we received: ".$data."\n\n";
//handleData($data, $socket);
}
}
}
}
socket_close($master); //close the socket
echo "[".date('Y-m-d H:i:s')."] SERVER CLOSED.\n";
//function to write to the flash client
function flash_write($socket, $msg) {
socket_write($socket, $msg.chr(0x0));
}
?>
Does anyone know what may cause this? I tried changing the timeout on the socket_select from none to 0 (instant return), but that didn't seem to change anything.
Could you post the source of the flash client? That would show what the problem is?
Are you sure the last thing you send from the flash client is a \n ?
Otherwise the server would block on socket_read() as the flash client socket can be read without blocking (triggered socket_select()), but doesn't send the ending \n.
One thing to help you debug: error_reporting(1) does not enable the display of all errors. Look at the documentation at http://us3.php.net/manual/en/function.error-reporting.php. You need something like error_reporting(E_ALL).
Related
I have an HL7 machine that sends data via TCP on a specified port. I want to continuously listen on that port and display any data received on the screen.
I have this which creates a connection but in my scenario, connection is created by the HL7 machine which then starts sending.
// host and port to connect to
$host = "localhost";
$port = 9876;
// connect to the port
$fp = fsockopen($host, $port, $errno, $errstr);
set_time_limit(0);
// if connection not successfull, display error
if (!$fp)
{
die("Error: Could not open socket for connection!");
}
else
{
// connection successfull, listen for data (1024 bytes by default)
$got = fgets($fp);
// display the data
echo $got;
}
fclose($fp);
You should wait (block) for a socket connection from the HL7 machine. When a connection is received you should process the data then wait for another connection.
If several connections are made at once and your processing of the HL7 message takes a bit of time, it may be wise to process the message/data from the socket in a new thread.
<?php
$condition = true;
$socket = socket_create_listen(port);
socket_set_block($socket);
while (condition) {
socket_accept($socket);
// read data from socket
// condition to break from listening
}
?>
Reference: http://php.net/manual/en/function.socket-set-block.php
i've seen other people with this problem, but maybe i can explain my situation and you can point out where the issue might be.
im getting a 'Warning : socket_bind(): unable to bind address [98]: Address already in use' error.
the situation is this. I am using a web application to trigger another program to perform tasks (from a webpage interface). The results of that program are sent through a socket to my web application that is listening on a socket.
first i create and open the socket, then i trigger the other program, then when that program is finished it should send its results back through the socket.
it works fine the first try. Then the next try (i trigger this process many times) i get the above socket bind error when trying to open the socket, obviously the socket is still bound.
i wait about a minute and i can successfully run the process again. I think the socket connection timesout.
I dont know if the problem is because of the way i have structure my socket code, or if the problem is in the external program that i am triggering. I dont know much about the internals of the external program as its a jar file built by someone else.
heres the code i use for creating and handling the socket. I just used an example on php.net and altered it for my needs.
$port1 = 15000;
// configure the socket
error_reporting(E_ALL);
set_time_limit(0);
ob_implicit_flush();
$address = '127.0.0.1';
$port2 = 54321;
$sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
$error = 'none';
if ($sock) {
if (socket_bind($sock, $address, $port2)) {
if (socket_listen($sock, 5)) {
// trigger external process
if (start_calibration()) {
$buf = array();
// listen to the socket for incoming messages
do {
// if incomming connection is not accepted break out and close socket
if (($msgsock = socket_accept($sock)) === false) {
break;
}
do {
// if cant read socket then break out and close socket
if (false === ($buf = socket_read($msgsock, 2048, PHP_BINARY_READ))) {
break 2;
}
$buf = unpack('C*', $buf);
socket_close($msgsock);
break 2;
} while (true);
socket_close($msgsock);
} while (true);
socket_close($sock);
// code to handle data recieved through the socket
}
else {
// start_calibration failed
$error = 'start_calibration failed';
socket_close($sock);
}
}
else {
// socket_listen failed
$error = 'socket_listen failed';
socket_close($sock);
}
}
else {
// socket_bind failed
$error = 'socket_bind failed';
socket_close($sock);
}
}
else {
// socket_create failed
$error = 'socket_create failed';
}
$data['error'] = $error;
echo json_encode($data);
also, is there is a more efficient way to handle the closing of sockets if there is problems with lines like 'socket_bind', 'socket_listen' etc?
Did you try to set the flag SO_REUSEADDR on your socket?
There's a sample in the socket_set_option's documentation.
I'm coding a php socket server script which is running on ubuntu.
It works well, clients can connect/disconnect to this server.
But the server is shutting down silently when a client connect to this server that didn't have any client connected for a long time.
I setted up timeout to 0 (unlimited) but the server is stoping without any errors or messages... like this.
root#exfl:/home/projectap/sec/server_core# php socket_server.php
[exfl.kr] Starting AbsolutePitch socket server...
[2014.06.21 16:50:58] Server is listening. PID: 6442
[2014.06.21 17:28:48] Client [192.168.0.1:8795] connected to the server.
root#exfl:/home/projectap/sec/server_core#
I coded for this server like this.
<?php
set_time_limit(0);
error_reporting(E_ALL);
ini_set("memory_limit","2048M");
ini_set("max_execution_time", "0");
if(posix_getpid() == true) {
echo "[exfl.kr] Starting AbsolutePitch socket server...\n";
} else {
echo getTimeToStr()."Server is already running.\n";
}
$cSock = array();
$socketsInformation = array();
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
$bind = socket_bind($socket, "0.0.0.0", "24180");
$listen = socket_listen($socket, 5);
echo getTimeToStr()."Server is listening. PID: ".posix_getpid()."\n";
while(true) {
$sockArr = array_merge(array($socket), $cSock);
if(socket_select($sockArr, $tWrite = null, $tExcept = null, null) > 0) {
foreach($sockArr as $sock){
if($sock == $socket){
$tSock = socket_accept($socket);
socket_getpeername($tSock, $sockIp, $sockPort);
array_push($cSock, $tSock);
array_push($socketsInformation, array("SOCKETINDEX"=>(count($cSock)-1), "IP"=>$sockIp, "USERID"=>"", "STATUS"=>"", "AUTH"=>false));
echo getTimeToStr()."Client [".$sockIp.":".$sockPort."] connected to the server.\n";
} else {
...
}
}
}
}
echo getTimeToStr()."Server closed.\n";
...
?>
When the server stops suddenly, it isn't outputing a "Server closed" message..
Please help.
Sorry for my bad English.
You may want to try socket_set_options() with SO_KEEPALIVE. To know more about your options use the socket_get_options page:
https://www.php.net/manual/en/function.socket-get-option.php
To know more about the usage of socket_set_options() use:
https://www.php.net/manual/en/function.socket-set-option.php
Issue at Hand: Intercepting a print request and modifying the data within the job to add content to it.
Solution so far: Here's the solution that has worked for the windows xp machines
1. Redirect the default printer to a raw TCP/IP port say 9100.
2. Write a basic socket server which listens on the port 9100 and accepts connections when they occur.
3. Read from the socket and modify the content before writing to a virtual printer which redirects to actual port that the default printer was on.
Problem: Steps 1 and 2 do not seem to work on windows 7.. Can someone please help..?
Here is the socket server code(very basic)...
<?php
// set some variables
$host = "127.0.0.1";
$port = 9100;
// don't timeout!
set_time_limit(0);
if(($sock = socket_create(AF_INET, SOCK_STREAM, 0)) < 0)
{
echo "failed to create socket: ".socket_strerror($sock)."\n";
exit();
}
if(($ret = socket_bind($sock, $host, $port)) < 0)
{
echo "failed to bind socket: ".socket_strerror($ret)."\n";
exit();
}
if( ( $ret = socket_listen( $sock, 0 ) ) < 0 )
{
echo "failed to listen to socket: ".socket_strerror($ret)."\n";
exit();
}
socket_set_nonblock($sock);
echo "waiting for clients to connect\n";
while (true)
{
$connection = #socket_accept($sock);
if ($connection === false)
{
usleep(100);
}elseif ($connection > 0)
{
//handle_client($sock, $connection);
}else
{
echo "error: ".socket_strerror($connection);
die;
}
}
So at this point, when a print job happens to a default printer, the server should accept the connection but that is not the case. A basic socket client which performs a socket_create, socket_connect and sends a socket_write works fine.. But the same thing does not happen when a print job to the same port is being sent. It works fine on windows XP. Can someone please help?
Found that on windows 7 IPV6 sockets are used by printers by default. If you run a microsoft fixit to prefer IPV4 over IPV6 or create a IPV6 socket it should work. – user2693294
Below is a PHP script that I have created to listen for incoming messages (XML strings).
That PHP script is hosted on my local home server on port 13330 so that's where I would listen for incoming requests, right? So I create the socket and bind it to the address the file is located on.
I receive this error: Warning: socket_bind(): unable to bind address [0]: Only one usage of each socket address (protocol/network address/port) is normally permitted.
I would appreciate it if anyone could let me know why I might be seeing that.
Thanks
createSocketServer();
function createSocketServer() {
// Set time limit to indefinite execution
set_time_limit (0);
// Set the ip and port we will listen on
$address = '127.0.0.1';
$port = 13330;
// Create a TCP Stream socket
$sock = socket_create(AF_INET, SOCK_STREAM, 0);
echo '<p>Socket created</p>';
// Bind the socket to an address/port
socket_bind($sock, $address, $port) or die('Could not bind to address');
echo '<p>Socket binded</p>';
// Start listening for connections
socket_listen($sock);
echo '<p>Socket listening</p>';
/* Accept incoming requests and handle them as child processes */
$client = socket_accept($sock);
// Read the input from the client – 1024 bytes
$input = socket_read($client, 1024);
// Strip all white spaces from input
$output = ereg_replace("[ \t\n\r]","",$input).chr(0);
echo $output;
}
use this code before binding:
if (!socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1)) {
echo socket_strerror(socket_last_error($socket));
exit;
}
for reference http://www.php.net/manual/en/function.socket-bind.php
You can also check http://www.php.net/manual/en/function.socket-set-option.php for details