1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-07-27 18:02:17 +03:00

Stream::send() (#6979)

This commit is contained in:
david gauchard
2021-03-15 01:36:20 +01:00
committed by GitHub
parent 4cc1472821
commit c720c0d9e8
48 changed files with 2136 additions and 650 deletions

View File

@ -326,3 +326,196 @@ C++
This assures correct behavior, including handling of all subobjects, which guarantees stability.
History: `#6269 <https://github.com/esp8266/Arduino/issues/6269>`__ `#6309 <https://github.com/esp8266/Arduino/pull/6309>`__ `#6312 <https://github.com/esp8266/Arduino/pull/6312>`__
Streams
-------
Arduino API
Stream is one of the core classes in the Arduino API. Wire, serial, network and
filesystems are streams, from which data are read or written.
Making a transfer with streams is quite common, like for example the
historical WiFiSerial sketch:
.. code:: cpp
//check clients for data
//get data from the telnet client and push it to the UART
while (serverClient.available()) {
Serial.write(serverClient.read());
}
//check UART for data
if (Serial.available()) {
size_t len = Serial.available();
uint8_t sbuf[len];
Serial.readBytes(sbuf, len);
//push UART data to all connected telnet clients
if (serverClient && serverClient.connected()) {
serverClient.write(sbuf, len);
}
}
One will notice that in the network to serial direction, data are transfered
byte by byte while data are available. In the other direction, a temporary
buffer is created on stack, filled with available serial data, then
transferred to network.
The ``readBytes(buffer, length)`` method includes a timeout to ensure that
all required bytes are received. The ``write(buffer, length)`` (inherited
from ``Print::``) function is also usually blocking until the full buffer is
transmitted. Both functions return the number of transmitted bytes.
That's the way the Stream class works and is commonly used.
Classes derived from ``Stream::`` also usually introduce the ``read(buffer,
len)`` method, which is similar to ``readBytes(buffer, len)`` without
timeout: the returned value can be less than the requested size, so special
care must be taken with this function, introduced in the Arduino
``Client::`` class (cf. AVR reference implementation).
This function has also been introduced in other classes
that don't derive from ``Client::``, e.g. ``HardwareSerial::``.
Stream extensions
Stream extensions are designed to be compatible with Arduino API, and
offer additional methods to make transfers more efficient and easier to
use.
The serial to network transfer above can be written like this:
.. code:: cpp
serverClient.sendAvailable(Serial); // chunk by chunk
Serial.sendAvailable(serverClient); // chunk by chunk
An echo service can be written like this:
.. code:: cpp
serverClient.sendAvailable(serverClient); // tcp echo service
Serial.sendAvailable(Serial); // serial software loopback
Beside reducing coding time, these methods optimize transfers by avoiding
buffer copies when possible.
- User facing API: ``Stream::send()``
The goal of streams is to transfer data between producers and consumers,
like the telnet/serial example above. Four methods are provided, all of
them return the number of transmitted bytes:
- ``Stream::sendSize(dest, size [, timeout])``
This method waits up to the given or default timeout to transfer
``size`` bytes to the the ``dest`` Stream.
- ``Stream::sendUntil(dest, delim [, timeout])``
This method waits up to the given or default timeout to transfer data
until the character ``delim`` is met.
Note: The delimiter is read but not transferred (like ``readBytesUntil``)
- ``Stream::sendAvailable(dest)``
This method transfers all already available data to the destination.
There is no timeout and the returned value is 0 when there is nothing
to transfer or no room in the destination.
- ``Stream::sendAll(dest [, timeout])``
This method waits up to the given or default timeout to transfer all
available data. It is useful when source is able to tell that no more
data will be available for this call, or when destination can tell
that it will no be able to receive anymore.
For example, a source String will not grow during the transfer, or a
particular network connection supposed to send a fixed amount of data
before closing. ``::sendAll()`` will receive all bytes. Timeout is
useful when destination needs processing time (e.g. network or serial
input buffer full = please wait a bit).
- String, flash strings helpers
Two additional classes are provided.
- ``StreamPtr::`` is designed to hold a constant buffer (in ram or flash).
With this class, a ``Stream::`` can be made from ``const char*``,
``F("some words in flash")`` or ``PROGMEM`` strings. This class makes
no copy, even with data in flash. For flash content, byte-by-byte
transfers is a consequence when "memcpy_P" cannot be used. Other
contents can be transferred at once when possible.
.. code:: cpp
StreamPtr css(F("my long css data")); // CSS data not copied to RAM
server.sendAll(css);
- ``S2Stream::`` is designed to make a ``Stream::`` out of a ``String::`` without copy.
.. code:: cpp
String helloString("hello");
S2Stream hello(helloString);
hello.reset(0); // prevents ::read() to consume the string
hello.sendAll(Serial); // shows "hello"
hello.sendAll(Serial); // shows nothing, content has already been read
hello.reset(); // reset content pointer
hello.sendAll(Serial); // shows "hello"
hello.reset(3); // reset content pointer to a specific position
hello.sendAll(Serial); // shows "lo"
hello.setConsume(); // ::read() will consume, this is the default
Serial.println(helloString.length()); // shows 5
hello.sendAll(Serial); // shows "hello"
Serial.println(helloString.length()); // shows 0, string is consumed
``StreamString::`` derives from ``S2Stream``
.. code:: cpp
StreamString contentStream;
client.sendSize(contentStream, SOME_SIZE); // receives at most SOME_SIZE bytes
// equivalent to:
String content;
S2Stream contentStream(content);
client.sendSize(contentStream, SOME_SIZE); // receives at most SOME_SIZE bytes
// content has the data
- Internal Stream API: ``peekBuffer``
Here is the method list and their significations. They are currently
implemented in ``HardwareSerial``, ``WiFiClient`` and
``WiFiClientSecure``.
- ``virtual bool hasPeekBufferAPI ()`` returns ``true`` when the API is present in the class
- ``virtual size_t peekAvailable ()`` returns the number of reachable bytes
- ``virtual const char* peekBuffer ()`` returns the pointer to these bytes
This API requires that any kind of ``"read"`` function must not be called after ``peekBuffer()``
and until ``peekConsume()`` is called.
- ``virtual void peekConsume (size_t consume)`` tells to discard that number of bytes
- ``virtual bool inputCanTimeout ()``
A ``StringStream`` will return false. A closed network connection returns false.
This function allows ``Stream::sendAll()`` to return earlier.
- ``virtual bool outputCanTimeout ()``
A closed network connection returns false.
This function allows ``Stream::sendAll()`` to return earlier.
- ``virtual ssize_t streamRemaining()``
It returns -1 when stream remaining size is unknown, depending on implementation
(string size, file size..).