传输层协议UDP

发布于:2025-09-12 ⋅ 阅读:(23) ⋅ 点赞:(0)

1.初步认识

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

以下是UDP的特征

特性

描述

无连接

发送数据前不需要建立连接,直接发送,减少了延迟和开销

不可靠传输

不保证数据包一定到达、不保证顺序、不提供重传机制

面向数据报

应用层交给UDP多长的报文,UDP就发送多少,保持报文边界

高效

头部开销小(仅8字节)

,没有拥塞控制,传输效率高

支持多播广播

支持一对一、一对多、多对多的通信方式

主要应用在以下场景:

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

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

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

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

2.UDP协议的格式

     

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

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

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

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

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

3.UDP使用示例

UDP接受端

#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发送端

#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;
}


网站公告

今日签到

点亮在社区的每一天
去签到