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,174 @@
|
||||
#ifndef TCPSTREAMSERVICE_H_
|
||||
#define TCPSTREAMSERVICE_H_
|
||||
|
||||
/**
|
||||
* @file TCPStreamService.h
|
||||
* @brief One in-process TCP streaming server shared by any number of
|
||||
* TCPStreamer DataSources, served by a pool of worker threads.
|
||||
*
|
||||
* @details Declared once, at the root of the configuration:
|
||||
* <pre>
|
||||
* +StreamService = {
|
||||
* Class = TCPStreamService
|
||||
* Port = 44500
|
||||
* Workers = 2
|
||||
* }
|
||||
* </pre>
|
||||
* and referenced from any number of DataSources:
|
||||
* <pre>
|
||||
* +Fast = { Class = TCPStreamer Service = StreamService StreamName = Fast ... }
|
||||
* +Slow = { Class = TCPStreamer Service = StreamService StreamName = Slow ... }
|
||||
* </pre>
|
||||
*
|
||||
* Wire protocol: plain UDPS framing over TCP, exactly like TCPSServer, plus one
|
||||
* client-to-server frame. Right after connecting, a client sends a SUBSCRIBE
|
||||
* frame (UDPS_TYPE_SUBSCRIBE, payload = stream name, 1..255 bytes). The service
|
||||
* then sends that stream's CONFIG followed by its DATA frames. One connection =
|
||||
* one stream. A connection that does not subscribe within HandshakeTimeout
|
||||
* seconds, or that names an unknown stream, is closed (clients retry).
|
||||
*
|
||||
* Threads: one acceptor plus `Workers` I/O threads. A connection lives on one
|
||||
* worker. Producer threads never touch sockets: they copy each frame into every
|
||||
* subscriber's bounded queue and poke the owning worker through a self-pipe, so
|
||||
* a slow client only loses its own frames and never delays a producer or
|
||||
* another client.
|
||||
*
|
||||
* @par Parameters (all optional)
|
||||
* | Parameter | Type | Default | Description |
|
||||
* |--------------------|--------|---------|-------------|
|
||||
* | Port | uint32 | 44500 | TCP listen port; 0 = ephemeral (see GetBoundPort()). |
|
||||
* | Workers | uint32 | 2 | I/O threads (1..32). |
|
||||
* | MaxClients | uint32 | 64 | Simultaneous connections (1..1024). |
|
||||
* | MaxStreams | uint32 | 32 | Registered streams (1..256). |
|
||||
* | ClientQueueDepth | uint32 | 8 | DATA frames queued per client (1..4096). |
|
||||
* | ClientStallTimeout | uint32 | 5 | Seconds without progress before eviction; 0 disables. |
|
||||
* | HandshakeTimeout | uint32 | 5 | Seconds allowed to send SUBSCRIBE. |
|
||||
* | SendBufferSize | uint32 | 0 | SO_SNDBUF for client sockets; 0 keeps the OS default. |
|
||||
* | CPUMask | uint32 | 0xFFFFFFFF | Affinity of the service threads. |
|
||||
* | StackSize | uint32 | 65536 | Stack of the service threads. |
|
||||
*/
|
||||
|
||||
#include "EmbeddedServiceMethodBinderI.h"
|
||||
#include "ExecutionInfo.h"
|
||||
#include "FastPollingMutexSem.h"
|
||||
#include "MutexSem.h"
|
||||
#include "Object.h"
|
||||
#include "SingleThreadService.h"
|
||||
#include "StructuredDataI.h"
|
||||
#include "TCPSStreamTapI.h"
|
||||
#include "UDPSProtocol.h"
|
||||
|
||||
namespace MARTe {
|
||||
|
||||
class TCPSWorker;
|
||||
class TCPSServiceStream;
|
||||
struct TCPSConn;
|
||||
|
||||
/** Longest stream name accepted in a SUBSCRIBE frame. */
|
||||
static const uint32 TCPS_MAX_STREAM_NAME = 255u;
|
||||
/** Most streams one connection may multiplex. */
|
||||
static const uint32 TCPS_MAX_CONN_STREAMS = UDPS_TCP_MAX_STREAMS;
|
||||
/** Longest SUBSCRIBE payload: a comma separated list of stream names. */
|
||||
static const uint32 TCPS_MAX_SUBSCRIBE_PAYLOAD = UDPS_TCP_MAX_SUBSCRIBE_PAYLOAD;
|
||||
|
||||
class TCPStreamService : public Object, public EmbeddedServiceMethodBinderI {
|
||||
public:
|
||||
CLASS_REGISTER_DECLARATION()
|
||||
|
||||
TCPStreamService();
|
||||
virtual ~TCPStreamService();
|
||||
|
||||
/** Reads the parameters, opens the listening socket and starts the threads. */
|
||||
virtual bool Initialise(StructuredDataI &data);
|
||||
|
||||
/** Acceptor thread entry point; do not call directly. */
|
||||
virtual ErrorManagement::ErrorType Execute(ExecutionInfo &info);
|
||||
|
||||
/** @return the port actually bound. */
|
||||
uint16 GetBoundPort() const;
|
||||
/** @return subscribed connections across all streams. */
|
||||
uint32 GetClientCount() const;
|
||||
uint32 GetStreamCount() const;
|
||||
uint32 GetWorkerCount() const;
|
||||
/** @return DATA frames dropped for slow clients, summed over registered streams. */
|
||||
uint64 GetClientDrops() const;
|
||||
/** @return connections closed by the stall timeout (all time). */
|
||||
uint32 GetStallEvictions() const;
|
||||
/** @return connections closed for a bad / unknown SUBSCRIBE (all time). */
|
||||
uint32 GetRejectedSubscriptions() const;
|
||||
|
||||
/* ---- stream side ---- */
|
||||
/** @return false if a stream with this name is already registered or the table is full. */
|
||||
bool RegisterStream(TCPSServiceStream *s);
|
||||
/** Remove the stream and make its subscribers close. */
|
||||
void UnregisterStream(TCPSServiceStream *s);
|
||||
|
||||
/**
|
||||
* Be told when streams register / unregister. The streams already registered are
|
||||
* replayed to the observer before AddObserver returns. Notifications are serialised
|
||||
* (and may nest on one thread), they never run under the topology lock, and once
|
||||
* RemoveObserver returns no callback is running or will start.
|
||||
* @return false if the observer table is full.
|
||||
*/
|
||||
bool AddObserver(TCPSStreamObserverI *obs);
|
||||
void RemoveObserver(TCPSStreamObserverI *obs);
|
||||
|
||||
/* ---- worker side (internal) ---- */
|
||||
/**
|
||||
* Bind a connection to the streams named in @p streamList (comma separated,
|
||||
* modified in place). The position in the list is the stream index stamped
|
||||
* on every frame. All-or-nothing: @return false if any name is unknown,
|
||||
* duplicated or malformed.
|
||||
*/
|
||||
bool Attach(TCPSConn *c, char8 *streamList);
|
||||
void Detach(TCPSConn *c);
|
||||
void ConnClosed();
|
||||
void NoteEviction();
|
||||
void NoteRejected();
|
||||
uint32 QueueDepth() const;
|
||||
uint64 StallTicks() const;
|
||||
uint64 HandshakeTicks() const;
|
||||
/** Max subscribers a stream may hold. */
|
||||
uint32 MaxClients() const;
|
||||
|
||||
private:
|
||||
void Shutdown();
|
||||
|
||||
uint32 port;
|
||||
uint16 boundPort;
|
||||
uint32 numWorkers;
|
||||
uint32 maxClients;
|
||||
uint32 maxStreams;
|
||||
uint32 queueDepth;
|
||||
uint32 stallTimeoutS;
|
||||
uint32 handshakeTimeoutS;
|
||||
uint32 sendBufferSize;
|
||||
uint32 cpuMask;
|
||||
uint32 stackSize;
|
||||
uint64 stallTicks;
|
||||
uint64 handshakeTicks;
|
||||
|
||||
int listenFd;
|
||||
SingleThreadService acceptThread;
|
||||
bool acceptorStarted;
|
||||
TCPSWorker **workers;
|
||||
uint32 workersCreated;
|
||||
|
||||
/** Most observers (TCPStreamJoin objects) one service can feed. */
|
||||
static const uint32 TCPS_MAX_OBSERVERS = 16u;
|
||||
MutexSem notifyMutex; ///< recursive; serialises observer calls with (un)registration
|
||||
TCPSStreamObserverI *observers[TCPS_MAX_OBSERVERS];
|
||||
uint32 numObservers;
|
||||
|
||||
mutable FastPollingMutexSem topology; ///< guards streams[] and every TCPSConn::stream
|
||||
TCPSServiceStream **streams;
|
||||
uint32 numStreams;
|
||||
|
||||
volatile int32 connCount;
|
||||
volatile int32 evictions;
|
||||
volatile int32 rejected;
|
||||
};
|
||||
|
||||
} // namespace MARTe
|
||||
|
||||
#endif // TCPSTREAMSERVICE_H_
|
||||
Reference in new issue
Block a user