Disclaimer:
The UDP client is not implemented by me. Only the server and the TCP client (subscriber) were developed as part of this project. For testing, I used this repository.
The server listens on both TCP and UDP protocols, using two separate sockets—one for each protocol.
For I/O multiplexing, poll() is used with three initial pollfd entries:
- Standard input (
stdin) - TCP socket
- UDP socket
The server runs continuously with the following behavior:
-
Standard Input Handling
- If input is available on
stdin, the server checks for theexitcommand. - This is the only accepted server-side command and causes a clean shutdown.
- If input is available on
-
TCP Connection Handling
- When data is available on the TCP socket, a new client connection is accepted.
- The Nagle algorithm is disabled (
TCP_NODELAYis set). - The client sends its
ID, which is checked against existing active clients.- If the ID is unique, it is registered in a mapping of IDs to file descriptors.
- The server informs the client whether the connection is accepted.
- If the ID is already in use, the client is instructed to terminate.
-
UDP Message Handling
- When data is available on the UDP socket, the server receives a message from a UDP client.
- The message is parsed into an internal structure and transformed into a
tcp_message_tstructure for TCP delivery. - The server extracts the topic and checks all TCP client subscriptions using regular expressions (to support wildcards).
- If a match is found, the client ID is added to a topic-to-subscribers map.
- The decoded message is sent to all currently connected TCP clients subscribed to the topic.
-
TCP Client Commands
- When a connected TCP client sends data, the server processes subscribe/unsubscribe commands.
- If the client disconnects, it is removed from active tracking.
- For each command, the server determines whether it's a regular or wildcard-based topic and updates subscriptions accordingly.
Upon receiving the exit command from stdin, the server closes all open sockets and terminates gracefully.
Upon startup, the subscriber:
- Opens a TCP socket and disables the Nagle algorithm.
- Connects to the server and sends its
ID. - Awaits confirmation that it can proceed (based on unique ID check).
If approved, the client enters a loop using poll() for I/O multiplexing, handling two main cases:
-
User Commands
- If input is available from the user (via
stdin), the client processes:exit: terminates the client.subscribe <topic>orunsubscribe <topic>:- Fills a
tcp_client_requeststructure with the topic and command type (truefor subscribe,falsefor unsubscribe). - Sends the request to the server.
- Fills a
- If input is available from the user (via
-
Server Messages
- If data is available from the server, it is printed to
stdoutin the format specified for TCP messages.
- If data is available from the server, it is printed to
At termination, the client closes the socket it originally opened.
-
udp_message_t- Holds the topic (string), data type (1 byte), and payload.
-
tcp_message_t- Contains the following:
- IP address (as a string)
- Port number (UDP sender)
- Data type (1 byte)
- Data format (e.g.,
INT,FLOAT, etc.) - Topic (string)
- Payload (formatted for readability)
- Contains the following:
-
tcp_client_request- Used for subscription commands.
- Fields:
- A boolean flag (
true= subscribe,false= unsubscribe) - Topic string
- A boolean flag (
-
int_tcp_tandfloat_tcp_t- Helper structures used for decoding UDP messages into readable TCP formats.
These structures enable effective message parsing, transformation, and routing from UDP to subscribed TCP clients.
To start the server, use the following command:
./server <PORT><PORT>: The port number on which the server will listen for both TCP and UDP connections.
The server will listen for:
- TCP connections from subscribers (clients)
- UDP datagrams from publishers (predefined clients)
To start a TCP client (subscriber), use:
./subscriber <ID_CLIENT> <IP_SERVER> <PORT_SERVER><ID_CLIENT>: A string (max 10 ASCII characters) identifying the client.<IP_SERVER>: The IPv4 address of the server (e.g.,127.0.0.1).<PORT_SERVER>: The same port number used to start the server.
Once started, the TCP client accepts the following commands via keyboard:
- Subscribe to a topic:
subscribe <TOPIC>- Unsubscribe from a topic:
unsubscribe <TOPIC>- Disconnect the client:
exit
TCP clients can subscribe to topics using wildcards to match multiple levels in topic names.
The * wildcard matches zero or more levels in the topic hierarchy.
Example:
subscribe UPB/precis/*/valueThis matches topics like:
UPB/precis/1/valueUPB/precis/room1/valueUPB/precis/sensors/room1/value
But not:
UPB/precis/room1/value/errors
The + wildcard matches exactly one level in the topic hierarchy.
Example:
subscribe a/+/b
This matches:
a/x/ba/room1/b
But not:
a/x/y/ba/b
You can use wildcards in combination:
subscribe UPB/+/1/+
subscribe */temperature
These will match:
UPB/precis/1/temperatureUPB/acs/temperatureanything/temperature
If a client subscribes to both a specific topic and a matching wildcard, it will still receive only one copy of each matching message.
The server accepts the following command from keyboard:
exit
This will close:
- All connected TCP clients
- The server process itself