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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions