传输层协议UDP

1.初步认识

udp属于传输层的协议,适用于更注重传输速度和实时性,并能容忍一定程度数据丢失的场景

以下是UDP的特征

特性 描述
无连接 发送数据前不需要建立连接,直接发送,减少了延迟和开销
不可靠传输 不保证数据包一定到达、不保证顺序、不提供重传机制
面向数据报 应用层交给UDP多长的报文,UDP就发送多少,保持报文边界
高效 头部开销小(仅8字节) ,没有拥塞控制,传输效率高
支持多播广播 支持一对一、一对多、多对多的通信方式

主要应用在以下场景:

•​实时音视频传输​:如视频会议、直播(VoIP)。少量丢包对体验影响不如延迟大。

•​在线游戏​:游戏状态更新对实时性要求极高。

域名解析(DNS)​​:查询请求小且需要快速响应。

物联网(IoT)通信​:许多传感器数据上报频率高,数据量小,且网络环境可能简单。

2.UDP协议的格式

UDP报文由首部数据两部分组成,其中首部只有8个字节,包含四个字段:

**源端口号(16位):**发送方端口号

**目的端口号(16位):**接受方端口号

**长度(16位):**指示整个UDP数据报(首部+数据)的长度

**校验和(16位):**用于检查数据在传输过程中是否出错(IPv4可选,IPv6必须)

3.UDP使用示例

UDP接受端

cpp 复制代码
#include <iostream>
#include <cstring>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h> // close()

int main() {
    // 1. 创建 UDP Socket
    int server_socket = socket(AF_INET, SOCK_DGRAM, 0);
    if (server_socket < 0) {
        std::cerr << "创建Socket失败!" << std::endl;
        return 1;
    }

    // 2. 绑定服务器地址和端口
    sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(server_addr)); // 清空结构体
    server_addr.sin_family = AF_INET;          // IPv4
    server_addr.sin_addr.s_addr = INADDR_ANY;   // 监听所有网卡
    server_addr.sin_port = htons(12345);       // 监听端口12345 (htons: 主机字节序转网络字节序)

    if (bind(server_socket, (sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
        std::cerr << "绑定端口失败!" << std::endl;
        close(server_socket);
        return 1;
    }

    std::cout << "UDP服务器已启动,正在端口 12345 监听..." << std::endl;

    // 3. 准备接收数据
    char buffer[1024]; // 接收缓冲区
    sockaddr_in client_addr; // 用于存储客户端地址
    socklen_t client_addr_len = sizeof(client_addr);

    while (true) {
        // 清空缓冲区
        memset(buffer, 0, sizeof(buffer));

        // 阻塞等待接收数据 (recvfrom)
        int bytes_received = recvfrom(
            server_socket,
            buffer,
            sizeof(buffer) - 1, // 留一个位置给字符串结束符 '\0'
            0,
            (sockaddr*)&client_addr,
            &client_addr_len
        );

        if (bytes_received < 0) {
            std::cerr << "接收数据出错!" << std::endl;
            continue; // 继续监听
        }

        // 打印收到的消息和客户端信息
        char client_ip[INET_ADDRSTRLEN];
        inet_ntop(AF_INET, &(client_addr.sin_addr), client_ip, INET_ADDRSTRLEN);
        std::cout << "收到来自 [" << client_ip << ":" << ntohs(client_addr.sin_port) << "] 的消息: "
                  << buffer << std::endl;

        // 4. (可选) 发送回复
        const char* reply = "服务器已收到你的消息!";
        sendto(
            server_socket,
            reply,
            strlen(reply),
            0,
            (sockaddr*)&client_addr,
            client_addr_len
        );
    }

    // 理论上不会执行到这里 (循环是 while true)
    close(server_socket);
    return 0;
}

UDP发送端

cpp 复制代码
#include <iostream>
#include <cstring>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h> // close()

int main() {
    // 1. 创建 UDP Socket
    int client_socket = socket(AF_INET, SOCK_DGRAM, 0);
    if (client_socket < 0) {
        std::cerr << "创建Socket失败!" << std::endl;
        return 1;
    }

    // 2. 设置目标服务器地址
    sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(12345); // 服务器端口

    // 将IP地址字符串转换为网络格式 (127.0.0.1 是本机回环地址)
    if (inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr) <= 0) {
        std::cerr << "无效的服务器地址!" << std::endl;
        close(client_socket);
        return 1;
    }

    // 3. 发送数据
    const char* message = "你好,UDP服务器!";
    int bytes_sent = sendto(
        client_socket,
        message,
        strlen(message),
        0,
        (sockaddr*)&server_addr,
        sizeof(server_addr)
    );

    if (bytes_sent < 0) {
        std::cerr << "发送失败!" << std::endl;
        close(client_socket);
        return 1;
    }

    std::cout << "已发送消息: " << message << std::endl;

    // 4. (可选) 等待并接收服务器的回复
    char buffer[1024];
    sockaddr_in from_addr;
    socklen_t from_addr_len = sizeof(from_addr);

    memset(buffer, 0, sizeof(buffer));
    int bytes_received = recvfrom(
        client_socket,
        buffer,
        sizeof(buffer) - 1,
        0,
        (sockaddr*)&from_addr,
        &from_addr_len
    );

    if (bytes_received < 0) {
        std::cerr << "接收回复失败!" << std::endl;
    } else {
        std::cout << "收到服务器回复: " << buffer << std::endl;
    }

    // 5. 关闭Socket
    close(client_socket);
    return 0;
}
相关推荐
拾光Ծ3 分钟前
【Linux网络】网络通信实战:UDP & TCP Socket编程实现Echo Server
linux·网络·网络协议·tcp/ip·udp·线程池
派葛穆11 分钟前
s7-200smart-tcp/ip通讯
网络协议·tcp/ip
星恒讯工业路由器13 小时前
5G FWA技术演进与趋势
网络·5g·信息与通信·4g·5g fwa·3gpp规范·fwa趋势
凌云C13 小时前
5G 协议体系与交互流程
网络协议
星夜夏空9915 小时前
网络编程(1)
服务器·网络
上海云盾-小余16 小时前
中小站点防护避坑:低价高防服务存在的各类安全短板剖析
网络·爬虫·安全·ddos
X7x518 小时前
跨厂商路由引入(重发布)实战指南:华为、华三、思科的逻辑差异与配置避坑
网络协议·信息与通信·信号处理·实施路由引入
数据知道18 小时前
邮件安全实战:SPF/DKIM/DMARC 配置与钓鱼绕过
网络·安全·web安全·网络安全·邮件安全
玩转4G物联网18 小时前
FS800DTU 新品上线|免费使用 DMP 设备管理平台,支持远程批量配置 & OTA 升级
物联网·网络协议·tcp/ip·云平台·核心板·fs800dtu·iot管理平台
王莎莎-MinerU18 小时前
MCP 解决的是工具接入,科研 Agent 还缺的是科学证据接口标准化
开发语言·网络·人工智能·深度学习·pdf·c#·php