传输层协议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 小时前
【深度长文】万字攻克网络原理:从 HTTP 报文解构到 HTTPS 终极加密逻辑
java·开发语言·网络·python·http·ai·https
王达舒19943 小时前
HTTP vs HTTPS: 终极解析,保护你的数据究竟有多重要?
网络协议·http·https
朱皮皮呀3 小时前
HTTPS的工作过程
网络协议·http·https
Binary-Jeff3 小时前
一文读懂 HTTPS 协议及其工作流程
网络协议·web安全·http·https
盟接之桥6 小时前
盟接之桥说制造:引流品 × 利润品,全球电商平台高效产品组合策略(供讨论)
大数据·linux·服务器·网络·人工智能·制造
会员源码网6 小时前
理财源码开发:单语言深耕还是多语言融合?看完这篇不踩坑
网络·个人开发
米羊1217 小时前
已有安全措施确认(上)
大数据·网络
ManThink Technology8 小时前
如何使用EBHelper 简化EdgeBus的代码编写?
java·前端·网络
珠海西格电力科技9 小时前
微电网能量平衡理论的实现条件在不同场景下有哪些差异?
运维·服务器·网络·人工智能·云计算·智慧城市
QT.qtqtqtqtqt9 小时前
未授权访问漏洞
网络·安全·web安全