feat(tcp): TCPStreamer DataSources, in-process TCPStreamService, stream multiplexing and TCPStreamJoin
Add TCPStreamer/TCPStreamerClient (TCP transport behind the UDPSServerI/UDPSClientI seam), an optional single in-process TCPStreamService serving many streams over worker threads, multiplexed SUBSCRIBE (comma list, stream index in fragmentIdx), and TCPStreamJoin, which merges several streams into one sample-and-hold stream paced by a master. StreamHub takes a comma list of streams over one connection. Includes GTests, E2E scenarios s58-s73 and docs. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
5562877c99
commit
50d85363a3
79 files changed
+12348
-138
No files matched your search
@@ -0,0 +1,160 @@
|
||||
#ifndef TCPS_SERVER_H_
|
||||
#define TCPS_SERVER_H_
|
||||
|
||||
/**
|
||||
* @file TCPSServer.h
|
||||
* @brief TCP transport for the UDPS wire format (producer side).
|
||||
*
|
||||
* TCPSServer carries the normal UDPS framing (17-byte header + CONFIG / DATA
|
||||
* payload, totalFragments always 1) over TCP byte streams. It implements
|
||||
* UDPSServerI so UDPStreamer can publish through it unchanged.
|
||||
*
|
||||
* Threading model: NOT thread-safe, exactly like UDPSServer. Every call must
|
||||
* come from the owner's sender thread. There is no thread per client: sockets
|
||||
* are non-blocking and everything is driven from ServiceClients() / SendData().
|
||||
*
|
||||
* Slow consumers: every client owns a bounded queue of ClientQueueDepth DATA
|
||||
* frames. When it is full the oldest queued DATA frame that is not already
|
||||
* (partially) on the wire is discarded and counted; other clients and the
|
||||
* producer are never affected. A client that makes no progress for
|
||||
* ClientStallTimeout seconds with data queued is disconnected.
|
||||
*
|
||||
* Ordering: a client always sees CONFIG before any DATA. A CONFIG is never
|
||||
* dropped. When a new CONFIG is published, the frames queued behind the one
|
||||
* currently on the wire are stale (encoded for the old layout) and are
|
||||
* discarded, so DATA is never decoded against the wrong CONFIG.
|
||||
*/
|
||||
|
||||
#include "StructuredDataI.h"
|
||||
#include "UDPSProtocol.h"
|
||||
#include "UDPSTransportI.h"
|
||||
|
||||
namespace MARTe {
|
||||
|
||||
class TCPSServer : public UDPSServerI {
|
||||
public:
|
||||
|
||||
/** Default TCP listen port. */
|
||||
static const uint32 TCPS_DEFAULT_PORT = 44500u;
|
||||
/** Default maximum payload bytes per frame. */
|
||||
static const uint32 TCPS_DEFAULT_MAX_PAYLOAD = 60000u;
|
||||
/** Hard ceiling on a frame payload (matches UDPSClient's packet limit). */
|
||||
static const uint32 TCPS_MAX_FRAME_PAYLOAD = 1048576u;
|
||||
/** Default simultaneous clients. */
|
||||
static const uint32 TCPS_DEFAULT_MAX_CLIENTS = 16u;
|
||||
/** Upper bound accepted for MaxClients. */
|
||||
static const uint32 TCPS_MAX_CLIENTS_LIMIT = 1024u;
|
||||
/** Default DATA frames queued per client. */
|
||||
static const uint32 TCPS_DEFAULT_QUEUE_DEPTH = 8u;
|
||||
/** Upper bound accepted for ClientQueueDepth. */
|
||||
static const uint32 TCPS_QUEUE_DEPTH_LIMIT = 4096u;
|
||||
/** Default stall timeout (seconds); 0 disables. */
|
||||
static const uint32 TCPS_DEFAULT_STALL_TIMEOUT_S = 5u;
|
||||
|
||||
TCPSServer();
|
||||
virtual ~TCPSServer();
|
||||
|
||||
/**
|
||||
* @brief Read configuration.
|
||||
*
|
||||
* Keys (all optional):
|
||||
* - Port (uint32) TCP listen port, default 44500. 0 picks an
|
||||
* ephemeral port (see GetPort() after Start()).
|
||||
* - MaxPayloadSize (uint32) 1..1 MiB, default 60000. Sizes Accumulate
|
||||
* batches in the owner; frames larger than 1 MiB are
|
||||
* refused by SendData().
|
||||
* - MaxClients (uint32) 1..1024, default 16. Extra connections
|
||||
* are accepted and closed immediately.
|
||||
* - ClientQueueDepth (uint32) 1..4096, default 8.
|
||||
* - ClientStallTimeout (uint32) Seconds, default 5; 0 disables.
|
||||
* - SendBufferSize (uint32) SO_SNDBUF for client sockets; 0 (default)
|
||||
* keeps the OS default.
|
||||
*/
|
||||
virtual bool Initialise(StructuredDataI &data);
|
||||
|
||||
/** Open the listening socket (idempotent). */
|
||||
virtual bool Start();
|
||||
|
||||
/** Close every socket and free all buffers (idempotent). */
|
||||
virtual bool Stop();
|
||||
|
||||
/**
|
||||
* Accept new clients, drop closed ones, flush queues, evict stalled
|
||||
* clients. Never blocks.
|
||||
*/
|
||||
virtual void ServiceClients();
|
||||
|
||||
/**
|
||||
* Cache the CONFIG and queue it on every connected client. New clients
|
||||
* receive the cached CONFIG on accept.
|
||||
*/
|
||||
virtual bool SendConfig(const uint8 *payload, uint32 payloadSize);
|
||||
|
||||
/**
|
||||
* Queue a DATA frame on every connected client and try to flush.
|
||||
* @return false only if the frame is larger than TCPS_MAX_FRAME_PAYLOAD.
|
||||
*/
|
||||
virtual bool SendData(uint32 counter, const uint8 *payload, uint32 payloadSize);
|
||||
|
||||
virtual bool HasClients() const;
|
||||
virtual bool IsMulticast() const;
|
||||
|
||||
/** @return the bound port once started, otherwise the configured port. */
|
||||
virtual uint16 GetPort() const;
|
||||
|
||||
/** @return number of connected clients. */
|
||||
uint32 GetClientCount() const;
|
||||
|
||||
/** @return DATA frames discarded (all clients, all time) because a client queue was full. */
|
||||
uint64 GetClientDrops() const;
|
||||
|
||||
/** @return clients disconnected by the stall timeout (all time). */
|
||||
uint32 GetStallEvictions() const;
|
||||
|
||||
uint32 GetMaxPayloadSize() const;
|
||||
|
||||
private:
|
||||
struct Slot;
|
||||
struct Client;
|
||||
|
||||
bool CacheConfig(const uint8 *payload, uint32 payloadSize);
|
||||
void AcceptPending();
|
||||
bool Enqueue(Client &c, bool isConfig, const uint8 *frame, uint32 frameSize);
|
||||
bool Flush(Client &c);
|
||||
bool PeerAlive(Client &c);
|
||||
void Evict(Client &c);
|
||||
bool BuildFrame(uint8 type, uint32 counter, const uint8 *payload, uint32 payloadSize);
|
||||
void ReportDrops();
|
||||
|
||||
uint32 port;
|
||||
uint16 boundPort;
|
||||
uint32 maxPayloadSize;
|
||||
uint32 maxClients;
|
||||
uint32 queueDepth;
|
||||
uint32 stallTimeoutS;
|
||||
uint32 sendBufferSize;
|
||||
|
||||
int listenFd;
|
||||
bool started;
|
||||
|
||||
Client *clients;
|
||||
uint32 numClients;
|
||||
|
||||
uint8 *cachedConfig;
|
||||
uint32 cachedConfigSize;
|
||||
uint32 configCounter;
|
||||
|
||||
uint8 *frameBuf; ///< scratch: header + payload built once per call
|
||||
uint32 frameCapacity;
|
||||
uint32 frameSize;
|
||||
|
||||
uint64 stallTicks;
|
||||
uint64 totalDrops;
|
||||
uint64 loggedDrops;
|
||||
uint64 lastDropLogTicks;
|
||||
uint32 stallEvictions;
|
||||
};
|
||||
|
||||
} // namespace MARTe
|
||||
|
||||
#endif // TCPS_SERVER_H_
|
||||
Reference in new issue
Block a user