Articles Catalogue
Background
Recently, in a company's equipment, the built-in DTU sends 16-digit data messages to the server through UDP. Because of the first contact with this kind of data analysis method, we summarize and reflect here to avoid detours.
II. Summary of Contents
2.1 Creation of UDP Communication Server
step
- Create UDP socket communication mode.
- Bind specific ports.
- Setting up port multiplexing wait (this step can be omitted)
- Get data.
- Send data to client.
- Parse and store data.
- Close the socket link for UDP.
Following are the explanations and summaries, which are adopted. MVP Complete all the above steps in a way that does not extend too much:
1. Create UDP socket communication mode.
import socket Server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
Before any type of communication starts, a network application must create a socket.
Sockets were originally created for applications on the same host, enabling one program (aka a process) running on the host to communicate with another. This is called Inter Process Communication (IPC).
There are two types of nested words:
- File-based: AF_UNIX
- Network-oriented: AF_INET (IPv4-oriented), AF_INET6 (IPv6-oriented)
DUP uses connectionless sockets
- Features: unreliable (intranet or more reliable), low overhead. In order to create UDP sockets, SOCK_DGRAM must be used as the socket type. The SOCK_DGRAM name of a UDP socket comes from the word "datagram".
2. Binding specific ports
Server.bind("", 8600)
bind means that the created Server will be bound to a specific port. Note:
As a UDP server, the IP address in front can be omitted, and the valid port number in the back ranges from 0 to 65535 (the port number less than 1024 is reserved for the system).
Setting up port reuse waiting (this step can be omitted)**
Server.setsockopt(socket.IPPROTO_IP, socket.SO_REUSEADDR, 1)
If the port has been used and the port link has been closed with Socket.close(), but the port has not yet been released, the above function can be used to wait for the port to be re-invoked.
4. Data acquisition
Msg, ClientAddr = Server.recvfrom(1024)
In UDP, recvform returns the ** byte stream (decimal, ASCII code, hexadecimal, etc.) sent by the client and the IP address of the client. 1024 indicates the size of the cached data.
5. Send data to client
Server.sendto(Data)
Usually UDP server sends heartbeat packet confirmation to client after receiving data, and data can be sent through this function.
6. Parsing data
Data = binascii.b2a_hex(Msg)
This function parses the transmitted byte stream message data into hexadecimal data. Opinions on relevant usage Byte stream conversion to ASCII code
7. Close the socket link for UDP
Server.close()
There's nothing to say, just have it, or you won't be able to continue using this port next time.
2.2 16-digit data parsing
1. Packet Time Resolution
Time = datetime.datetime.strptime(Data[26:38], "%y%m%d%H%M%S") # Resolution time
Because time is decimal data, there is no need to do hexadecimal conversion here, directly through datetime strptime method for data conversion.
2. Converting hexadecimal system to 10-decimal system and then to ASCII code
chr(int(Data[224 + (i - 2):224 + i],16))
int(num, 16) converts 16 to 10
Chr (decimal) parses the corresponding ASCII code
2.3 File Creation and Data Storage Analysis
I have to say that I encountered a lot of pits when I stored data files.
Pit 1: How to automatically create folder structure of year - > month - > day?
When creating folders, I have thought of using makedirs() function chain to create folders, but I always reported errors when judging whether the folder exists. I have always thought that it was caused by improper use of makedirs(), and I have thought of using chdir function and mkdir() function to create folders step by step. The final effect is as follows. Nor is it particularly good. Later, after careful examination of the data for a long time, it was found that:
if not os.path.exists(NewPath): os.makedirs(NewPath)
When judging whether a folder exists in the default IDLE, there has always been a problem that will cause an error. After a long time, it changed to:
if not os.path.isdir(FileDir): os.makedirs(FileDir)
No mistake. Take notes here to remind yourself.
These are all the mistakes I have summarized. I hope you can avoid these pits when you read this post. Below is my complete UDP message receiving and parsing code:
#!/usr/local/bin/python3 # coding:utf-8 import socket import binascii import datetime import os import csv ''' //Author: Zflyee Mailto: zflyee@126.com ''' Server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # Create UDP to transfer data # Server.setsockopt(socket.IPPROTO_IP, socket.SO_REUSEADDR, 1) # Fast Implementation of Port Multiplexing Server.bind(("", 8600)) print(u"Binded native port:8600,Data is being monitored...") def DataParsing(Data): Time = datetime.datetime.strptime(Data[26:38], "%y%m%d%H%M%S") # Resolution time Voltage = int(Data[44:46], 16) / 10.0 # Voltage data Temp = int(Data[60:64], 16) / 10.0 # Real-time temperature data Temp_1h_max = int(Data[70:74], 16) / 10.0 # Hourly maximum temperature Temp_1h_min = int(Data[80:84], 16) / 10.0 # Minimum Temperature Hour Hum = int(Data[90:94], 16) / 10.0 # Humidity data Hum_1h_max = int(Data[100:104], 16) / 10.0 # Maximum Humidity Hour Hum_1h_min = int(Data[110:114], 16) / 10.0 # Minimum Humidity Hour Pa = int(Data[120:124], 16) / 10.0 # Barometric data Pa_1h_max = int(Data[130:134], 16) / 10.0 # Maximum air pressure hourly Pa_1h_min = int(Data[150:154], 16) / 10.0 # Minimum air pressure hour WindSpd = int(Data[140:144], 16) / 10.0 # Instantaneous wind speed WindSpd_10min_avg = int(Data[160:164], 16) / 10.0 # Average 10-minute wind speed WindSpd_max = int(Data[170:174], 16) / 10.0 # Maximum current wind speed WindSpd_min = int(Data[180:184], 16) / 10.0 # Current minimum wind speed WindDir = int(Data[190:194], 16) / 10.0 # Current Wind Direction Instantaneous Value WindDir_10min_avg = int(Data[200:204], 16) / 10.0 # 10-minute mean wind direction Rain_1day = int(Data[210:214], 16) / 10.0 # Daily rainfall # Estimating the Length of Latitude Data Lati_len = int(Data[220:224], 16) # Conversion to 10-digit Lati = "" for i in range(2, Lati_len * 2, 2): Lati += (chr(int(Data[224 + (i - 2):224 + i], 16))) # Estimating Dimension Length and Data Long_len = int(Data[250:252], 16) Long = "" for i in range(2, Long_len * 2, 2): Long += (chr(int(Data[254 + (i - 2):254 + i], 16))) # Assemble data DataList = [Time, WindSpd, WindSpd_10min_avg, WindSpd_max, WindSpd_min, WindDir, WindDir_10min_avg, Temp, Temp_1h_max, Temp_1h_min, Hum, Hum_1h_max, Hum_1h_min, Pa, Pa_1h_max, Pa_1h_min, Rain_1day, Voltage] # Create a file path Path = "E:\\Fuoton\\data\\SY_FWS600\\" Text = os.path.join(Path, Time.strftime("%Y"), Time.strftime("%m")) + "\\" + Time.strftime("%d") + ".csv" FileDir = os.path.split(Text)[0] if not os.path.isdir(FileDir): os.makedirs(FileDir) # Write data with open(Text, "a+", newline="") as f: Writer = csv.writer(f) Writer.writerow(DataList) # Storage tips print(u"{}Time data has been successfully stored.".format(Time)) while True: try: Msg, ClientAddr = Server.recvfrom(1024) Data = binascii.b2a_hex(Msg) # Converting data into hexadecimal data Data = str(Data, encoding="utf-8") print(u"from{0}Of{1}The port gets the following data:\n{2}".format(ClientAddr[0], ClientAddr[1], Data)) if Data[0:2] == "7b": Content = "7B810010" + Data[8:30] + "7B" Response = binascii.a2b_hex(Content) Server.sendto(Response, ClientAddr) # Reply to client data print(u"Replied Client") elif Data[0:2] == '01': DataParsing(Data) else: print(u"%%%%%%%%%%%%%%%Data Error Reporting and Retrieval%%%%%%%%%%%%%%%") continue except: print(u"%%%%%%%%%%%%%%%Data Error Reporting and Retrieval%%%%%%%%%%%%%%%") continue Server.close()