libsodium stream encryption
libsodium has an API dedicated to stream encryption: crypto_secretstream, which is fully documented here: https://download.libsodium.org/doc/secret-key_cryptography/secretstream.html

Using simply crypto_stream_* or OpenSSL aes-256-cfb would be completely insecure. Without any authentication tags, the stream can be tampered with, without any ways to detect that it happened.

crypto_secretstream lets you encrypt and decrypt a sequence of variable-length messages, and prevents tampering, reordering and truncation.

However, if 50 bytes, then 20 bytes are encrypted, you must decrypt 50 bytes, then 20 bytes as well, in this order.

If you are reading data from a TCP connection, you can accumulate it into a fixed-size buffer, and once that buffer is full or you have reached the end of the stream, encrypt or decrypt its content. This will also improve performance and minimize the overhead of authentication tags over encrypting the outcome of ever single read() call.

If the session is interactive, your options are:


Pad messages to the chunk size (sodium_pad(), sodium_unpad()) before encrypting them. This uses more bandwidth, but improves security by revealing less information about the message sizes.
Prefix each ciphertext with its size, so you know how much data has to be read before being decrypted.