The Pico In MicroPython: Sockets
Written by Mike James & Harry Fairhead   
Monday, 05 August 2024
Article Index
The Pico In MicroPython: Sockets
Socket Address
A Socket Web Client
SSL Socket Based HTTPS Client

Socket Address

After defining the type of connection you need to specify the addresses involved in the connection. As sockets can be used to connect to a wide range of different types of network the address format could vary a lot and not just be a simple URL or an IP address. For this reason sockets are used with their own internal address representation and you have to use the getaddrinfo method:

socket.getaddrinfo(host, port, af=0, type=0, proto=0, flags=0)

The first two parameters are familiar and simple. The host has to be specified using a URL or an IP address. The second is the numeric port to use with the socket. The next three parameters are the same as used in creating the socket. In general you use the same parameter values for an address intended to be used with a socket as used to create the socket. If you don’t specify a parameter than getaddrinfo will return a list of tuples for each possible address type. Each tuple has the following format:

(af, type, proto, canonname, sockaddr)

where af, type and proto are as before and canonname is the cannonical name for the address type and sockaddr is the actual address, which may also be a tuple. In the case of an IP address, the sockaddr is a tuple with the format:

(IP, port)

At the time of writing the Pico only supports IPv4 and it only returns a list with a single tuple. The only really useful part of this tuple is the final element which is an IP tuple which most of the socket methods actually use. You could short circuit everything by simply creating the IP tuple and not use getaddrinfo, however, you should use it to allow for compatibility with the full sockets module and for future development.

For example:

ai = socket.getaddrinfo("www.example.com", 
                   80,socket.AF_INET,socket.SOCK_DGRAM)

returns the list:

[(2, 1, 0, '', ('93.184.216.34', 80))]

and is it the final tuple

('93.184.216.34', 80)

which we actually use in calls to socket methods. To extract this final tuple we use:

addr=ai[0][-1]

While on the subject of addresses there are two functions which can be used to convert an IP address in “dotted” form to a byte value and vice versa:

socket.inet_ntop(socket.AF_INET,bytes)

gives the dotted text form and:

socket.inet_pton(socket.AF_INET,string)

gives the binary form of the IP address.

 

Client Sockets

Once we have a socket object and the ability to specify an address we have to connect it to another socket to make a two-way communication channel. Data can be written and read at both sockets that form the connection. Exactly how sockets are connected depends on which is the client and which the server. In this section we look at how to connect to a server. By default all socket methods are blocking. See later for non-blocking operation.

If you want to connect a socket to a server socket than all you have to do is use:

socket.connect(address)

where address is the address of the sever socket you are trying to connect to and has to be specified as an IP tuple:

(ip,port)

For example:

socket.connect(('93.184.216.34',80))

While you can use an IP tuple, it is more usual to use socket.getaddrinfo to generate it.

You should always close a socket when you are finished using it with a call to the close method.

Once you have a connected socket you can send and receive data using a range of methods.

The methods used to send data are:

send(bytes)

Returns the number of bytes actually sent

sendall(bytes)

Sends all of the data even if it takes multiple chunks of data. Doesn’t work well with non-blocking sockets and write is preferred.

write(buf)

Tries to write all of the buffer but this may not be possible with a non-blocking socket and it returns the number of bytes actually sent.

The receive methods are:

recv(len)

Returns no more than len bytes as a Bytes object.

recvfrom(len)

Return no more than len bytes as a tuple (bytes,address) the address it he address of the device sending the database.

read(len)

Return no more than len bytes as a bytes object. If len is not specified it reads as much data is sent until the socket is closed.

readinto(buf, len)

Read no more than len bytes into the buf. If len is not specified len(buf) is used. Returns the number of bytes actually read.

readline()

Read a line, ending in a newline character.

There are also:

sendto(bytes, address)

Send data to the address specified – the socket used has to be unconnected for this to work.

makefile(mode='rb', 
          buffering=0)

Available for compatibility with Python which needs the socket to be converted to a file before reading or writing. In MicroPython this can be used but it does nothing.

 



Last Updated ( Tuesday, 06 August 2024 )