Datagram Socket (UDP)
The figure below reproduces a diagram that introduces sample code using the typical socket functions for a UDP client-server application. The example uses the Micrium proprietary socket API function calls. A similar example could be written using the BSD socket API.
Figure - µC/TCP-IP Socket calls used in a typical UDP client-server application
The code in the listing below implements a UDP server. It opens a socket and binds an IP address, listens and waits for a packet to arrive at the specified port.
Datagram Server (UDP Server)
Listing - Datagram Server
#include <Source/net_cfg_net.h> #include <Source/net_sock.h> #include <Source/net_app.h> #include <Source/net_util.h> #define UDP_SERVER_PORT 10001 #define RX_BUF_SIZE 15 #ifdef NET_IPv4_MODULE_EN void App_UDP_ServerIPv4 (void) { NET_SOCK_ID sock; NET_SOCK_ADDR_IPv4 server_sock_addr_ip; NET_SOCK_ADDR_IPv4 client_sock_addr_ip; NET_SOCK_ADDR_LEN client_sock_addr_ip_size; NET_SOCK_RTN_CODE rx_size; NET_SOCK_RTN_CODE tx_size; NET_SOCK_DATA_SIZE tx_rem; CPU_CHAR rx_buf[RX_BUF_SIZE]; CPU_INT32U addr_any = NET_IPv4_ADDR_ANY; void *p_buf; CPU_BOOLEAN fault_err; NET_ERR err; /* ----------------- OPEN IPV4 SOCKET ----------------- */ sock = NetSock_Open( NET_SOCK_ADDR_FAMILY_IP_V4, NET_SOCK_TYPE_DATAGRAM, NET_SOCK_PROTOCOL_UDP, &err); if (err != NET_SOCK_ERR_NONE) { return; } /* ------------ CONFIGURE SOCKET'S ADDRESS ------------ */ NetApp_SetSockAddr((NET_SOCK_ADDR *)&server_sock_addr_ip, NET_SOCK_ADDR_FAMILY_IP_V4, UDP_SERVER_PORT, (CPU_INT08U *)&addr_any, NET_IPv4_ADDR_SIZE, &err); switch (err) { case NET_APP_ERR_NONE: break; case NET_APP_ERR_FAULT: case NET_APP_ERR_NONE_AVAIL: case NET_APP_ERR_INVALID_ARG: default: NetSock_Close(sock, &err); return; } /* ------------------- BIND SOCKET -------------------- */ NetSock_Bind( sock, (NET_SOCK_ADDR *)&server_sock_addr_ip, NET_SOCK_ADDR_SIZE, &err); if (err != NET_SOCK_ERR_NONE) { NetSock_Close(sock, &err); return; } fault_err = DEF_NO; do { /* ----- WAIT UNTIL RECEIVING DATA FROM A CLIENT ------ */ client_sock_addr_ip_size = sizeof(client_sock_addr_ip); rx_size = NetSock_RxDataFrom( sock, rx_buf, RX_BUF_SIZE, NET_SOCK_FLAG_NONE, (NET_SOCK_ADDR *)&client_sock_addr_ip, &client_sock_addr_ip_size, DEF_NULL, DEF_NULL, DEF_NULL, &err); switch (err) { case NET_SOCK_ERR_NONE: tx_rem = rx_size; p_buf = rx_buf; /* ----- TRANSMIT THE DATA RECEIVED TO THE CLIENT ----- */ do { tx_size = NetSock_TxDataTo( sock, p_buf, tx_rem, NET_SOCK_FLAG_NONE, (NET_SOCK_ADDR *)&client_sock_addr_ip, client_sock_addr_ip_size, &err); tx_rem -= tx_size; p_buf += tx_size; } while (tx_rem > 0); break; case NET_SOCK_ERR_RX_Q_EMPTY: case NET_ERR_FAULT_LOCK_ACQUIRE: break; default: fault_err = DEF_YES; break; } } while (fault_err == DEF_NO); /* ------------- FATAL FAULT SOCKET ERROR ------------- */ NetSock_Close(sock, &err); /* This function should be reached only when a fatal ...*/ /* fault error has occurred. */ } #endif /* ********************************************************************************************************* * App_UDP_ServerIPv6() * * Description : UDP Echo server: * * (a) Open a socket. * (b) Configure socket's address. * (c) Bind that socket. * (d) Receive data on the socket. * (e) Transmit to source the data received. * (f) Close socket on fatal fault error. * * Argument(s) : none. * * Return(s) : none. * * Caller(s) : none. * * Note(s) : none. ********************************************************************************************************* */ #ifdef NET_IPv6_MODULE_EN void App_UDP_ServerIPv6 (void) { NET_SOCK_ID sock; NET_SOCK_ADDR_IPv6 server_sock_addr_ip; NET_SOCK_ADDR_IPv6 client_sock_addr_ip; NET_SOCK_ADDR_LEN client_sock_addr_ip_size; NET_SOCK_RTN_CODE rx_size; NET_SOCK_RTN_CODE tx_size; NET_SOCK_DATA_SIZE tx_rem; CPU_CHAR rx_buf[RX_BUF_SIZE]; void *p_buf; CPU_BOOLEAN fault_err; NET_ERR err; /* ----------------- OPEN IPV6 SOCKET ----------------- */ sock = NetSock_Open( NET_SOCK_ADDR_FAMILY_IP_V6, /* IPv6 Socket family. */ NET_SOCK_TYPE_DATAGRAM, /* Datagram socket. */ NET_SOCK_PROTOCOL_UDP, /* UDP protocol. */ &err); if (err != NET_SOCK_ERR_NONE) { return; } /* ------------ CONFIGURE SOCKET'S ADDRESS ------------ */ /* Populate the NET_SOCK_ADDR_IP structure for the ... */ /* server address and port, and convert it to ... */ /* network order. */ NetApp_SetSockAddr((NET_SOCK_ADDR *)&server_sock_addr_ip, NET_SOCK_ADDR_FAMILY_IP_V6, UDP_SERVER_PORT, (CPU_INT08U *)&NET_IPv6_ADDR_ANY, NET_IPv6_ADDR_SIZE, &err); switch (err) { case NET_APP_ERR_NONE: break; case NET_APP_ERR_FAULT: case NET_APP_ERR_NONE_AVAIL: case NET_APP_ERR_INVALID_ARG: default: NetSock_Close(sock, &err); return; } /* ------------------- BIND SOCKET -------------------- */ NetSock_Bind( sock, /* Bind the newly created socket to the address and ... */ (NET_SOCK_ADDR *)&server_sock_addr_ip, /* port specified by server_sock_addr_ip. */ NET_SOCK_ADDR_SIZE, &err); if (err != NET_SOCK_ERR_NONE) { NetSock_Close(sock, &err); return; } fault_err = DEF_NO; do { /* ----- WAIT UNTIL RECEIVING DATA FROM A CLIENT ------ */ client_sock_addr_ip_size = sizeof(client_sock_addr_ip); rx_size = NetSock_RxDataFrom( sock, /* Receive data from any host on port UDP_SERVER_PORT. */ rx_buf, RX_BUF_SIZE, NET_SOCK_FLAG_NONE, (NET_SOCK_ADDR *)&client_sock_addr_ip, &client_sock_addr_ip_size, DEF_NULL, DEF_NULL, DEF_NULL, &err); switch (err) { case NET_SOCK_ERR_NONE: tx_rem = rx_size; p_buf = rx_buf; do { /* ------- TRANSMIT RECEIVED DATA TO THE CLIENT ------- */ /* Transmit data to IP address and port of the client. */ tx_size = NetSock_TxDataTo( sock, p_buf, tx_rem, NET_SOCK_FLAG_NONE, (NET_SOCK_ADDR *)&client_sock_addr_ip, client_sock_addr_ip_size, &err); tx_rem -= tx_size; p_buf += tx_size; } while (tx_rem > 0); break; case NET_SOCK_ERR_RX_Q_EMPTY: case NET_ERR_FAULT_LOCK_ACQUIRE: break; default: fault_err = DEF_YES; break; } } while (fault_err == DEF_NO); /* Process more client requests. */ /* ------------- FATAL FAULT SOCKET ERROR ------------- */ NetSock_Close(sock, &err); /* This function should be reached only when a fatal ...*/ /* fault error has occurred. */ } #endif
- Open a datagram socket (UDP protocol).
- Populate the
NET_SOCK_ADDR_IP
structure for the server address and port, and convert it to network order. - Bind the newly created socket to the address and port specified by
server_sock_addr_ip
. - Receive data from any host on port
DATAGRAM_SERVER_PORT
. - Close the socket.
Datagram Client (UDP Client)
The code in the listing below implements a UDP client. It sends a ‘Hello World!’
message to a server that listens on the UDP_SERVER_PORT
.
Listing - Datagram Server
#define UDP_SERVER_IP_ADDR "192.168.1.100" #define UDP_SERVER_PORT 10001 #define UDP_SERVER_TX_STR "Hello World!" CPU_BOOLEAN TestUDPClient (void) { NET_SOCK_ID sock; NET_IP_ADDR server_ip_addr; NET_SOCK_ADDR_IP server_sock_addr_ip; NET_SOCK_ADDR_LEN server_sock_addr_ip_size; CPU_CHAR *pbuf; CPU_INT16S buf_len; NET_SOCK_RTN_CODE tx_size; NET_ERR err; pbuf = UDP_SERVER_TX_STR; buf_len = Str_Len(UDP_SERVER_TX_STR); sock = NetSock_Open( NET_SOCK_ADDR_FAMILY_IP_V4, (1) NET_SOCK_TYPE_DATAGRAM, NET_SOCK_PROTOCOL_UDP, &err); if (err != NET_SOCK_ERR_NONE) { return (DEF_FALSE); } server_ip_addr = NetASCII_Str_to_IP(UDP_SERVER_IP_ADDR, &err); (2) if (err != NET_ASCII_ERR_NONE) { NetSock_Close(sock, &err); return (DEF_FALSE); } server_sock_addr_ip_size = sizeof(server_sock_addr_ip); (3) Mem_Clr((void *)&server_sock_addr_ip, (CPU_SIZE_T) server_sock_addr_ip_size); server_sock_addr_ip.AddrFamily = NET_SOCK_ADDR_FAMILY_IP_V4; server_sock_addr_ip.Addr = NET_UTIL_HOST_TO_NET_32(server_ip_addr); server_sock_addr_ip.Port = NET_UTIL_HOST_TO_NET_16(UDP_SERVER_PORT); tx_size = NetSock_TxDataTo((NET_SOCK_ID ) sock, (4) (void *) pbuf, (CPU_INT16S ) buf_len, (CPU_INT16S ) NET_SOCK_FLAG_NONE, (NET_SOCK_ADDR *)&server_sock_addr_ip, (NET_SOCK_ADDR_LEN) sizeof(server_sock_addr_ip), (NET_ERR *)&err); NetSock_Close(sock, &err); (5) if (err != NET_SOCK_ERR_NONE) { return (DEF_FALSE); } return (DEF_TRUE); }
- Open a datagram socket (UDP protocol).
- Convert an IPv4 address from ASCII dotted-decimal notation to a network protocol IPv4 address in host-order.
- Populate the
NET_SOCK_ADDR_IP
structure for the server address and port, and convert it to network order. - Transmit data to host
DATAGRAM_SERVER_IP_ADDR
on portDATAGRAM_SERVER_PORT
. - Close the socket.