As a support towards a complete tutorial and presentation of the “An UART interpreter“, I discovered the need to learn something about networking under Python language. In this way, I should be capable to enable the access to Internet of my microcontroller based board.
So I will start by showing an example on how to send any signal to the other end of a network – here in the same localhost, i.e. send messages from my PC to itself, but once the mechanism is set, we can speak to the other side of the planet by simply changing the IP address. By doing this, the UART interpreter will be IoT-enabled.
For everyone who don’t know anything about networking softwares and modules and wants to learn something, like me, the best thing is to start from the bottom layer of the network: sockets. Which are not so bottom, but let accept this trade off. In these examples is developed a sample software in Python 3 running on two machines, here used the same PC speaking in local, i.e. the address 127.0.0.1, or localhost. I used Python because is well suited to easily work with the RaspberryPi, which will be exploited soon in next projects. And can be used to test the set of networking scripts described here.
What is a socket? Basically it’s an “istance” of two point of communication between processes, or in other words are an IPC methodology (Inter-Process Communication). You can use them on local machine or between machines separated by any kind of networks. Of course, there are more efficients methods to allow two processes to communicate on the same machine, but sockets are almost the only simple solution to allow communication over the network. From the user point of view, the socket represent an IP address to which you want to connect to by using a specific “port” that can (but don’t have to) be different depending whether it is a request or an actual data response. A port then can be considered as an instance of communication with that IP, which can be treated in a different way as different as the port chosen, for that reason you should not use ports with a fixed function and causing possible conflicts between processes. Use for example:
Thanks to sockets, you can also see this website, where data pass through your IP at port 80. For a complete description I invite you to search around, since explaining them deeply is not the purpose of this article and I’m not capable to.
In Python, we need to import the module socket in order to use a server socket and binding it at localhost address. This is the server address, but can be anything else than localhost (127.0.0.1). Then we listen for a certain number of connections at a time, here just one connection at a time is allowed, but typically is 5. The socket is an INET type since we deal with internet protocol addresses and is STREAM because I want to keep monitoring of the activity until I decide to disconnect from it. If this is DGRAM, I send my data and then disconnect. But here I want to disconnect at the end of the client execution only.
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server.bind(('localhost', 8000)) server.listen(1)
Then in a loop we need to accept the connection, creating a client socket with its address, then receive from the client a string saved in mex and send the server aknowledge to the client.
while 1: #accept connections from outside print(&quot;Server notification: waiting for client&quot;) (clientsocket, address) = server.accept() mex = receive_sck(clientsocket) print(&quot;Server notification: \n\tIncoming data: &quot; + mex) msg = &quot;Server notification: data received&quot; msg = msg_len(msg) send_sck(clientsocket, msg)
A sad but true thing is that inside blocking sockets I can wait forever because there is not a prefixed size. So I’ve implemented by using the msg_len() method a protocol which attach before the message the number of chars followed by an underscore character. Of course, the number include the number of char used by the number it self, too. The method return the modified string.
In this way at receiving part I used the receive_sck() to receive and check if in the received part the “_” is present, thanks to this I can identify the number. After that I set the MSGLEN to this number, exiting from the while after that amount of data is received, and if present, more data is discarded since is not part of the message, according to this protocol. Must be noticed that even if the maximum buffer allowed is 2048 chars, I can receive even only one char at a time, if the line is congested. So a marking char must be searched every time I receive from socket until I find it. The marking char here is “_”.
With the send_sck() is more simple, because what I send is known, but must be previously transformed to attach the number of chars, useful at the receiving part. When transmitting an error handling can be implemented.
On the other side of the connection the same methods are reused for modularity. They can be improved by using heavily a self created class, which I didn’t done here.
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) client.connect(('localhost', 8000)) msg = 'Hello IoT!' msg = msg_len(msg) send_sck(client, msg) client.shutdown(1) mex = receive_sck(client) print(&quot;Client notification: \n\tIncoming data: &quot; + mex) client.close()
Here I’ve implemented the socket client and connected it to server, the message msg is sent to the client socket called with fantasy client , sending the content to the server at localhost, i.e. the server address. The new thing is the client.shutdown(1), in which I close the client transmission capability allowing it to still receive, just to check the aknowledge from the server. Then I close the socket, disconnecting from server.
As a result, this is how two separate processes (server.py in the white backgroung and client.py executed on prompt of Windows) are communicatin each other. Client script is executed after server is waiting for client. Raw data received from each part is printed on stdout after the “Incoming data: ” and the actual payload contains the number of chars added by the protocol. These can be filtered out when printed, because are needed only by the algorithm and usually not by the user.
Here you can dowload both client and server and play with them.