Sockets¶
Introduction¶
LwIP network stack includes built-in support BSD style sockets, allowing developers to use the familiar socket programming API. Using familiar socket APIs abstract the inner implementation from the user, allowing migration of networking code more easily. In LwIP there are two main types of sockets, BSD sockets API and Netconn APIs. There is also a RAW socket API that is used mostly when in no-OS mode but this would not be covered.
BSD style APIs¶
This is a high-level API that provides a familiar interface for network programming, similar to what you’d find in standard Unix/Linux systems. The BSD sockets API provides a more standard, POSIX-like interface, than Netconn.
The APIs for using BSD sockets are mainly under socket.h header file.
These BSD socket APIs would call lwip_xxx() with the xxx defined as the API operation itself.
To enable LwIP sockets, user must define label LWIP_SOCKET in lwipopts.h.
The full set of BSD Socket APIs can be found at socket.html.
Netconn style APIs¶
lwIP uses the Netconn API to implement the BSD Sockets API internally, but it can also be called directly from applications. The Netconn API is a higher-level, lwIP-specific interface for socket programming, and as such, it is not portable as a BSD socket API.
The APIs for using Netconn start with netconn_xxx().
To enable LwIP sockets and also Netconn support, user must define label LWIP_SOCKET and LWIP_NETCONN in lwipopts.h.
The full set of Netconn APIs can be found at netconn.html.
Socket APIs used in SDK examples¶
The SDK includes currently two examples, CC35xx_network_terminal and CC35xx_MQTT_client
CC35xx_network_terminal example uses the lwip_xxx() which are eventually calling the netconn_xxx() APIs.
It can be seen that the default configuration in lwipopts.h includes both, LWIP_SOCKET and LWIP_NETCONN.
CC35xx_MQTT_client example, like other built-in protocols, exposes protocol specific APIs so there is no need to call directly any socket APIs.
In MQTT example specifically, LwIP provides some specific MQTT APIs (starting with mqtt_xxx()), which handle the socket internally and transparently.
More specifically, it uses ALTCP layer (Application Layered TCP) which is an abstraction layer that prevents applications linking directly against the tcp.h.
This way, an application can make use of other application layer protocols on top of TCP without knowing the details. A good example is the TLS implementation with mbedTLS stack.
The ALTCP is used internally in MQTT as well as in HTTP and applications can also use it.
Code examples¶
The following code snippet illustrates a TCP server allowing connection from a peer device, receiving and printing the received message and sending a pre-defined response.
#include "lwip/sockets.h"
#define SERVER_PORT 8080
#define BUFFER_SIZE 1024
void tcp_server(void *arg) {
int server_fd, client_fd;
struct sockaddr_in server_addr, client_addr;
socklen_t addr_len = sizeof(client_addr);
char buffer[BUFFER_SIZE];
// Create socket
server_fd = lwip_socket(AF_INET, SOCK_STREAM, 0);
if (server_fd < 0) {
printf("Socket creation failed\n");
return;
}
// Bind socket to port
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(SERVER_PORT);
server_addr.sin_addr.s_addr = INADDR_ANY;
if (lwip_bind(server_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
printf("Bind failed\n");
lwip_close(server_fd);
return;
}
// Listen for connections
if (lwip_listen(server_fd, 5) < 0) {
printf("Listen failed\n");
lwip_close(server_fd);
return;
}
printf("Server listening on port %d\n", SERVER_PORT);
while (1) {
// Accept client connection
client_fd = lwip_accept(server_fd, (struct sockaddr*)&client_addr, &addr_len);
if (client_fd < 0) {
printf("Accept failed\n");
continue;
}
printf("Client connected\n");
// Receive data
int len = lwip_recv(client_fd, buffer, BUFFER_SIZE, 0);
if (len > 0) {
buffer[len] = '\0';
printf("Received: %s\n", buffer);
// Send response
lwip_send(client_fd, "Hello from server", 17, 0);
}
// Close client connection
lwip_close(client_fd);
}
lwip_close(server_fd);
}
The following code snippet illustrates a TCP client connecting to a server, sending a pre-defined data, receiving a response and presenting it.
#include "lwip/sockets.h"
#define SERVER_IP "192.168.1.100"
#define SERVER_PORT 8080
void tcp_client(void *arg) {
int client_fd;
struct sockaddr_in server_addr;
char buffer[1024] = "Hello from client";
// Create socket
client_fd = lwip_socket(AF_INET, SOCK_STREAM, 0);
if (client_fd < 0) {
printf("Socket creation failed\n");
return;
}
// Server address
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(SERVER_PORT);
server_addr.sin_addr.s_addr = inet_addr(SERVER_IP);
// Connect to server
if (lwip_connect(client_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
printf("Connection failed\n");
lwip_close(client_fd);
return;
}
// Send data
lwip_send(client_fd, buffer, strlen(buffer), 0);
// Receive response
int len = lwip_recv(client_fd, buffer, sizeof(buffer), 0);
if (len > 0) {
buffer[len] = '\0';
printf("Received: %s\n", buffer);
}
// Close socket
lwip_close(client_fd);
}