Send and Receive Structure with Mixed Data Types over UDP
This example shows how to send and receive a structure containing mixed data types over User Datagram Protocol (UDP). To send data over UDP, you must first serialize the structure by converting its data into bytes, also known as packing the data. To receive UDP data, deserialize the data by converting the bytes back to the original structure. This example illustrates this process using a structure containing numeric scalar values of different types.
Define Data Structure
Define a structure containing data of multiple MATLAB® data types. The structure in this example includes double data and two types of integer data.
dataStruct = struct(temperature=88.8, ... humidity=uint8(65), ... pressure=37.4, ... sampleNumber=uint32(24))
dataStruct = struct with fields:
temperature: 88.8000
humidity: 65
pressure: 37.4000
sampleNumber: 24
Clear any existing UDP port connections.
delete(udpportfind);
Create UDP Ports
Create two UDP interfaces using udpport
, one to send and one to receive data. In this example, you send and receive the data in the same MATLAB session. In practice, you might send and receive data between multiple devices or different MATLAB sessions.
udpSender = udpport
udpSender = UDPPort with properties: IPAddressVersion: "IPV4" LocalHost: "0.0.0.0" LocalPort: 51954 Tag: "" NumBytesAvailable: 0 Show all properties, functions
udpReceiverIPAddress = "127.0.0.1"; udpReceiverPort = 3232; udpReceiver = udpport(LocalHost=udpReceiverIPAddress, ... LocalPort=udpReceiverPort)
udpReceiver = UDPPort with properties: IPAddressVersion: "IPV4" LocalHost: "127.0.0.1" LocalPort: 3232 Tag: "" NumBytesAvailable: 0 Show all properties, functions
Convert Structure into Byte Array
To serialize the data for sending over UDP, convert the structure data into bytes. You can write your own MATLAB function to perform this conversion. For instance, the packStructToBytes
function converts the data for each field of the structure into uint8 format and then adds the resulting bytes to an array. The function assumes the data structure contains only numeric scalar values.
function packedStruct = packStructToBytes(dataStruct) packedStruct = []; fieldNames = fieldnames(dataStruct); for i = 1:numel(fieldNames) fieldData = dataStruct.(fieldNames{i}); fieldBytes = typecast(fieldData,"uint8"); packedStruct = [packedStruct,fieldBytes]; end end
Use the packStructToBytes
function to pack your data into an array of bytes.
packedStruct = packStructToBytes(dataStruct)
packedStruct = 1×21 uint8 row vector
51 51 51 51 51 51 86 64 65 51 51 51 51 51 179 66 64 24 0 0 0
When you send and receive data over UDP, knowing the exact number of bytes to be read can help avoid incomplete and inaccurate data retrieval. Calculate the total number of bytes needed to represent all of the data in your structure.
totalSize = numel(packedStruct)
totalSize = 21
Check whether this data size exceeds the output packet size specified in the OutputDatagramSize
property of the sending UDP interface.
udpSender.OutputDatagramSize
ans = 512
In this case, the data fits into a single output packet. When the data size exceeds output packet size of the sender interface, MATLAB automatically breaks the data into multiple packets. Sending UDP data in multiple packets can introduce errors if the packets arrive out of order or are lost. To avoid such errors when sending data larger than the default output packet size of 512 bytes, increase the packet size by adjusting OutputDatagramSize
to accommodate the data in one packet. (For Ethernet, the recommended maximum data size is 1500 bytes.)
Send Data
Send the array of bytes over UDP.
write(udpSender,packedStruct,udpReceiverIPAddress,udpReceiverPort);
Receive Data
Receive the array of bytes using the read
function.
receivedData = read(udpReceiver,totalSize)
receivedData = 1×21
51 51 51 51 51 51 86 64 65 51 51 51 51 51 179 66 64 24 0 0 0
Based on the order of the fields and the number of bytes for each corresponding data type, extract the bytes for each field. The unpackStructFromBytes
function performs the extraction, assuming the structure contains only numeric values.
function receivedStruct = unpackStructFromBytes(receivedData,fieldNames,fieldTypes) receivedStruct = struct(); startIndex = 1; for i = 1:numel(fieldNames) fieldType = fieldTypes{i}; switch fieldType case {"double","uint64","int64"} numBytes = 8; case {"single","uint32","int32"} numBytes = 4; case {"uint16","int16"} numBytes = 2; case {"uint8","int8"} numBytes = 1; end fieldBytes = receivedData(startIndex:startIndex + numBytes - 1); fieldValue = typecast(uint8(fieldBytes),fieldType); receivedStruct.(fieldNames{i}) = fieldValue; startIndex = startIndex + numBytes; end end
The function also assumes that the receiving session has access to the field names and the corresponding data types of the original structure and accepts these values in string arrays. Use this function with the received byte data, known field names, and known field types to reconstruct the original structure.
fieldNames = ["temperature","humidity","pressure","sampleNumber"]; fieldTypes = ["double","uint8","double","uint32"]; receivedStruct = unpackStructFromBytes(receivedData,fieldNames,fieldTypes)
receivedStruct = struct with fields:
temperature: 88.8000
humidity: 65
pressure: 37.4000
sampleNumber: 24
Close UDP Connections
When you finish sending and receiving data, close the UDP connections.
clear udpSender clear udpReceiver