DAY37 Getting Started with UDP Network Programming

Getting Started with UDP Network Programming

1. Basic Theories of Network Programming

1.1 Network Models: OSI Seven-Layer and TCP/IP Four-Layer

There are two core architectures for network communication. The OSI model is a general reference model, while the TCP/IP model is the practical application model for the Internet. Their corresponding relationships are as follows:

OSI Seven-Layer Model Core Functions TCP/IP Four-Layer Model Core Protocols/Technologies
Application Layer Provides network services for users (e-mail, file transfer, etc.) Application Layer HTTP, FTP, TFTP, DNS, SNMP
Presentation Layer Unifies data representation and completes data encryption/decryption Application Layer (Merged into the Application Layer in the TCP/IP model)
Session Layer Manages process sessions and coordinates communication processes Application Layer (Merged into the Application Layer in the TCP/IP model)
Transport Layer Manages end-to-end data transmission and provides reliable/unreliable services Transport Layer TCP (Reliable Transmission), UDP (Real-Time Transmission)
Network Layer Routing selection, internet interconnection, and locating target hosts Network Layer IP, ICMP (ping command), RIP, OSPF, IGMP
Data Link Layer Physical address addressing, data frame encapsulation, and error control Link Layer ARP (IP to MAC), RARP
Physical Layer Converts data into electrical signals and transmits them through network media Link Layer Network cards, twisted pair, optical fibers, wireless channels

1.2 Explanation of Core Concepts

(1) IP Address and Port
  • IP Address : Composed of network bits and host bits, it is used to identify hosts in the network. The mainstream version is IPv4 (32-bit, e.g., 192.168.14.128), and IPv6 will be gradually adopted in the future.
  • Port Number: Used to identify applications on a host, with a range of 1 to 65535. Ports 1 to 1023 are reserved for the system, and ports 1024 to 65535 are user-defined.
  • IP + Port: Uniquely identifies a specific application in the network and serves as the basic address identifier for network communication.
(2) Socket

A Socket is an interface between an application and the kernel network protocol stack, essentially a file descriptor. Through it, network data transmission and reception can be realized, which is the core entry point for network programming.

(3) Byte Order
  • Host Byte Order: Mainstream CPUs (Intel, AMD, ARM) adopt little-endian storage (low bytes are stored at low addresses).
  • Network Byte Order: Network devices uniformly adopt big-endian storage (high bytes are stored at low addresses).
  • Conversion Functions: htons() (Host to Network Short), inet_addr() (Converts dotted decimal IP to network byte order IP).
Command Function
ifconfig View/temporarily configure network information (e.g., ifconfig ens33 192.168.0.13/24 up to temporarily set the IP address)
sudo vim /etc/network/interfaces Edit the Ubuntu permanent network configuration file
sudo /etc/init.d/networking restart Restart the network service to load permanent configurations
ping www.baidu.com Test network connectivity
netstat -anp View all network communication connections and process associations on the local machine
sudo reboot -f Force restart the system to make network configurations take effect

1.3 DHCP and DNS

  • DHCP (Dynamic Host Configuration Protocol): Automatically assigns network parameters such as IP address, subnet mask, and gateway to the host without manual configuration.
  • DNS (Domain Name System) : Translates human-readable domain names (e.g., www.baidu.com) into machine-recognizable IP addresses, realizing the mapping from domain names to IP addresses.

2. Detailed Explanation of UDP Protocol

2.1 Core Features of UDP

UDP (User Datagram Protocol) is a connectionless transport layer protocol with the following core features:

  1. Connectionless: Communication parties do not need to establish a connection and can send data directly, saving the overhead of connection establishment.
  2. Low Latency: Without mechanisms such as confirmation and retransmission, data transmission is fast, suitable for real-time scenarios.
  3. Low Network Resource Utilization: The protocol header is simple (only 8 bytes), with low overhead.
  4. Unreliable Transmission: Does not guarantee the orderly arrival and integrity of data, and packet loss or out-of-order may occur.

2.2 Characteristics of UDP Datagrams

  1. There is a clear boundary between data packets, and the receiver can distinguish different data packets.
  2. The number of sending and receiving operations must correspond; if data is sent 10 times, the receiver also needs to call the receiving function 10 times to obtain the complete data.
  3. No write blocking: When the sending speed is too fast, the kernel buffer will be full, leading to data loss, and the sending rate needs to be controlled manually.
  4. With read blocking: If there is no data for the receiver to read, it will block and wait until data arrives.

2.3 UDP Communication Roles and Processes

(1) Communication Roles
  • Server: The end that provides services, usually only one. It is responsible for binding a fixed IP and port, and waiting for and processing client requests.
  • Client: The end that uses services, which can be multiple. It does not need to bind a fixed port and directly sends requests to the server.
(2) Function Call Process
Role Core Process Key Functions
Server Create Socket → Bind IP and Port → Cyclically Receive Client Data → Reply Data → Close Socket socket()bind()recvfrom()sendto()close()
Client Create Socket → Send Data to Server → Receive Server Reply → Close Socket socket()sendto()recvfrom()close()

3. UDP Practice: Timestamp Echo Service (Complete Code)

This section implements a simple UDP server that receives messages from the client, appends the current timestamp, and replies to the client. The client cyclically sends messages and receives replies, demonstrating the complete process of UDP communication.

3.1 Server Code (udp_server.c)

c 复制代码
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>

// Define an alias for the socket address structure pointer to simplify code
typedef struct sockaddr *(SA);

int main(int argc, char **argv)
{
    // 1. Create UDP socket
    // AF_INET: IPv4 address family, SOCK_DGRAM: UDP datagram socket, 0: Automatically adapt to the protocol
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (-1 == sockfd)
    {
        perror("socket create failed");
        return 1;
    }
    printf("UDP socket created successfully, socket descriptor: %d\n", sockfd);

    // 2. Initialize server address structure
    struct sockaddr_in ser_addr, cli_addr;
    bzero(&ser_addr, sizeof(ser_addr));  // Clear the structure memory
    bzero(&cli_addr, sizeof(cli_addr));
    ser_addr.sin_family = AF_INET;  // Specify the IPv4 address family
    ser_addr.sin_port = htons(50000);  // Convert port number to network byte order (50000 is a custom port)
    // Bind to the local IP (192.168.14.128), or use INADDR_ANY to bind all network card IPs
    ser_addr.sin_addr.s_addr = inet_addr("192.168.14.128");

    // 3. Bind the socket to the server IP + port
    int ret = bind(sockfd, (SA)&ser_addr, sizeof(ser_addr));
    if (-1 == ret)
    {
        perror("bind failed");
        close(sockfd);
        return 1;
    }
    printf("Socket bound successfully, IP: 192.168.14.128, Port: 50000\n");

    // 4. Cyclically receive client data and reply
    socklen_t cli_addr_len = sizeof(cli_addr);  // Client address length
    while (1)
    {
        char buf[512] = {0};  // Receive buffer

        // Receive client data (blocking wait)
        // (SA)&cli_addr: Used to store client address information, &cli_addr_len: Client address length
        ssize_t recv_len = recvfrom(sockfd, buf, sizeof(buf), 0, (SA)&cli_addr, &cli_addr_len);
        if (recv_len < 0)
        {
            perror("recvfrom failed");
            continue;
        }
        // Print client information and received data
        printf("Received message from client [%s:%d]: %s\n", 
               inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port), buf);

        // Get the current system time and append it to the received message
        time_t current_time;
        time(&current_time);
        struct tm *time_info = localtime(&current_time);
        sprintf(buf, "%s %02d:%02d:%02d", buf, 
                time_info->tm_hour, time_info->tm_min, time_info->tm_sec);

        // Reply to the client
        ssize_t send_len = sendto(sockfd, buf, strlen(buf) + 1, 0, (SA)&cli_addr, cli_addr_len);
        if (send_len < 0)
        {
            perror("sendto failed");
            continue;
        }
        printf("Replied to client [%s:%d]: %s\n", 
               inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port), buf);
    }

    // 5. Close the socket (this will not be executed in practice due to the while(1) loop; terminate with Ctrl+C)
    close(sockfd);
    return 0;
}
Key Analysis of Server Code
  • socket(AF_INET, SOCK_DGRAM, 0): Creates an IPv4 UDP socket and returns a file descriptor.
  • bind(): Binds the socket to a fixed IP and port. The server must bind, otherwise the client cannot locate the server.
  • recvfrom(): Receives client data and obtains client address information for replying.
  • sendto(): Replies to the specified client address, which requires passing the client address structure.
  • htons()/inet_addr(): Converts host byte order to network byte order to ensure cross-device communication compatibility.

3.2 Client Code (udp_client.c)

c 复制代码
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>

typedef struct sockaddr *(SA);

int main(int argc, char **argv)
{
    // 1. Create UDP socket
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (-1 == sockfd)
    {
        perror("socket create failed");
        return 1;
    }
    printf("UDP client socket created successfully\n");

    // 2. Initialize server address structure (specify server IP and port)
    struct sockaddr_in ser_addr;
    bzero(&ser_addr, sizeof(ser_addr));
    ser_addr.sin_family = AF_INET;
    ser_addr.sin_port = htons(50000);  // Consistent with the server port
    ser_addr.sin_addr.s_addr = inet_addr("192.168.14.128");  // Server IP

    // 3. Cyclically send messages to the server and receive replies
    int send_count = 10;  // Send messages 10 times cyclically
    while (send_count--)
    {
        char buf[512] = "hello";  // Message to be sent
        // Send data to the server
        ssize_t send_len = sendto(sockfd, buf, strlen(buf), 0, (SA)&ser_addr, sizeof(ser_addr));
        if (send_len < 0)
        {
            perror("sendto failed");
            close(sockfd);
            return 1;
        }
        printf("Sent message to server: %s (Remaining sending times: %d)\n", buf, send_count);

        // Receive server reply
        bzero(buf, sizeof(buf));  // Clear the receive buffer
        ssize_t recv_len = recvfrom(sockfd, buf, sizeof(buf), 0, NULL, NULL);
        if (recv_len < 0)
        {
            perror("recvfrom failed");
            close(sockfd);
            return 1;
        }
        printf("Received reply from server: %s\n", buf);

        sleep(1);  // Send once every 1 second
    }

    // 4. Close the socket
    close(sockfd);
    printf("Client exited normally\n");
    return 0;
}
Key Analysis of Client Code
  • The client does not need to call bind(): The kernel will automatically assign a random port and local IP to the client, which does not affect communication with the server.
  • sendto(): Sends data directly to the server address, which requires specifying the server's IP and port.
  • recvfrom(NULL, NULL): The client does not need to care about the server address (already clear), so pass NULL to ignore the server address information.
  • sleep(1): Controls the sending rate to avoid packet loss caused by too fast sending.

4. Compilation and Running Steps

4.1 Environment Preparation

  1. Install Compilation Environment : Install the gcc compiler in the Ubuntu system

    bash 复制代码
    sudo apt update && sudo apt install gcc -y
  2. Configure Network : Ensure the server and client are in the same local area network, or achieve communication through bridge mode

    • Temporarily set the server IP: ifconfig ens33 192.168.14.128/24 up
    • Test network connectivity: ping 192.168.14.128 (The client pings the server to ensure smooth network)

4.2 Compile Code

bash 复制代码
# Compile the server
gcc udp_server.c -o udp_server
# Compile the client
gcc udp_client.c -o udp_client

4.3 Run the Program

Step 1: Start the Server (Run First)
bash 复制代码
./udp_server

Server Output:

复制代码
UDP socket created successfully, socket descriptor: 3
Socket bound successfully, IP: 192.168.14.128, Port: 50000
Step 2: Start the Client (Open a New Terminal and Run Later)
bash 复制代码
./udp_client

Client Output (Example):

复制代码
UDP client socket created successfully
Sent message to server: hello (Remaining sending times: 9)
Received reply from server: hello 15:30:25
Sent message to server: hello (Remaining sending times: 8)
Received reply from server: hello 15:30:26
...
Client exited normally
Step 3: View Server Output (Example)
复制代码
Received message from client [192.168.14.129:41235]: hello
Replied to client [192.168.14.129:41235]: hello 15:30:25
Received message from client [192.168.14.129:41235]: hello
Replied to client [192.168.14.129:41235]: hello 15:30:26
...

5. Troubleshooting Common Issues

  1. bind() Failed: Address already in use

    • Cause: Port 50000 is already occupied by another process.
    • Solution: Use netstat -anp | grep 50000 to find the occupying process, kill the process, or replace the port.
  2. Unable to Receive/Send Data

    • Check if the IP addresses of the server and client are correct and ensure they are in the same network segment.
    • Check if the firewall is blocking the UDP port; you can disable the firewall (sudo ufw disable).
    • Confirm that the network mode is bridge mode to avoid network segment isolation caused by NAT mode.
  3. Data Loss

    • Cause: UDP has no flow control, and the kernel buffer overflows due to too fast sending rate.
    • Solution: Add sleep() in the client to control the sending rate, or implement flow control at the application layer.

6. Summary and Expansion

6.1 Article Summary

  1. Network Models: The OSI seven-layer is a reference model, and the TCP/IP four-layer is a practical application model; their corresponding relationships need to be kept in mind.
  2. UDP Features: Connectionless, low latency, unreliable, suitable for real-time scenarios; datagrams have clear boundaries, and the number of sending and receiving operations must correspond.
  3. UDP Programming Process: Server (Create Socket → Bind → Receive/Send Data), Client (Create Socket → Send/Receive Data).
  4. Core Functions: socket(), bind(), recvfrom(), and sendto() are the basics of UDP programming.

6.2 Expansion Directions

  1. Multi-Client Communication : The server can obtain addresses of different clients through recvfrom() to achieve one-to-many communication.
  2. Data Verification: UDP does not guarantee reliability; you can add checksum and retransmission mechanisms at the application layer to improve data transmission reliability.
  3. Comparative Learning of TCP and UDP: TCP is connection-oriented reliable transmission, suitable for scenarios such as file transfer; you can further learn TCP programming.
  4. Advanced Network Programming: Learn advanced technologies such as socket option settings, non-blocking IO, and multiplexing (select/poll/epoll).
相关推荐
JIes__2 小时前
网络协议——传输层协议
网络协议
我爱拉臭臭2 小时前
socket前置知识
网络
北京耐用通信2 小时前
告别布线烦恼:耐达讯自动化Profibus六路中继器如何让您的网络“无限续航”
人工智能·物联网·网络协议·自动化·信息与通信
HIT_Weston2 小时前
73、【Ubuntu】【Hugo】搭建私人博客:Hugo&PaperMod 兼容问题
linux·运维·ubuntu
麒qiqi2 小时前
OSI 模型到 UDP 套接字
网络·网络协议·udp
WX131695189982 小时前
是德科技E5080A E5080B安捷伦E5071C网络分析仪
网络·科技
卓豪终端管理2 小时前
每周5小时“隐形流失”,如何精准锁定并回收?
网络·安全·web安全
skywalk81632 小时前
为什么Linux系统里用户id和组id不一样?怎么改成一样呢?
linux·服务器
HIT_Weston2 小时前
72、【Ubuntu】【Hugo】搭建私人博客:Git 下载方式对比
linux·git·ubuntu