PHP Server Socket shutting down at seemingly random instances - php

I have a server online, and I wrote a PHP Code to act as a Socket Server to handle messages. The messages are coming in from devices that connect to the IP and the Port and send messages.
I found this code example that lets me handle multiple connections at the same time and manage the messages as they come in.
I have modified the code to properly parse the messages that come in from my devices.
Everything has been going well during testing. However, when we did extended testing, the PHP Socket Server would shutdown at seemingly random times and would give the error:
socket_read() failed: reason: Connection reset by Peer at line 104.
Looking at the code I am running, this is the code block for line 104, it starts at the if condition.
if (false === ($buf = socket_read($client, 115200, PHP_BINARY_READ))) {
echo "socket_read() failed: reason: " . socket_strerror(socket_last_error($client)) . "\n";
$GLOBALS['mysqli']->close();
break 2;
}
I actually am not sure how to make sense of this error message. During our testing periods, sometimes that error would show up and shut down the Socket Server while the device is sending a message - but we are sure that the device did not send a Socket Shutdown command. At other times, when we would let the Socket Server just run through, that error would show up.
Does anyone know how to effectively keep a PHP Socket Server from shutting down and keep on running?
I know I can run a cronjob that periodically checks if the socket is being used. However, when the socket server shuts down unexpectedly, the PHP Code can't execute as it still reads that the port is still in use, even if the previous socket server instance is already down and we can no longer connect to it. It takes quite some time until the cronjob manages to put the socket back up again and accept messages - and we need the socket server to run virtually all the time.

"Connection reset by Peer" means the client disconnected unexpectedly. For instance, the user may have closed the client before it was done talking to the server.
Your server code needs to be prepared to handle errors on client sockets, and not quit when it gets an error on a client socket. When you get an error from a client socket it's appropriate to just disconnect that client.

Related

XMPP client receiving server messages

I am implementing my custom XMPP PHP library (Packagist repo) and I have trouble fetching messages (that the client sent) from XMPP server.
Library is using PHP sockets to connect to the server, and I am able to fetch a response from server when initially connecting and authenticating. I can also send a message from server to the client, and that part works.
I can't however receive a message.
This is the code I am using when receiving anything from server:
public function getRawResponse()
{
// Wait max 3 seconds before terminating the socket
socket_set_option($this->socket, SOL_SOCKET, SO_RCVTIMEO, ["sec" => $this->options->getSocketWaitPeriod(), "usec" => 0]);
while ($out = socket_read($this->socket, 2048)) {
echo "*** Data ***\n\n";
echo str_replace("><", ">\n<", $out) . "\n\n";
echo "\n\n************\n";
}
}
This while loop is here to fetch all one-batch responses from the server, and it reads from server while it has something to read, otherwise it terminates the connection.
In the main program I am thus doing a do{...}while(true) and putting this method inside so that it doesn't terminate ever. But still I am not getting any response when sending the other way around, from client back to server.
I have found that I needed to send initial empty presence stanza to server
<presence/>
Once I got the server response back, so did the message responses started incoming.

Shutting down a socket in PHP

I created a cache server and client in php, no need to ask why, just for fun. The implementation works, but a problem occures every time when:
Server starts
Client connects
Server stores data
Client disconnects
When I stop the running server process, after a client disconnects and trying to restart the server, the socket_bind throws an error, that the address is already in use. The client always closes connection after the data has been sent or recieved and when I check if the port is in use via sudo netstat, the port is not listed. The server looks like this:
public function run()
{
$this->socket = $this->ioHandler->createServerSocket();
while ($this->running) {
while ($connection = #socket_accept($this->socket)) {
socket_set_nonblock($connection);
$this->maintainer->maintainBucket($this->bucket);
$this->maintainer->checkBackup(time(), $this->bucket);
try {
$dataString = $this->ioHandler->readFromSocket($connection);
$data = unserialize($dataString);
($this->actionHandler)($data, $this->bucket, $this->ioHandler, $connection);
} catch (Exception $ex) {
$this->ioHandler->writeToSocket($connection, self::NACK);
$this->ioHandler->closeSocket($connection);
}
}
}
}
I think the problem might be that the server shuts down via a simple ctrl+c or a start-stop-daemon --stop --pidfile and the socket is still open and there might be some automatized service that cleans up dead sockets. How can I properly shut down the server? Can I somehow terminate the process by sending an input via STDIN to kill the server socket? Or am I wrong on the issue? The full code is available on github: https://github.com/dude920228/php-cache
Perhaps it's related to TIME_WAIT state. Long story short - socket_close() may close the socket, but there still may be data to send. Until the data is sent, the port will not be available.
More info is:
here
here
and here

Detecting if stream_socket is valid

I have a PHP server-like script that runs indefinitely. It connects to APNS (Apple Push Notification Service) with a stream_socket_client object in PHP.
The problem is that while this works most of the time, I cannot figure out how to validate if the connection to APNS is available when I want to send a push notification. The script receives incoming connections and copies the content to APNS.
When it doesn't work, the script reconnects (the return value of stream_copy_to_stream is 0 on 0 bytes written, which triggers reconnect) and then the next incoming token will succeed, but it logs the following and of course does not deliver the message:
PHP Warning: stream_copy_to_stream(): SSL: An established connection was
aborted by the software in your host machine.
Is there any way to detect the above and thus reconnect to APNS before trying to write to the socket.
And doing this before trying to copy to APNS:
if (!$socketObject) {
// reconnect
}
Does not work, as the object still exists (var_dump will print a description). So how can I check if the connection is still open?
Writing anything to the socket that is not a valid token and payload will cause APNS to disconnect.
The code that performs the writing looks like this:
function writeToAPNS($client) {
return stream_copy_to_stream ( $client, $this->connectionAPNS );
}
Where $client is returned from stream_socket_accept ( $this->socket, -1 ) and $this->socket is a variable containing the local socket object listening for incoming connections. -1 means there is no timeout when waiting for an incoming connection. When it works this function returns the number of bytes written. When it fails it returns 0.
$this->connectionAPNS is the object returned from stream_socket_client when connecting to APNS. This is what I want to check for validity before I perform the stream_copy_to_stream function.
So basically I want to detect if $this->connectionAPNS is valid.
I tried dumping the metadata for the connection object, but it doesn't say anything about the validity, only if it's timed out, protocol type etc.
Did you see this note in the official stream_socket_client documentation?
UDP sockets will sometimes appear to have opened without an error, even if the remote host is unreachable. The error will only become apparent when you read or write data to/from the socket. The reason for this is because UDP is a "connectionless" protocol, which means that the operating system does not try to establish a link for the socket until it actually needs to send or receive data.
Please try this methiod stream_get_meta_data on your connection to try to detect a difference. I can't test it right now, but it might help you. Especially the timed_out property.
Another option to at least mute the error messages, since you are handling them, is to set an appropriate errno on the stream_socket_client.
Well, as explained by M.K., this is how UDP works. And by the way, your code works. Your problem is the warning, which is fairly easy to get rid of by adding an # to your write function.
Your code would then look like :
function writeToAPNS($client) {
return #stream_copy_to_stream ( $client, $this->connectionAPNS );
}

PHP: socket_accept() stops working after it received the first string message

I created a socket server with 10 possible clients by using socket_accept(socket).
It is possible to connect up to 10 times now.
The problem appears after the first client submitted a message to the server which is caught by
$data = #socket_read($clients[$i]['socket'], 1024, PHP_NORMAL_READ);
Then the script tries to listen for clients and messages again by socket_accept and socket_read, but all socket_accept-requests fail with the error string "Invalid argument".
var_dump indicates that the parameter is a resource(14) of type (Socket), though.
Already connected clients can continue using the "server" script as nothing happened and remain connected. Only new clients are unable to connect and the port seems to close (no telnet and netcat requests are possible - connection refused)
Any ideas would be helpful. Thanks!
Discovered that I assumed to disconnect all sockets when the destructor of the socket handler class was called - which terminated all connections once the child process closed.
Removing the socket_shutdown() and socket_close() from the destructor solved the problem.

PHP Socket client - detect server disconnect

I have a socket client that connects to a server and waits for lines of text to be sent from the server.
I open the connection with:
$handle = fsockopen(MY_IP_ADDRESS,MY_PORT,$sockErrno,$sockErrStr);
stream_set_blocking($handle,1);
stream_set_timeout($handle,MY_SOCKET_TIMEOUT);
Then:
while (true) {
$inString = fgets($handle,256);
do some stuff with the received data...
}
This all works fine. There is no particular interval between messages received. Messages may arrive several per second or not for several minutes.
The stream_set_timeout is set to 60 seconds... if no message has been received then I just loop around and queue the fgets again.
Once in a while, the connection is broken for one reason or another.
I want to be able to detect the broken connection so I can begin to attempt to reconnect.
Is there a way to detect a broken connection? Is there something I can examine when a stream timeout occurs that will tell me there is no longer a connection?

Categories