Publish/Subscribe API for C-Core SDK
The foundation of the PubNub service is the ability to send a message and have it delivered anywhere in less than 30 ms. Send a message to just one other person, or broadcast to thousands of subscribers at once.
For higher-level conceptual details on publishing and subscribing, refer to Connection Management and to Publish Messages.
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.
- Prerequisites and limitations
- Security
- Message data
- Size
- Publish rate
- Custom message type
- Best practices
- You must initialize PubNub with the
publishKey. - You don't have to be subscribed to a channel to publish to it.
- You cannot publish to multiple channels simultaneously.
You can secure the messages with SSL/TLS by setting ssl to true during initialization. You can also encrypt messages.
The message can contain any JSON-serializable data (Objects, Arrays, Ints, Strings) and shouldn't contain any special classes or functions. String content can include any single-byte or multi-byte UTF-8 characters.
Don't JSON serialize
You should not JSON serialize the message and meta parameters when sending signals, messages, or files as the serialization is automatic. Pass the full object as the message/meta payload and let PubNub handle everything.
The maximum message size is 32 KiB, including the final escaped character count and the channel name. An optimal message size is under 1800 bytes.
If the message you publish exceeds the configured size, you receive a Message Too Large error. If you want to learn more or calculate your payload size, refer to Message Size Limit.
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.
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 compression 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.
1struct pubnub_publish_options options = pubnub_publish_defopts();
2options.method = pubnubSendViaPOSTwithGZIP;
3enum pubnub_res pbresult = pubnub_publish_ex(pn, "channel_name", "{\"message\":\"This message will be compressed\"}", options);
4}]
You can publish as fast as bandwidth conditions 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, the subscriber may not receive the first 100 messages because the message queue has a limit of only 100 messages stored in memory.
You can optionally provide the CustomMessageType parameter to add your business-specific label or category to the message, for example text, action, or poll.
- Publish to any given channel in a serial manner (not concurrently).
- Check that the return code is success (for example,
[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 according to your app's latency needs, for example no more than 5 messages per second.
Method(s)
To Publish a message you can use the following method(s) in the C-Core SDK:
1enum pubnub_res pubnub_publish (
2 pubnub_t *p,
3 const char *channel,
4 const char *message
5)
| Parameter | Description |
|---|---|
p *Type: pubnub_t* | Pointer to PubNub context. Can't be NULL |
channel *Type: const char* | Pointer to string with the channel ID (or comma-delimited list of channel IDs) to publish to. |
message *Type: const char* | Pointer to string containing message to publish in JSON format. |
1enum pubnub_res pubnub_publishv2 (
2 pubnub_t *p,
3 const char *channel,
4 const char *message,
5 bool store_in_history,
6 bool eat_after_reading
7)
| Parameter | Description |
|---|---|
p *Type: pubnub_t* | Pointer to Pubnub Client Context |
channel *Type: const char* | Pointer to string with the channel ID (or comma-delimited list of channel IDs) to publish to. |
message *Type: const char* | Pointer to string containing message to publish in JSON format. |
store_in_history *Type: bool | If false, message will not be stored in history of the channel ID. |
eat_after_reading *Type: const char* | If true, message will not be stored for delayed or repeated retrieval or display. |
Sample code
Publish a message to a channel
1pubnub_publish(ctx, "my_channel", "\"message\"");
2pbresult = pubnub_await(ctx);
3if (PNR_OK == pbresult) {
4 /* Published successfully */
5}
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[1, "Sent", "13769558699541401"]
Other examples
Publish a JSON serialized message
1
2pubnub_t *ctx = pubnub_alloc();
3if (NULL == ctx) {
4 puts("Couldn't allocate a Pubnub context");
5 return -1;
6}
7pubnub_init(ctx, "demo", "demo");
8pubnub_set_user_id(ctx, "MyUniqueUser_Id");
9pubnub_publish(ctx, "hello_world", "{\"msg\": \"Hello from Pubnub C-core docs!\"}");
10enum pubnub_res pbresult = pubnub_await(ctx);
11if (pbresult != PNR_OK) {
12 printf("Failed to publish, error %d\n", pbresult);
13 pubnub_free(ctx);
14 return -1;
15}
Publish with cipher key
1res = pubnub_publish_encrypted(pbp, chan, "\"Hello world from crypto sync!\"", cipher_key);
2if (res != PNR_STARTED) {
3 printf("pubnub_publish() returned unexpected: %d\n", res);
4 pubnub_free(pbp);
5 return -1;
6}
Publish with cipher key using pubnub_publish_ex
Using this method you can reuse the cipherKey from the options.
1struct pubnub_publish_options options = pubnub_publish_defopts();
2options.cipher_key = my_cipher_key;
3enum pubnub_res pbresult = pubnub_publish_ex(pn, "my_channel", "42", options);
Extended publish
Extended publish options structure
Holds all the options for extended publish.
Method(s)
Declaration
1struct pubnub_publish_options {
2 bool store;
3 char const *cipher_key;
4 bool replicate;
5 char const *meta;
6 enum pubnub_publish_method method;
7 char const* custom_message_type;
8}
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. |
ttl | size_t | How many hours message should be kept and available in Storage. |
custom_message_type | char const* | A case-sensitive, alphanumeric string from 3 to 50 characters describing the business-specific label or category of the message. Dashes - and underscores _ are allowed. The value cannot start with special characters or the string pn_ or pn-. Examples: text, action, poll. |
Initialize extended publish options
This returns the default options for publish V1 transactions. Will set:
| Parameter |
|---|
storeDefault: true |
cipher_keyDefault: NULL |
replicateDefault: true |
metaDefault: NULL |
methodDefault: pubnubPublishViaGET |
custom_message_typeDefault: NULL |
Method(s)
Declaration
struct pubnub_publish_options pubnub_publish_defopts(void);
Parameters
This method doesn't take any argument.
Sample code
1struct 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
1enum pubnub_res pubnub_publish_ex(
2 pubnub_t *p,
3 const char *channel,
4 const char *message,
5 struct pubnub_publish_options opts
6)
Parameters
| Parameter | Description |
|---|---|
p *Type: pubnub_t* | The Pubnub context. |
channel *Type: char const* | The string with the channel ID to publish to. |
message *Type: char const* | The message to publish. It needs to be JSON encoded. |
opts *Type: struct pubnub_publish_options | The Publish options. |
Sample code
1struct pubnub_publish_options options = pubnub_publish_defopts();
2options.store = false;
3enum pubnub_res pbresult = pubnub_publish_ex(pn, "my_channel", "42", options);
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 behavior 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
1enum pubnub_res pubnub_signal(
2 pubnub_t* pb,
3 char const* channel,
4 char const* message
5)
Parameters
| Parameter | Description |
|---|---|
pb *Type: pubnub_t* | The Pubnub context in which to parse the response. |
channel *Type: char const* | The string with the channel ID to signal to. |
message *Type: char const* | The string with the signal, expected to be in JSON format. |
Sample code
Signal a message to a channel
1enum 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) |
Extended signal
Extended signal options structure
Holds all the options for extended signal.
Method(s)
Declaration
1struct pubnub_signal_options {
2 char const* custom_message_type;
3};
Members
| Member | Type | Description |
|---|---|---|
custom_message_type | char const* | A case-sensitive, alphanumeric string from 3 to 50 characters describing the business-specific label or category of the message. Dashes - and underscores _ are allowed. The value cannot start with special characters or the string pn_ or pn-. Examples: text, action, poll. |
Initialize extended signal options
This returns the default options for signal transactions. Will set:
| Parameter |
|---|
custom_message_typeDefault: NULL |
Method(s)
Declaration
struct pubnub_signal_options pubnub_signal_defopts(void);
Parameters
This method doesn't take any argument.
Sample code
1struct pubnub_signal_options options = pubnub_signal_defopts();
2options.custom_message_type = "test-message";
3enum pubnub_res pbresult = pubnub_signal_ex(ctx, "my_channel", "status:active", options);
Extended signal
The extended signal V1. Basically the same as pubnub_signal(), but with added optional parameters in @p opts.
Method(s)
Declaration
1enum pubnub_res pubnub_signal_ex(
2 pubnub_t* pb,
3 const char* channel,
4 const char* message,
5 struct pubnub_signal_options opts);
Parameters
| Parameter | Description |
|---|---|
pb *Type: pubnub_t* | The Pubnub context. |
channel *Type: char const* | The string with the channel ID to signal to. |
message *Type: char const* | The message to signal. It needs to be JSON encoded. |
opts *Type: struct pubnub_signal_options | The Signal options. |
Sample code
1struct pubnub_signal_options options = pubnub_signal_defopts();
2options.custom_message_type = "test-message";
3enum pubnub_res pbresult = pubnub_signal_ex(ctx, "my_channel", "status:active", options);
Returns
| Type | Value | Description |
|---|---|---|
enum pubnub_res | PNR_STARTED | Success. |
| other | Indicates the type of error. |
Returns
| Type | Value | Description |
|---|---|---|
struct pubnub_signal_options | The default options for signal. |
Subscribe (new)
The subscribe function creates an open TCP socket to PubNub and begins listening for messages and events on a specified entity or set of entities. To subscribe successfully, you must configure the appropriate subscribeKey at initialization.
Conceptual overview
For more general information about subscriptions, refer to Subscriptions.
Entities are first-class citizens that provide access to their encapsulated APIs. You can subscribe using the PubNub client object or directly on a specific entity:
A newly subscribed client receives messages after the subscribe() call completes. You can configure automatic retries to attempt to reconnect automatically and retrieve any available messages if a client gets disconnected.
Subscription scope
Subscription objects provide an interface to attach listeners for various real-time update types. Your app receives messages and events via those event listeners. Two types of subscriptions are available:
Subscription, created from an entity with a scope of only that entity (for example, a particular channel)SubscriptionSet, created from the PubNub client with a global scope (for example, all subscriptions created on a singlepubnubobject ). A subscription set can have one or more subscriptions.
The event listener is a single point through which your app receives all the messages, signals, and events in the entities you subscribed to. For information on adding event listeners, refer to Event listeners.
Create a subscription
An entity-level Subscription allows you to receive messages and events for only that entity for which it was created. Using multiple entity-level Subscriptions is useful for handling various message/event types differently in each channel.
1// entity-based, local-scoped, with options
2pubnub_subscription_options_t options = pubnub_subscription_options_defopts();
3options.receive_presence_events = true;
4pubnub_subscription_t* subscription = pubnub_subscription_alloc(
5 entity,
6 &options);
7if (NULL == subscription) {
8 // Handle parameters error (missing entity or invalid PubNub context pointer) or insufficient memory.
9}
10
11// entity-based, local-scoped, without options
12pubnub_subscription_t* subscription = pubnub_subscription_alloc(entity, NULL);
13if (NULL == subscription) {
14 // Handle error for missing entity or invalid PubNub context pointer or insufficient memory.
15}
| Parameter | Description |
|---|---|
options.receive_presence_eventsType: bool | Whether presence updates for userIds should be delivered through the listener streams. For information on how to receive presence events and what those events are, refer to Presence Events. |
Create a subscription set
A client-level SubscriptionSet allows you to receive messages and events for all entities. A single SubscriptionSet is useful for similarly handling various message/event types in each channel.
1// client-based, general-scoped, with options
2pubnub_subscription_options_t options = pubnub_subscription_options_defopts();
3options.receive_presence_events = true;
4pubnub_subscription_set_t* subscription_set = pubnub_subscription_set_alloc_with_entities(
5 entities,
6 4,
7 &options);
8if (NULL == subscription_set) {
9 // Handle parameters error (missing entities or invalid entity's PubNub context pointer) or insufficient memory.
10}
11
12// client-based, general-scoped, without options
13pubnub_subscription_set_t* subscription_set = pubnub_subscription_set_alloc_with_entities(
14 entities,
15 4,
show all 19 lines| Parameter | Description |
|---|---|
entities *Type: pubnub_entity_t** | Pointer to the array with PubNub entities object pointers which should be used in subscriptions set. |
entities_count *Type: int | The number of PubNub entities in array. |
options *Type: const pubnub_subscription_options_t* | Pointer to the subscription configuration options. Set to NULL if options are not required. |
Method(s)
Subscription and SubscriptionSet use the same subscribe() method.
Subscribe
To subscribe, you can use the following method in the c SDK:
1enum pubnub_res pubnub_subscribe_with_subscription(
2 pubnub_subscription_t* sub,
3 const pubnub_subscribe_cursor_t* cursor);
| Parameter | Description |
|---|---|
cursorType: const pubnub_subscribe_cursor_t | Timetoken from which to return any available cached messages. Message retrieval with timetoken is not guaranteed and should only be considered a best-effort service. If the value is not a 17-digit number, the provided value will be ignored. |
subType: pubnub_subscription_t* | Pointer to the subscription, which should be used with the next subscription loop. |
1// subscription cursor
2// timetoken is a pointer to the PubNub high-precision timetoken
3pubnub_subscribe_cursor_t pubnub_subscribe_cursor(
4 const char* timetoken);
Sample code
enum pubnub_res rslt = pubnub_subscribe_with_subscription(subscription, NULL);
if (PNR_OK != rslt) {
// Handle subscription error (mostly because of parameters error).
}
Returns
The subscribe() method doesn't have a return value.
Entities
Entities are subscribable objects for which you can receive real-time updates (messages, events, etc).
Create channels
This method returns a local Channel entity.
pubnub_channel_t* pubnub_channel_alloc(
pubnub_t* pb,
const char* name);
| Parameter | Description |
|---|---|
pb *Type: pubnub_t* | Pointer to the PubNub context used by the created entity to interact with PubNub REST API. |
name *Type: const char* | Pointer to the name of the channel to create. |
Sample code
pubnub_channel_t* channel = pubnub_channel_alloc(pb, "my_channel");
Create channel groups
This method returns a local Channel Group entity.
pubnub_channel_group_t* pubnub_channel_group_alloc(
pubnub_t* pb,
const char* name);
| Parameter | Description |
|---|---|
pb *Type: pubnub_t* | Pointer to the PubNub context used by the created entity to interact with PubNub REST API. |
name *Type: const char* | Pointer to the name of the channel group to create. |
Sample code
pubnub_channel_group_t* group = pubnub_channel_group_alloc(pb, "my_group");
Create channel metadata
This method returns a local Channel Metadata entity.
pubnub_channel_metadata_t* pubnub_channel_metadata_alloc(
pubnub_t* pb,
const char* id);
| Parameter | Description |
|---|---|
pb *Type: pubnub_t* | Pointer to the PubNub context used by the created entity to interact with PubNub REST API. |
id *Type: const char* | The String identifier of the channel metadata object to create. |
Sample code
pubnub_channel_metadata_t* metadata = pubnub_channel_metadata_alloc(pb, "channel_meta");
Create user metadata
This method returns a local User Metadata entity.
pubnub_user_metadata_t* pubnub_user_metadata_alloc(
pubnub_t* pb,
const char* id);
| Parameter | Description |
|---|---|
pb *Type: pubnub_t* | Pointer to the PubNub context used by the created entity to interact with PubNub REST API. |
id *Type: const char* | The String identifier of the user metadata object to create a subscription of. |
Sample code
pubnub_user_metadata_t* metadata = pubnub_user_metadata_alloc(pb, "user_meta");