How to handle socket broken pipe [error 32] in php? - php

I have socket handler class, which is used to communicate to client with specific ip and port with the help of several socket functions. At the very first time when I am using writetosocket() function, it's working perfectly.
But when I am restarting client(with ip and port). And tries to use writetosocket() it returns me broken pipe error with error code 32. but after some successful execution of socket_write function. Means I am getting this error after some time duration, when I am writing data on socket. I read some solutions and tried most common solution where I am using socket_shutdown and socket_close to terminate socket connection properly whenever I am finding client is not responding. And after that I am again calling startconnection, which is giving me new socket. But still I am getting broken pipe error.
function startconnection(){
/* Create a socket in the AF_INET family, using SOCK_STREAM for TCP connection */
$this->socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if ($this->socket === false) {
$errorcode = socket_last_error();
$errormsg = socket_strerror($errorcode);
echo "$errorcode : $errormsg";
return false;
}
else {
echo "Socket successfully created.";
}
/* Accept incoming connections */
$this->result = socket_connect($this->socket, $this->ipaddress, $this->port);
if($this->result === false){
$errorcode = socket_last_error();
$errormsg = socket_strerror($errorcode);
echo "$errorcode : $errormsg";
return false;
}
else {
echo "successfully connected to $this->ipaddress, $this->port";
}
return true;
}
function writetosocket($input){
$sent = socket_write($this->socket, $input, strlen($input));
if($sent === false) {
$errorcode = socket_last_error();
$errormsg = socket_strerror($errorcode);
echo "$errorcode : $errormsg";
return false;
}
else {
echo "Message Sent : $input";
}
return true;
}
Help me to understand and resolve this problem so that function can handle broken pipe error.

You are getting that error because the server socket has closed and is no longer listening and the client socket is attempting to send data to the server socket after it has been closed but before the port is free to be used again (while it is in TIME_WAIT).
The Server Socket and the Client Socket both go through different steps before they become available for I/O:
SERVER
socket()
bind()
listen()
accept()
Client
socket()
bind() [optional, see below]
connect() [does an implicit bind on an ephemeral port if not already bound]

Related

Send data from web server to perl socket listener

I try to send data from php web script to local perl socket listener.
Here is perl server code:
#!/usr/bin/perl
use IO::Socket::INET;
use strict;
$| = 1;
my $web = new IO::Socket::INET (
LocalHost => '127.0.0.1',
LocalPort => '9001',
Proto => 'tcp',
Listen => 5,
Reuse => 1
) or die "ERROR in Socket Creation : $!\n";
while ($web->accept()) {
my $web_address = $web->peerhost();
my $web_port = $web->peerport();
print "Accepted New Web Client Connection From : $web_address, $web_port\n";
my $data = <$web>;
chomp ($data);
print "Data from web: $data\n";
}
And here is php code:
if(!($sock = socket_create(AF_INET, SOCK_STREAM, 0)))
{
$errorcode = socket_last_error();
$errormsg = socket_strerror($errorcode);
die("Couldn't create socket: [$errorcode] $errormsg \n");
}
echo "Socket created \n";
if(!socket_connect($sock , '127.0.0.1' , 9001))
{
$errorcode = socket_last_error();
$errormsg = socket_strerror($errorcode);
die("Could not connect: [$errorcode] $errormsg \n");
}
echo "Connection established \n";
$message = "GET / HTTP/1.1\r\n\r\n";
if( !socket_send ($sock , $message , strlen($message) , 0))
{
$errorcode = socket_last_error();
$errormsg = socket_strerror($errorcode);
die("Could not send data: [$errorcode] $errormsg \n");
}
echo "Message send successfully \n";
Here is output of perl script:
Accepted New Web Client Connection From : ,
Data from web:
And here is output of php script:
Socket created
Connection established
Message send successfully
So, why it actually don't send the data?
The $web->accept() only creates and returns an object, which can be used to read the handle (for the socket). You are attempting to read with $web itself, which it cannot do. In other words, <$web> does not read from the socket. The PHP client has sent its message which is sitting in the buffer waiting to be read.
Further, as the PHP client prints it is filling up the buffer, since nothing is emptying it (reading) on the other end. If it prints enough at one point the buffer will get full and the next print will hang, just waiting. This is a common source of errors, when the buffer is not being read from orderly.
Your code needs small changes
if ( my $listen = $web->accept() ) {
my ($buff, $recd);
while (defined($buff = <$listen> ) {
chomp($recd = $buff);
# process the line in $recd
}
} else { warn "Error with the socket -- $!"; }
The while around $buff = <$listen> is needed to read more than one line as they are sent. For multiple connections that you allow all of this should be in a while loop, which you have. In a nutshell, for the one-line-message in your posted example
my $listen = $web->accept();
my $recd = <$listen>;
chomp($recd);
print "$recd\n";
This is as far as Perl code goes. I don't know how PHP routines work (they seem to be OK to me).
While IO::Socket provides basic information, there is a lot more scattered around Perl documentation. For example, there is a server example using IO::Socket in
Perl IPC, by the very end of that page.
Please add use warnings; at the beginning. It is actually extremely useful. I suspect that it would have warned you of this.

PHP: TCP sockets, 'unable to bind address'

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.

PHP Warning: socket_read(): unable to read from socket [104]: Connection reset by peer

I use socket_create() to create socket Resource,then I bind an IP address to it by socket_bind(), its works fine;
But after a while(more than 30 minutes) in line socket_read($sock, 2048) this error thrown :
"PHP Warning: socket_read(): unable to read from socket [104]: Connection reset by peer in test.php on line 198".
This is my simplified code:
$this->sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
// check if tcp socket ceated or not
if ($this->sock === false) {
$errorcode = socket_last_error();
$errormsg = socket_strerror($errorcode);
die("Couldn't create socket: [$errorcode] $errormsg");
}
// Bind the source address
socket_bind($this->sock, $this->ip);
// Connect to destination address
socket_connect($this->sock, $this->mxHost, $this->port);
$buf = socket_read($this->sock, 2048);
This piece of code make a SMTP(port 25) connection to a MX Host at the other side.
Maybe it's the fault on the other side of your connection, But how can I detect that the other side isn't ready for the connection right now. In the other word how can I find out the "Connection reset by peer" occurred?
You should check if socket_connect() was successful before reading from it.
so you could rewrite your code like this:
-- UPDATED --
$this->sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
// Bind the source address
socket_bind($this->sock, $this->ip);
// Connect to destination address
if (socket_connect($this->sock, $this->mxHost, $this->port)) {
// suppress the warning for now since we have error checking below
$buf = #socket_read($this->sock, 2048);
// socket_read() returns a zero length string ("") when there is no more data to read.
// This indicates that the socket is closed on the other side.
if ($buf === '')
{
throw new \Exception('Connection reset by peer');
}
} else {
// Connection was not successful. Get the last error and throw an exception
$errorMessage = socket_strerror(socket_last_error());
throw new \Exception($errorMessage);
}
Hmm... Your peer reset the connection. Maybe it's the fault on the other side of your connection ? A timeout mechanism may be running on the other side.
You could test the socket before you write to it with the socket_last_error function and recreate the connection on a disconnection.

PHP Socket Disconnecting Randomly

I'm using a PHP Socket to listen on port 6000 for incoming connections and its working perfectly 99% percent of the time but 1% of the time the client is getting a connection error when sending a request to the server. I created a different script to ping the socket on port 6000 every second in an infinite loop and write the result to a log file so I can see if its breaking, and out of 78,000 Successful pings, 23 Failed.
There must be some small logic error with my code which is causing this. If anyone has any ideas its much appreciated.
Socket:
if(!($sock = socket_create(AF_INET, SOCK_STREAM, 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, "0.0.0.0" , 6000) )
{
$errorcode = socket_last_error();
$errormsg = socket_strerror($errorcode);
die("Could not bind socket : [$errorcode] $errormsg \n");
}
echo "Socket bind OK \n";
if(!socket_listen ($sock , 10))
{
$errorcode = socket_last_error();
$errormsg = socket_strerror($errorcode);
die("Could not listen on socket : [$errorcode] $errormsg \n");
}
echo "Socket listen OK \n";
echo "Waiting for incoming connections... \n";
//start loop to listen for incoming connections
while (true)
{
//Accept incoming connection - This is a blocking call
$client = socket_accept($sock);
//read data from the incoming socket
$input = "";
$input = socket_read($client, 10000000);
if ($input != "")
{
// do my logic here with $input
}
}
socket_close($sock);
EDIT: No, I'm not using CMD to ping. This is my PHP script which is doing the pinging:
<?php
$host = '0.0.0.0';
$port = 6000;
$waitTimeoutInSeconds = 1;
while(true)
{
if($fp = fsockopen($host,$port,$errCode,$errStr,$waitTimeoutInSeconds))
{
$file = 'log.txt';
$current = file_get_contents($file);
$today = date("Y-m-d_H:i:s");
$current .= $today . " - SUCCESS\n";
file_put_contents($file, $current);
}
else
{
$file = 'log.txt';
$current = file_get_contents($file);
$today = date("Y-m-d_H:i:s");
$current .= $today . " - FAILED\n";
file_put_contents($file, $current);
}
fclose($fp);
sleep(1);
}
?>
For an actual transaction, the client is only connected for a split second while it sends through an xml request in raw text, then it does some logic which takes less than a second. Since its failing on the ping test though, that means my listener is breaking for a second for one reason or another does it not?
I'm not sure if I understand correctly.
You say about 0,03% of your pings failed. Is this your problem? If these are real pings (ping.exe from cmd.exe) then it has nothing to do with your logic. It's the network. (Is the host on WIFI?)
If you are convinced it's your logic:
If someone connects, how long is he connected? And what happens to new requests while connected to the previous client? I think you may find your answer here.
Also try to do a test with a client that continuously connects and sends dummy data, in stead of pinging. And log what responses the client is receiving.

Wanting to run a section of php code repeatedly but without losing scope

So I've been able to use AJAX to repeatedly refresh a div on my website, using the following code:
var $container = $("#content");
var refreshId = setInterval(function()
{
$container.load('toad.php').fadeOut("slow").load('response.php').fadeIn("slow"); ;
}, 2000);
This works fine, toad.php gets executed every 2 seconds and the contents update.
toad.php contains the following code currently:
<?php
if ( !($sock = socket_create(AF_INET, SOCK_STREAM, 0)) ) {
$errorcode = socket_last_error();
$errormsg = socket_strerror($errorcode);
die("Couldn't create socket: [$errorcode] $errormsg \n");
}
echo "Socket created \n";
if (!socket_connect($sock, '127.0.0.1', 45000)) {
//$errorcode = socket_last_error();
//$errormsg = socket_strerror($errorcode);
echo "No sensor available to connect to.\n";
//die("Could not connect: [$errorcode] $errormsg \n");
}
echo "Connection established \n";
//Now receive reply from server
if (false !== ($bytes = socket_recv($sock, $buf, 1200, MSG_WAITALL))) {
echo "Read $bytes bytes from socket_recv(). Closing socket...";
}
else {
echo "socket_recv() failed; reason: " . socket_strerror(socket_last_error($sock)) . "\n";
}
socket_close($sock);
echo $buf . "\n";
echo "OK.\n";
?>
The issue with this is that the socket is created and connected to every single time the div is refreshed.
If I don't have the socket_create and socket_connect functions in toad.php then the socket_recv function doesn't know about the socket and doesn't work.
My question is how can I get the socket receive code to loop and update the contents of the div without having to re create and connect to the socket every time?
Thanks!
If you can rewrite the server your connecting to to use websocket, you could just connect directly from the browser using socket.io.
http://socket.io/
As others have said, maintaining a persistent PHP connection can be tricky, but if running a NodeJS (or similar) script to handle client connections isn't possible you could serve the websockets from that same PHP script.
Try this approach:
http://devzone.zend.com/209/writing-socket-servers-in-php/
Your toad.php script would run on the command line, listening to your existing socket server, then serving the data to it's own socket server which the browser connects to directly with websocket.

Categories