Publish/Subscribe API for PubNub Windows C SDK
Publish
The pubnub_publish()
function is used to send a message to all subscribers of a channel. To publish a message you must first specify a valid publish_key
at initialization. A successfully published message is replicated across the PubNub Real-Time Network and sent simultaneously to all subscribed clients on a channel.
Messages in transit can be secured from potential eavesdroppers with SSL/TLS by setting ssl to true during initialization.
Publish Anytime
It's not required to be subscribed to a channel in order to publish to that channel.
Message Data
The message argument can contain any JSON serializable data, including: Objects, Arrays, Ints and Strings. data
should not contain special Windows C classes or functions as these will not serialize. String content can include any single-byte or multi-byte UTF-8 character.
JSON serialize
It is important to note that you should JSON serialize when sending signals/messages via PUBNUB.
Message Size
The maximum number of characters per message is 32 KiB by default. The maximum message size is based on the final escaped character count, including the channel name. An ideal message size is under 1800 bytes which allows a message to be compressed and sent using single IP datagram (1.5 KiB) providing optimal network performance.
If the message you publish exceeds the configured size, you will receive the following message:
Message Too Large Error
["PUBLISHED",[0,"Message Too Large","13524237335750949"]]
For further details please check: https://support.pubnub.com/hc/en-us/articles/360051495932-Calculating-Message-Payload-Size-Before-Publish
Message Publish Rate
Messages can be published as fast as bandwidth conditions will allow. There is a soft limit based on max throughput since messages will be discarded if the subscriber can't keep pace with the publisher.
For example, if 200 messages are published simultaneously before a subscriber has had a chance to receive any messages, the subscriber may not receive the first 100 messages because the message queue has a limit of only 100 messages stored in memory.
Publishing to Multiple Channels
It is not possible to publish a message to multiple channels simultaneously. The message must be published to one channel at a time.
Publishing Messages Reliably
There are some best practices to ensure messages are delivered when publishing to a channel:
- Publish to any given channel in a serial manner (not concurrently).
- Check that the return code is success (e.g.
[1,"Sent","136074940..."]
) - Publish the next message only after receiving a success return code.
- If a failure code is returned (
[0,"blah","<timetoken>"]
), retry the publish. - Avoid exceeding the in-memory queue's capacity of 100 messages. An overflow situation (aka missed messages) can occur if slow subscribers fail to keep up with the publish pace in a given period of time.
- Throttle publish bursts in accordance with your app's latency needs e.g. Publish no faster than 5 msgs per second to any one channel.
Publishing Compressed Messages
Message compression lets you send the message payload as the compressed body of an HTTP POST call.
Every PubNub SDK supports sending messages using the publish()
call in one or more of the following ways:
- Uncompressed, using HTTP GET (message sent in the URI)
- Uncompressed, using HTTP POST (message sent in the body)
- Compressed, using HTTP POST (compressed message sent in the body)
This section outlines what compressing a message means, and how to use compressed messages to your advantage.
Compressed messages support
Currently, the C and Objective-C SDKs support compressed messages.
Message compression can be helpful if you want to send data exceeding the default 32 KiB message size limit, or use bandwidth more efficiently. Compressing messages is useful for scenarios that include high channel occupancy and quick exchange of information like ride hailing apps or multiplayer games.
Compression Trade-offs
Small messages can expand Compressed messages generally have a smaller size, and can be delivered faster, but only if the original message is over 1 KiB. If you compress a signal (whose size is limited to 64 bytes), the compressed payload exceeds the signal's initial uncompressed size.
CPU overhead can increase While a smaller payload size is an advantage, working with compressed messages uses more CPU time than working with uncompressed messages. CPU time is required to compress the message on the sending client, and again to decompress the message on the receiving client. Efficient resource management is especially important on mobile devices, where increased usage affects battery life. Carefully consider the balance of lower bandwidth and higher speed versus any increased CPU usage.
Using Compression Compression methods and support vary between SDKs. If the receiving SDK doesn't support the sender's compression method, or even if it doesn't support it at all, the PubNub server automatically changes the compressed message's format so that it is understandable to the recipient. No action is necessary from you.
Messages are not compressed by default; you must always explicitly specify that you want to use message compression. Refer to the code below for an example of sending a compressed message.
struct pubnub_publish_options opt = pubnub_publish_defopts();
opt.method = pubnubSendViaPOSTwithGZIP;
pbresult = pubnub_publish_ex(pn, "channel_name", "{\"message\":\"This message will be compressed\"}", opt);
}]
Method(s)
To Publish a message
you can use the following method(s) in the Windows C SDK:
enum pubnub_res pubnub_publish (pubnub_t *p, const char *channel, const char *message)
Parameter | Type | Required | Description |
---|---|---|---|
p | pubnub_t* | Yes | Pointer to pubnub context. Can't be NULL |
channel | const char* | Yes | Pointer to string with the channel name (or comma-delimited list of channel names) to publish to. |
message | const char* | Yes | Pointer to string containing message to publish in JSON format. |
enum pubnub_res pubnub_publishv2 (pubnub_t *p, const char *channel, const char *message, bool store_in_history, bool eat_after_reading)
Parameter | Type | Required | Description |
---|---|---|---|
p | pubnub_t* | Yes | Pointer to Pubnub Client Context |
channel | const char* | Yes | Pointer to string with the channel name (or comma-delimited list of channel names) to publish to. |
message | const char* | Yes | Pointer to string containing message to publish in JSON format. |
store_in_history | bool | Yes | If false, message will not be stored in history of the channel |
eat_after_reading | const char* | Yes | If true, message will not be stored for delayed or repeated retrieval or display |
Basic Usage
Publish a message to a channel
pubnub_publish(ctx, "my_channel", "\"message\"");
pbresult = pubnub_await(ctx);
if (PNR_OK == pbresult) {
/* Published successfully */
}
Subscribe to the channel
Before running the above publish example, either using the Debug Console or in a separate script running in a separate terminal window, subscribe to the same channel that is being published to.
Rest Response from Server
The function returns the following formatted response:
[1, "Sent", "13769558699541401"]
Other Examples
Publish a JSON serialized message
pubnub_t *ctx = pubnub_alloc();
if (NULL == ctx) {
puts("Couldn't allocate a Pubnub context");
return -1;
}
pubnub_init(ctx, "demo", "demo");
pubnub_publish(ctx, "hello_world", "{\"msg\": \"Hello from Pubnub C-core docs!\"}");
pubnub_cancel(ctx);
Publish with cipher key
res = pubnub_publish_encrypted(pbp, chan, "\"Hello world from crypto sync!\"", cipher_key);
if (res != PNR_STARTED) {
printf("pubnub_publish() returned unexpected: %d\n", res);
pubnub_free(pbp);
return -1;
}
Publish with cipher key using pubnub_publish_ex
Using this method you can reuse the cipherKey
from the options.
struct pubnub_publish_options opt = pubnub_publish_defopts();
opt.cipher_key = my_cipher_key;
pbresult = pubnub_publish_ex(pn, "my_channel", "42", opt);
Extended Publish
Extended Publish Options structure
Holds all the options for extended
publish.
Method(s)
Declaration
struct pubnub_publish_options { bool store; char const* cipher_key; bool replicate; char const* meta; enum pubnub_publish_method method; };
Members
Member | Type | Description |
---|---|---|
store | bool | If true , the message is stored in history. If false , the message is not stored in history. |
cipher_key | char const* | If not NULL , the key used to encrypt the message before sending it to PubNub. Keep in mind that encryption is a CPU intensive task. Also, it uses more bandwidth, most of which comes from the fact that decrypted data is sent as Base64 encoded JSON string. This means that the actual amount of data that can be sent as encrypted in a message is at least 25% smaller (than un-encrypted). Another point to be made is that it also does some memory management (allocating and deallocating). |
replicate | bool | If true , the message is replicated, thus will be received by all subscribers. If false , the message is not replicated and will be delivered only to Function event handlers. Setting false here and false on store is referred to as a Fire (instead of a publish ). |
meta | char const* | An optional JSON object, used to send additional (meta ) data about the message, which can be used for stream filtering . |
method | enum pubnub_publish_method | Defines the method by which publish transaction will be performed. Can be HTTP GET or POST . If using POST , content can be GZIP compressed. |
Initialize extended Publish options
This returns the default options
for publish V1 transactions. Will set:
Parameter | Default |
---|---|
store | true |
cipher_key | NULL |
replicate | true |
meta | NULL |
method | pubnubPublishViaGET |
Method(s)
Declaration
struct pubnub_publish_options pubnub_publish_defopts(void);
Parameters
This method doesn't take any argument.
Basic Usage
struct pubnub_publish_options opts = pubnub_publish_defopts();
Returns
Type | Value | Description |
---|---|---|
struct pubnub_publish_options | The default options for publish . |
Extended Publish
The extended publish V1. Basically the same as pubnub_publish()
, but with added optional parameters in @p
opts.
Method(s)
Declaration
enum pubnub_res pubnub_publish_ex(pubnub_t *p, const char *channel, const char *message, struct pubnub_publish_options opts);
Parameters
Parameter | Type | Required | Description |
---|---|---|---|
p | pubnub_t* | Yes | The Pubnub context. |
channel | char const* | Yes | The string with the channel name to publish to. |
message | char const* | Yes | The message to publish . It needs to be JSON encoded. |
opts | struct pubnub_publish_options | Yes | The Publish options. |
Basic Usage
struct pubnub_publish_options opt = pubnub_publish_defopts();
opt.store = false;
pbresult = pubnub_publish_ex(pn, "my_channel", "42", opt);
Returns
Type | Value | Description |
---|---|---|
enum pubnub_res | PNR_STARTED | Success. |
other | Indicates the type of error. |
Signal
Sends a signal @p
message (in JSON format) on @p
channel, using the @p
pb context. This actually means "initiate a signal transaction".
It has similar behaviour as publish, but unlike publish transaction, signal erases previous signal message on server (on a given channel,) and you can not send any metadata.
There can be only up to one signal message at the time. If it's not renewed by another signal, signal message disappears from channel history after a certain amount of time.
You can't (send a) signal
if a transaction is in progress on @p
pb context.
If transaction is not successful (@c
PNR_PUBLISH_FAILED
), you can get the string describing the reason for failure by calling pubnub_last_publish_result()
.
Keep in mind that the timetoken from the signal operation response is not parsed by the library, just relayed to the user. Only time-tokens from the subscribe operation are parsed by the library.
Also, for all error codes known at the time of this writing, the HTTP error will also be set, so the result of the Pubnub operation will not be @c
PNR_OK
(but you will still be able to get the result code and the description).
By default, signals are limited to a message payload size of 64
bytes. This limit applies only to the payload, and not to the URI or headers. If you require a larger payload size, please contact support.
Method(s)
Declaration
enum pubnub_res pubnub_signal(pubnub_t* pb, char const* channel, char const* message);
Parameters
Parameter | Type | Required | Description |
---|---|---|---|
pb | pubnub_t* | Yes | The Pubnub context in which to parse the response. |
channel | char const* | Yes | The string with the channel to signal to. |
message | char const* | Yes | The string with the signal, expected to be in JSON format. |
Basic Usage
Signal a message to a channel
enum pubnub_res = pubnub_signal(pb, "my_channel", "\"signalling\"");
Returns
Type | Value | Description |
---|---|---|
enum pubnub_res | PNR_OK | Transaction finished (signal sent). |
PNR_STARTED | Transaction started (started to send signal), will finish later. | |
otherwise | Error, value indicates the reason for failure. |
Message type enumeration (enum pubnub_message_type)
Defines the type of a message that is retrieved with subscribe V2:
Symbol | Value | Description |
---|---|---|
pbsbPublished | 0 | Published message (sent via Publish transaction) |
pbsbSignal | 1 | A signal message (sent via Signal transaction) |
Subscribe
This function causes the client to create an open TCP socket to the PubNub Real-Time Network and begin listening for messages on a specified channel
. To subscribe to a channel
the client must send the appropriate subscribe_key
at initialization. By default a newly subscribed client will only receive messages published to the channel after the pubnub_subscribe()
call completes.
Context usage
Typically, you will want two separate contexts for publish and subscribe. When changing the active set of subscribed channels, first call pubnub_leave()
on the old set. The pubnub_subscribe()
interface is essentially a transaction to start listening on the channel for arrival of next message. This has to be followed by pubnub_get()
call to retrieve the actual message, once the subscribe transaction completes successfully. This needs to be performed every time it is desired to retrieve a message from the channel.
Unsubscribing from all channels
Unsubscribing from all channels, and then subscribing to a new channel Y is not the same as subscribing to channel Y and then unsubscribing from the previously-subscribed channel(s). Unsubscribing from all channels resets the last-received timetoken
and thus, there could be some gaps in the subscription that may lead to message loss.
Method(s)
To Subscribe to a channel
you can use the following method(s) in the Windows C SDK:
enum pubnub_res pubnub_subscribe (pubnub_t *p, const char *channel, const char *channel_group)
Parameter | Type | Required | Description |
---|---|---|---|
p | pubnub_t* | Yes | Pointer to Pubnub client context. Can't be NULL. |
channel | const char* | Optional | The string with the channel name (or comma-delimited list of channel names) to subscribe to. |
channel_group | const char* | Optional | The string with the channel group name (or comma-delimited list of channel group names) to subscribe to. |
Basic Usage
Subscribe to a channel:
pubnub_subscribe(ctx, "my_channel", NULL);
pbresult = pubnub_await(ctx);
if (PNR_OK == pbresult) {
char const *message = pubnub_get(ctx);
while (message != NULL) {
message = pubnub_get(ctx);
}
}
Rest Response from Server
The output below demonstrates the response format to a successful call:
[[], "Time Token"]
Other Examples
Subscribing to multiple channels
It's possible to subscribe to more than one channel using the Multiplexing feature. The example shows how to do that using an array to specify the channel names.
Alternative subscription methods
You can also use Wildcard Subscribe and Channel Groups to subscribe to multiple channels at a time. To use these features, the Stream Controller add-on must be enabled on your keyset in the Admin Portal.
pubnub_t *ctx = pubnub_alloc();
if (NULL == ctx) {
puts("Couldn't allocate a Pubnub context");
return -1;
}
pubnub_init(ctx, "demo", "demo");
pubnub_subscribe(ctx, "hello_world1,hello_world2,hello_world3", NULL);
pbresult = pubnub_await(ctx);
if (pbresult != PNR_OK) {
printf("Failed to subscribe, error %d\n", pbresult);
pubnub_free(ctx);
return -1;
}
else {
char const *msg = pubnub_get(ctx);
show all 23 lines