传输层协议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;
}
相关推荐
2301_780789669 小时前
智能汽车的“软肋”:车载系统漏洞分析与安全防护框架初探
网络·安全·车载系统·汽车·ddos
Escalating_xu9 小时前
【Linux 网络编程】IP 分片与重组:3000 字节的数据报,怎样拆开又拼回来?
linux·网络·tcp/ip
OpenLoong 开源社区10 小时前
打破 NAT 限制,零侵入跨网络通信:基于 WebRTC 的透明 TCP 隧道跨网络通信方案
网络协议·tcp/ip·开源·webrtc·openloong开源社区
风娜10 小时前
【Linux网络】UDP 服务器怎么写?从 socket、bind 到 recvfrom/sendto,手写完整回显服务器
linux·服务器·网络
从琳开始98910 小时前
从Socket到UDP回显服务器:Java网络编程完整指南
java·网络·网络协议·udp·java-ee
Lhan.zzZ10 小时前
用 Qt 构建线程安全的通讯静态库:从线程亲和性到完整工程
c++·vscode·qt·tcp/ip·udp
Gauss松鼠会10 小时前
GaussDB 整体架构解析
运维·服务器·网络·数据库·sql·架构·gaussdb
sinovoip10 小时前
Banana Pi BPI-RT2 WiFi 6 路由器板采用 Realtek RTL8198D 双核 MIPS SoC。
网络·智能路由器
xiaoye-duck10 小时前
《C++ 项目:手写大模型接入 SDK》DeepSeek接口设计(上):初始化和全量响应
开发语言·网络·c++·语言模型
Yang961111 小时前
鼎讯信通热剥钳实测:大芯径光纤如何做到无损剥除
网络