Skip to content

writeToSocket(): You doing it wrong #207

@webloft

Description

@webloft

The method \PhpMqtt\Client\MqttClient::writeToSocket() currently has an implementation of socket_set_blocking() to ensure correct writing:

This is wrong:

if ($this->settings->shouldUseBlockingSocket()) {
            socket_set_blocking($this->socket, false);
}

And this is wrong too:

if ($result === false || $result !== $length) {

Please referer to the php documentation to stream_set_blocking(), it says:

This affects calls like [fgets()](https://www.php.net/manual/en/function.fgets.php) and [fread()](https://www.php.net/manual/en/function.fread.php) that read from the stream. It says nothing about writing.

In addition it says for fwrite():

Writing to a network stream may end before the whole string is written. Return value of fwrite() may be checked and then shows a loop that calls fwrite() until all bytes are written.

Understanding the problem:

socket_set_blocking() sets the O_NONBLOCK flag. That means it will not block the local process from execution if it tries to read from or write to a receiver.

It has no impact how the data actually can be written over the line. This is made by a underlying I/O-controller. Sending more data than the receiver buffer can handle will result in broken pipe errors (the ones that are silenced via @-operator).

But even if fwrite() returns false, it could be just a temporary problem and must be retried. You may check stream_get_meta_data() for some stream state or even feof() if the connection was really closed.

Long story short: never rely on blocking sockets for write operations.

  • Check the return value by fwrite()
  • Repeat until all data was sent
  • Don't stop after a "false"
  • Only abort after a timeout or by other bad condition

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions