|
Page 1 of 3 There are big advantages to using FreeRTOS with the Pico and one of them is being able to use sockets. This is an extract from our latest book on the Raspberry Pi Pico 2W in C.
Master the Raspberry Pi Pico in C: WiFiwith lwIP, mbedTLS & FreeRTOS Second Edition
By Harry Fairhead & Mike James

Buy from Amazon.
Contents
Preface
- The Pico WiFi Stack
- Introduction To TCP
Extract: Simplest HTTP Client *
- More Advanced TCP
- SSL/TLS and HTTPS
Extract: Simplest HTTPS Client *
- Details of Cryptography
Extract: Random Numbers*
- Servers
Extract: HTTP Server *
- UDP For Speed
Extract: Basic UDP *
- SNTP For Time-Keeping
- SMTP For Email
- MQTT For The IoT
- FreeRTOS
Extract: Installing FreeRTOS
- Client Sockets
Extract: Client Sockets NEW!!
- Socket Server
- Secure Sockets
Appendix 1 Getting Started In C
* Extracts from the first edition not yet updated.
<ASIN:B0FDYDPQ54>
Sockets are a general-purpose way of communicating over networks and similar infrastructure. Essentially they are a generalization of files to things other than storage devices. They aren’t part of the C standard, but are available on all POSIX-compliant operating systems such as Linux. As a result there are lots of programs that implement network transactions using sockets. Although the Pico SDK does not support sockets, lwIP does, but it requires support for threads or tasks as implemented by FreeRTOS. The main problem is that lwIP’s sockets are not a 100% implementation of the POSIX standard and you are almost certain to require some changes to any existing program. However, the differences are small enough not to be a burden when creating a new program.
The biggest problem is that neither FreeRTOS nor lwIP sockets are well supported by Raspberry Pi and the documentation is severely lacking. This is what this chapter sets out to remedy.
All sockets do is transport data from one point to another, so you can use them to communicate using almost any standard protocol, like HTTP, or a custom protocol of your own devising. Put simply, a socket is a stream of bytes that you can send over a communication channel.
Socket Basics
The basic steps in using a socket are fairly simple:
-
Create socket
-
Connect the socket to an address
-
Transfer data.
Sockets connect to other sockets by their addresses. The simplest case is where there are just two sockets, or two endpoints, communicating. Once the connection is made, the two sockets at each end of the connection operate in more or less the same way. In general, one of the sockets, the client, will have initiated the connection and the other, the server, will have accepted it.
There is a conceptual difference between a client socket and a server socket. A server socket is set up and then it waits for clients to connect to it. A client socket actively seeks a connection with a server. Once connected, data can flow in both directions and the difference between the two ends of the connection becomes less. That is, the difference between client and server is only about who initiates the connection.
Socket Functions
There are several basic socket functions that are needed for specific purposes and these are common to all sockets implementations including lwIP:
Create a socket
sockfd= socket(int socket_family, int socket_type, int protocol);
This returns a socket descriptor, an int which you use in other socket functions. The socket_family is where you specify the type of communications link to be use and this is where sockets are most general. There are lots of communications methods that sockets can use, including AF_UNIX or AF_LOCAL, which don't use a network, but allow inter-communication between processes on the same machine. In most cases, you are going to be using AF_INET for IPv4 or AF_INET6 for IPv6 networking. lwIP supports both but IPv6 is only available if you enable it.
The socket_type specifies the general protocol to be used. In most cases you will use SOCK_STREAM which specifies a reliable two-way connection - for IP communications this means TCP/IP is used. For some applications you might want to use SOCK_DGRAM, which specifies that the data should be sent without confirming that it has been received. This is a broadcast mechanism that corresponds to UDP for IP communications. LwIP supports both and also SOCK_RAW.
The protocol parameter selects a sub-protocol of the socket type. In most cases you can simply set it to 0 or IPPROTO_IP. LwIP supports IPPROTO_ICMP, IPPROTO_IP, IPPROTO_IP and IPPROTO_IP
As we are going to be working with sockets that basically work with the web, we will use AF_INET and SOCK_STREAM.
Connect a socket to an address
To connect a socket as a client of another use the connect function:
int connect(int sockfd,const struct sockaddr *addr,
socklen_t addrlen);
The sockfd parameter is just the socket file descriptor returned from the socket function. The addr parameter points at a sockaddr struct which contains the address of the socket you want to connect to. Of course, addrlen just specifies the size of the struct. The socket address type depends on the underlying communications medium that the socket uses, but in most cases it is just an IP address.
Reading and Writing
As an open socket is just a file, you can use the standard read and write functions that you would use to work with a file. There are two additional functions, send and recv, which work in the same way as write and read but have an additional final parameter that can be used to control exactly how the transaction is performed. It is worth noting that Windows sockets do not support read and write but they do work with recv and send and if you are developing a cross-platform or porting a Windows socket program then it might be easier to use these alternatives.
Both read and write are blocking in the sense that they do not return until there is either data to process or the data has been sent. This makes writing programs easier but without the use of threads or events brings the rest of the program to a halt. You can convert read and write into non-blocking operations but this is less commonly used.
|