当前位置: 首页 > news >正文

【实时Linux实战系列】实时数据流的网络传输

在实时系统中,数据流的实时传输是许多应用场景的核心需求之一。无论是工业自动化中的传感器数据、金融交易中的高频数据,还是多媒体应用中的视频流,都需要在严格的时间约束内完成数据的传输。实时数据流的传输不仅要求高吞吐量,还要求低延迟和高可靠性。掌握实时数据流的网络传输技能对于开发者来说至关重要,它可以帮助开发者设计出更加高效和可靠的实时系统。

本文将通过实际案例,详细介绍如何在实时 Linux 下实现数据流的实时传输,包括优化网络传输延迟的技术手段及方案。我们将从基本的网络传输概念入手,逐步深入到具体的实现细节和优化方法。

核心概念

1. 实时数据流

实时数据流是指需要在严格的时间约束内传输的数据序列。实时数据流的特性包括:

  • 时间敏感性:数据必须在规定的时间内到达目的地,否则可能失去价值。

  • 高吞吐量:数据流通常包含大量数据,需要高效的传输机制。

  • 可靠性:数据传输过程中需要保证数据的完整性和准确性。

2. 网络传输延迟

网络传输延迟是指数据从发送端到接收端所需的时间。延迟的来源包括:

  • 处理延迟:数据在发送端和接收端的处理时间。

  • 传输延迟:数据在物理介质中的传输时间。

  • 排队延迟:数据在网络节点(如路由器、交换机)中的排队时间。

  • 传播延迟:信号在物理介质中的传播时间。

3. 实时 Linux

实时 Linux 是一种经过优化的 Linux 系统,能够提供低延迟和高确定性的任务调度。它通过实时补丁(如 PREEMPT_RT)来增强 Linux 内核的实时性,适用于需要高实时性的应用场景。

4. 传输协议

传输协议是数据在网络中传输的规则。常见的传输协议包括:

  • TCP(传输控制协议):提供可靠的、面向连接的传输服务,适用于对可靠性要求较高的场景。

  • UDP(用户数据报协议):提供无连接的、不可靠的传输服务,适用于对实时性要求较高的场景。

  • RTP(实时传输协议):专门用于实时数据流的传输,支持数据的时间戳和序列号,适用于多媒体应用。

环境准备

1. 操作系统

  • 推荐系统:Ubuntu 20.04 或更高版本(建议使用实时内核,如 PREEMPT_RT)。

  • 安装实时内核

    1. 添加实时内核 PPA:

    2. sudo add-apt-repository ppa:longsleep/golang-backports
      sudo add-apt-repository ppa:ubuntu-toolchain-r/test
      sudo add-apt-repository ppa:realtime-linux/ppa
      sudo apt update
    3. 安装实时内核:

    4. sudo apt install linux-image-rt-amd64
    5. 重启系统并选择实时内核启动。

2. 开发工具

  • 推荐工具gcc(用于编译 C 程序)。

  • 安装方法

  • sudo apt update
    sudo apt install build-essential

3. 测试工具

  • 推荐工具iperf3(用于测试网络带宽和延迟)。

  • 安装方法

  • sudo apt install iperf3

实际案例与步骤

1. 使用 UDP 实现实时数据流传输

示例代码

以下代码展示了如何使用 UDP 实现实时数据流的传输。UDP 是一种无连接的协议,适用于对实时性要求较高的场景。

// sender.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>#define PORT 8080
#define BUFFER_SIZE 1024int main() {int sockfd;struct sockaddr_in servaddr;// 创建 UDP 套接字if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {perror("socket creation failed");exit(EXIT_FAILURE);}memset(&servaddr, 0, sizeof(servaddr));// 配置服务器地址servaddr.sin_family = AF_INET;servaddr.sin_port = htons(PORT);servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");char buffer[BUFFER_SIZE];while (1) {printf("Enter data to send: ");fgets(buffer, BUFFER_SIZE, stdin);// 发送数据sendto(sockfd, buffer, strlen(buffer), 0, (const struct sockaddr*)&servaddr, sizeof(servaddr));}close(sockfd);return 0;
}

 

// receiver.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>#define PORT 8080
#define BUFFER_SIZE 1024int main() {int sockfd;struct sockaddr_in servaddr, cliaddr;// 创建 UDP 套接字if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {perror("socket creation failed");exit(EXIT_FAILURE);}memset(&servaddr, 0, sizeof(servaddr));memset(&cliaddr, 0, sizeof(cliaddr));// 配置服务器地址servaddr.sin_family = AF_INET;servaddr.sin_addr.s_addr = htonl(INADDR_ANY);servaddr.sin_port = htons(PORT);// 绑定套接字if (bind(sockfd, (const struct sockaddr*)&servaddr, sizeof(servaddr)) < 0) {perror("socket bind failed");exit(EXIT_FAILURE);}char buffer[BUFFER_SIZE];int n;socklen_t len = sizeof(cliaddr);while (1) {// 接收数据n = recvfrom(sockfd, buffer, BUFFER_SIZE, 0, (struct sockaddr*)&cliaddr, &len);buffer[n] = '\0';printf("Received data: %s\n", buffer);}close(sockfd);return 0;
}
编译与运行
  1. 编译代码:

  2. gcc -o sender sender.c
    gcc -o receiver receiver.c
  3. 运行程序:

    • 在一个终端运行接收端:

  4. ./receiver
  5. 在另一个终端运行发送端:

  6. ./sender
    代码说明
    • UDP 套接字:使用 socket 函数创建 UDP 套接字。

    • 发送数据:使用 sendto 函数发送数据。

    • 接收数据:使用 recvfrom 函数接收数据。

    • 服务器地址:配置服务器的 IP 地址和端口号。

    2. 使用 TCP 实现实时数据流传输

    示例代码

    以下代码展示了如何使用 TCP 实现实时数据流的传输。TCP 是一种面向连接的协议,适用于对可靠性要求较高的场景。

    c

    复制

    // tcp_server.c
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <arpa/inet.h>#define PORT 8080
    #define BUFFER_SIZE 1024int main() {int sockfd, connfd;struct sockaddr_in servaddr, cliaddr;// 创建 TCP 套接字if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {perror("socket creation failed");exit(EXIT_FAILURE);}memset(&servaddr, 0, sizeof(servaddr));memset(&cliaddr, 0, sizeof(cliaddr));// 配置服务器地址servaddr.sin_family = AF_INET;servaddr.sin_addr.s_addr = htonl(INADDR_ANY);servaddr.sin_port = htons(PORT);// 绑定套接字if (bind(sockfd, (const struct sockaddr*)&servaddr, sizeof(servaddr)) < 0) {perror("socket bind failed");exit(EXIT_FAILURE);}// 监听连接if (listen(sockfd, 5) < 0) {perror("socket listen failed");exit(EXIT_FAILURE);}int len = sizeof(cliaddr);if ((connfd = accept(sockfd, (struct sockaddr*)&cliaddr, &len)) < 0) {perror("socket accept failed");exit(EXIT_FAILURE);}char buffer[BUFFER_SIZE];int n;while (1) {// 接收数据n = read(connfd, buffer, BUFFER_SIZE);buffer[n] = '\0';printf("Received data: %s\n", buffer);// 发送数据write(connfd, buffer, strlen(buffer));}close(sockfd);close(connfd);return 0;
    }

     

    // tcp_client.c
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <arpa/inet.h>#define PORT 8080
    #define BUFFER_SIZE 1024int main() {int sockfd;struct sockaddr_in servaddr;// 创建 TCP 套接字if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {perror("socket creation failed");exit(EXIT_FAILURE);}memset(&servaddr, 0, sizeof(servaddr));// 配置服务器地址servaddr.sin_family = AF_INET;servaddr.sin_port = htons(PORT);servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");// 连接到服务器if (connect(sockfd, (const struct sockaddr*)&servaddr, sizeof(servaddr)) < 0) {perror("socket connection failed");exit(EXIT_FAILURE);}char buffer[BUFFER_SIZE];while (1) {printf("Enter data to send: ");fgets(buffer, BUFFER_SIZE, stdin);// 发送数据write(sockfd, buffer, strlen(buffer));// 接收数据read(sockfd, buffer, BUFFER_SIZE);printf("Received data: %s", buffer);}close(sockfd);return 0;
    }
    编译与运行
    1. 编译代码:

    2. gcc -o tcp_server tcp_server.c
      gcc -o tcp_client tcp_client.c
    3. 运行程序:

      • 在一个终端运行服务器端:

    4. ./tcp_server
    5. 在另一个终端运行客户端:

    6. ./tcp_client
      代码说明
      • TCP 套接字:使用 socket 函数创建 TCP 套接字。

      • 连接:使用 connect 函数连接到服务器。

      • 发送数据:使用 write 函数发送数据。

      • 接收数据:使用 read 函数接收数据。

      • 服务器地址:配置服务器的 IP 地址和端口号。

      3. 使用 RTP 实现实时数据流传输

      示例代码

      以下代码展示了如何使用 RTP 实现实时数据流的传输。RTP 是一种专门用于实时数据流的传输协议,支持数据的时间戳和序列号。

      // rtp_sender.c
      #include <stdio.h>
      #include <stdlib.h>
      #include <string.h>
      #include <unistd.h>
      #include <arpa/inet.h>#define PORT 8080
      #define BUFFER_SIZE 1024int main() {int sockfd;struct sockaddr_in servaddr;// 创建 UDP 套接字if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {perror("socket creation failed");exit(EXIT_FAILURE);}memset(&servaddr, 0, sizeof(servaddr));// 配置服务器地址servaddr.sin_family = AF_INET;servaddr.sin_port = htons(PORT);servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");char buffer[BUFFER_SIZE];int seq_num = 0;while (1) {printf("Enter data to send: ");fgets(buffer, BUFFER_SIZE, stdin);// 添加 RTP 头部buffer[0] = (seq_num >> 8) & 0xFF; // 序列号高字节buffer[1] = seq_num & 0xFF;       // 序列号低字节seq_num++;// 发送数据sendto(sockfd, buffer, strlen(buffer) + 2, 0, (const struct sockaddr*)&servaddr, sizeof(servaddr));}close(sockfd);return 0;
      }

       

      // rtp_receiver.c
      #include <stdio.h>
      #include <stdlib.h>
      #include <string.h>
      #include <unistd.h>
      #include <arpa/inet.h>#define PORT 8080
      #define BUFFER_SIZE 1024int main() {int sockfd;struct sockaddr_in servaddr, cliaddr;// 创建 UDP 套接字if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {perror("socket creation failed");exit(EXIT_FAILURE);}memset(&servaddr, 0, sizeof(servaddr));memset(&cliaddr, 0, sizeof(cliaddr));// 配置服务器地址servaddr.sin_family = AF_INET;servaddr.sin_addr.s_addr = htonl(INADDR_ANY);servaddr.sin_port = htons(PORT);// 绑定套接字if (bind(sockfd, (const struct sockaddr*)&servaddr, sizeof(servaddr)) < 0) {perror("socket bind failed");exit(EXIT_FAILURE);}char buffer[BUFFER_SIZE];int n;socklen_t len = sizeof(cliaddr);while (1) {// 接收数据n = recvfrom(sockfd, buffer, BUFFER_SIZE, 0, (struct sockaddr*)&cliaddr, &len);buffer[n] = '\0';// 提取 RTP 头部int seq_num = (buffer[0] << 8) | buffer[1];printf("Received data (seq_num: %d): %s\n", seq_num, buffer + 2);}close(sockfd);return 0;
      }
      编译与运行
      1. 编译代码:

      2. gcc -o rtp_sender rtp_sender.c
        gcc -o rtp_receiver rtp_receiver.c
      3. 运行程序:

        • 在一个终端运行接收端:

      4. ./rtp_receiver
      5. 在另一个终端运行发送端:

      6. ./rtp_sender
        代码说明
        • RTP 头部:在数据前添加序列号,用于标识数据包的顺序。

        • UDP 套接字:使用 socket 函数创建 UDP 套接字。

        • 发送数据:使用 sendto 函数发送数据。

        • 接收数据:使用 recvfrom 函数接收数据。

        • 服务器地址:配置服务器的 IP 地址和端口号。

        常见问题与解答

        1. 如何选择合适的传输协议?

        选择合适的传输协议取决于具体的应用场景:

        • UDP:适用于对实时性要求较高的场景,如视频流、音频流。

        • TCP:适用于对可靠性要求较高的场景,如文件传输、数据库通信。

        • RTP:适用于需要时间戳和序列号的实时数据流,如多媒体应用。

        2. 如何优化网络传输延迟?

        可以通过以下方法优化网络传输延迟:

        • 使用 UDP:UDP 是一种无连接的协议,传输延迟较低。

        • 减少数据包大小:较小的数据包可以减少传输延迟。

        • 使用实时 Linux:实时 Linux 可以提供低延迟和高确定性的任务调度。

        • 优化网络配置:调整网络参数,如 MTU(最大传输单元)和缓冲区大小。

        3. 如何调试网络传输问题?

        可以通过以下方法调试网络传输问题:

        • 使用 iperf3:测试网络带宽和延迟。

        • 使用 tcpdump:捕获和分析网络数据包。

        • 使用 netstat:查看网络连接和端口状态。

        4. 如何处理数据包丢失?

        可以通过以下方法处理数据包丢失:

        • 使用 TCP:TCP 提供可靠的数据传输,可以自动处理数据包丢失。

        • 实现重传机制:在 UDP 中实现自定义的重传机制。

        • 使用 FEC(前向纠错):在数据中添加冗余信息,以便在数据包丢失时恢复数据。

        实践建议与最佳实践

        1. 合理选择传输协议

        根据具体的应用场景选择合适的传输协议,避免过度优化导致复杂性增加。

        2. 使用实时 Linux

        实时 Linux 可以提供低延迟和高确定性的任务调度,适用于需要高实时性的应用场景。

        3. 优化网络配置

        调整网络参数,如 MTU 和缓冲区大小,以减少传输延迟。

        4. 使用调试工具

        在开发过程中,使用调试工具(如 iperf3tcpdumpnetstat)可以帮助你更好地理解和解决网络传输问题。

        5. 实现重传机制

        在 UDP 中实现自定义的重传机制,以处理数据包丢失。

        6. 使用 FEC

        在数据中添加冗余信息,以便在数据包丢失时恢复数据。

        总结与应用场景

        本文通过实际案例,详细介绍了如何在实时 Linux 下实现数据流的实时传输,包括优化网络传输延迟的技术手段及方案。实时数据流的传输在许多领域都有广泛的应用,如工业自动化、金融交易、多媒体应用等。希望读者能够将所学知识应用到真实项目中,优化系统的实时性能。如果你有任何问题或建议,欢迎在评论区留言。

        http://www.lryc.cn/news/589127.html

        相关文章:

      1. Flutter Socket 连接方案分析与适用场景
      2. 国产化Excel处理组件Spire.XLS教程:在 C# 中生成 Excel文件
      3. excel 通过openpyxl表格下载和插入图片
      4. 给 Excel 整列空格文字内容加上前缀:像给文字穿衣服一样简单!
      5. Vue获取上传Excel文件内容并展示在表格中
      6. 【YOLOv11-目标检测】06-模型部署(C++)
      7. Sentinel热点参数限流完整示例实现
      8. 【PCIe 总线及设备入门学习专栏 5.1.1 -- PCIe PERST# 信号的作用】
      9. 【PCIe 总线及设备入门学习专栏 5.1.2 -- PCIe EP core_rst_n 与 app_rst_n】
      10. Excel制作玫瑰图
      11. 大语言模型:高考志愿填报的“新纪元智能参谋”
      12. 20250715问答课题-基于BERT与混合检索问答系统
      13. 论文阅读:arxiv 2025 A Survey on Data Contamination for Large Language Models
      14. 第八章,应用题
      15. OpenCV 对数变换函数logTransform()
      16. 【机器学习】第一章 概述
      17. 【机器学习】第二章 Python入门
      18. 【安卓笔记】RxJava之flatMap的使用
      19. PyTorch笔记6----------神经网络案例
      20. 【人工智能99问】神经网络的工作原理是什么?(4/99)
      21. Android中Launcher简介
      22. MySQL索引与事务详解:用大白话讲透核心概念
      23. compose、 pipe 组合函数实现
      24. 从底层技术到产业落地:优秘企业智脑的 AI 革命路径解析
      25. Basilisk库教程(二)
      26. QT——QList的详细讲解
      27. SpringBoot3.0 +GraalVM17 + Docker
      28. AI大模型训练相关函数知识补充
      29. MongoDB基础增删改查命令
      30. vscode配置运行完整C代码项目