This tutorial demonstrates how to use TCP and UDP sockets in a Native Client (NaCl) embed module. The sample application allows the user to create a basic TCP or UDP server that echoes text messages sent to it.

To create a client TCP or UDP socket and connect it to a host, select the socket type, enter the host address and port, and click "Connect". You can connect to the locally-created socket, or to a remote socket.

To send a message to the server socket, enter the message in the "Secret Message" field, and click "Send".

To close the client connection, click "Close".

Although the user interacts with the same application interface for both TCP and UDP sockets, the underlying logic depends on the socket type.

The JavaScript component can send the following messages to the NaCl component:

Create a client TCP socket and connect to a specified host.

Create a client UDP socket and connect to a specified host.

Close the client TCP or UDP socket.

Listen on a TCP or UDP server socket.

Send a message from the client socket to the server.

The NaCl component only sends log messages to the JavaScript component. The logs are shown in the "NaCl messages" area in the application.

Figure 2. Server logs

For information on how to access the sample application cheat sheet and run the application, see Sample-based Tutorials.

Initializing the Instance

To initialize the TCP and UDP interfaces:

In the main SocketInstance class, create the client and server objects:

When initializing the objects, check whether each interface is available.
An interface can be unavailable if the required permissions have not been specified in the manifest file, or if the interface is not supported by the platform.

When a client connection attempt is detected, trigger a listening callback to accept the connection.

In the on_server_accept_callback_ function, which is triggered when a client connection attempt is successful, save the client socket to the incoming_socket_ object and log the IP address the connection was accepted from.

Wait for incoming messages on the client socket using the TryRead() function.

Implement echoing received messages to the client in the on_server_receive_callback_ function, which is triggered when a message is successfully read and saved in the receive_buffer_ variable:

// This callback is run when a message is received on the server socket
void SocketsInstance::OnTCPServerReceiveCallback(int32_t result,
const std::string& message) {
// ...
// Echo the received message
tcp_server_.Write(message,
callback_factory_.NewCallbackWithOutput(
&SocketsInstance::OnTCPServerReceiveCallback));
}

In the Write() function, write the message to the connected socket, and resume waiting for incoming messages.

When the client disconnects, reading fails and the failure message is passed to the on_server_receive_callback_ function. When the client disconnection message is detected, restart listening for connections.

Implementing the TCP Client

The client TCP uses a single pp::TCPSocket object. After the application is initialized, the TCP socket client can connect to the TCP server in the sample application or an external TCP server.

To implement the TCP client functionality:

To connect to a TCP server:

Create a TCP socket, and resolve the host address using the pp::HostResolver interface, transforming the address string into a pp::NetAddress object:

To close the connection, close the current pp::TCPSocket instance and reset it by creating a new one:

tcp_socket_.Close();
tcp_socket_ = pp::TCPSocket();

Implementing the UDP Server

Unlike a TCP server, only a single UDP socket is needed for a UDP server. After the server has been bound to a listening port, it can monitor incoming connections and receive messages from multiple sources.

Implementing the UDP Client

The UDP client is implemented similarly to the TCP client. The main difference is that you must bind the UDP socket before you can listen for messages. The logic for sending and handling received messages, and closing the connection is the same as for the TCP client:

To connect to a server:

Create a pp::UDPSocket instance.

Resolve the host address.

Bind the socket to an IP address and port.

Listen for incoming messages.

To send and receive messages:

To send a message, write the message to the socket.

To handle a received message:

Trigger the OnReceiveFromCompletion() function, which invokes the OnUDPClientReceiveFromCallback() function of the SocketInstance class.