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

《Linux 网络编程二:UDP 与 TCP 的差异、应用及问题应对》

一、UDP 与 TCP 对比表

对比项UDPTCP
连接方式无需建立连接有连接(三次握手建立,四次挥手断开)
传输可靠性尽最大努力交付,可能丢包安全可靠的数据传输机制
面向对象面向数据包面向数据流
传输模式一对一、一对多传输本质一对一,并发实现一对多
协议机制机制简单,资源开销小,实时性高机制复杂,网络资源开销大
报文头部8 字节(源端口、目标端口、长度、校验和)更复杂,包含更多控制信息
应用场景视频流、音频流等实时性要求高的场景文件传输、HTTP 等准确性要求高的场景
编程复杂度相对简单相对复杂,需处理连接建立与断开

二、UDP 相关内容

1.UDP 丢包原因

        UDP 存在接收缓冲区,当发送数据速度过快,致使接收缓冲区满时,后续数据包会丢失。UDP 无需建立连接,进一步增加了丢包可能性。

2.UDP 特点

  • 面向数据包:以数据包为基本传输单位。
  • 无需建立连接:通信前无需预先建立连接。
  • 尽力交付:是不安全可靠的数据协议,存在数据丢包情况。
  • 传输模式多样:能够实现一对一、一对多的传输。
  • 机制简单高效:机制简单,资源开销小,数据实时性高。

3.避免 UDP 丢包方法

  • 发送延时:在发送时使用 usleep() 函数延时,让接收方有足够时间处理数据。
  • 模仿 TCP 应答:发送一个数据后,等待接收端回应,收到回应后再发送下一包数据。

4.UDP 报文头部字段

字段字节数含义
源端口号2 字节发送方进程端口号
目标端口号2 字节接收方进程端口号
长度2 字节UDP 报文长度(头部加正文)
校验和2 字节用于数据差错校验

UDP 报文头部共 8 字节。


三、TCP 相关内容

1.TCP 协议概述

        TCP 即传输控制协议,位于传输层,采用流式套接字。

2.TCP 特点

  • 面向数据流:将数据作为连续的字节流处理。
  • 有连接:通信前需通过三次握手建立连接。
  • 安全可靠:具备安全可靠的数据传输机制。
  • 机制复杂:机制复杂,网络资源开销大。
  • 通信模式:本质只能实现一对一通信,可通过 TCP 并发方式实现一对多通信。

3.TCP 机制

        三次握手:TCP 建立连接时需进行三次握手,确保双方通信前都已准备就绪。SYN 为请求建立连接标志位,ACK 为响应报文标志位。

        四次挥手:确保断开连接时需进行四次挥手,保证断开连接前双方都已通信结束。FIN 为请求断开连接标志位,ACK 为响应报文标志位。ACK 和 FIN 不能一起,防止客户端断开后服务端还想发送信息。

    4.TCP 编程流程

            1)客户端流程
            

            socket() 创建套接字
            connect() 请求建立连接
            send() 发送
            recv() 接收
            close() 关闭

            2)服务端流程

            socket() 创建监听套接字
            bind() 绑定
            listen() 监听要建立连接的客户端
            accept() 接受完成三次握手的客户端并产生通信套接字
            recv()
            send()
            close()

    5.相关函数接口

    • connect():请求与服务端建立连接。

       int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
      • 参数:sockfd(套接字)、addr(服务端地址信息)、addrlen(服务端地址大小)。
      • 返回值:成功返回 0,失败返回 -1。
    • send():发送网络数据。

       ssize_t send(int sockfd, const void *buf, size_t len, int flags);
      • 参数:sockfd(网络套接字)、buf(发送数据首地址)、len(发送字节数)、flags(默认 0)。
      • 返回值:成功返回实际发送字节数,失败返回 -1。
    • listen():监听建立三次握手的客户端。

      int listen(int sockfd, int backlog);
      • 参数:sockfd(监听套接字)、backlog(最大监听客户端数)。
      • 返回值:成功返回 0,失败返回 -1。
    • accept():接收建立三次握手的客户端并产生通讯套接字。

      int accept(int socket, struct sockaddr *restrict address,socklen_t *restrict address_len);
      • 参数:socket(监听套接字)、address(客户端地址信息)、address_len(客户端地址长指针)。
      • 返回值:成功返回通讯套接字,失败返回 -1。
    • recv():从网络套接字接收数据。

      ssize_t recv(int sockfd, void *buf, size_t len, int flags);
      • 参数:sockfd(通讯套接字)、buf(接收数据首地址)、len(期望接收字节数)、flag(默认 0)。
      • 返回值:成功返回实际接收字节数,失败返回 -1,对方断开连接返回 0。

    6.TCP 粘包问题

    问题描述
    发送方应用层发送的多包数据,在接收方可能一次读到,多包数据产生粘连。

    原因

    • 发送方速度快,TCP 底层可能对多包数据重新组帧。
    • 接收方数据处理速度慢,多包数据在接收缓冲区缓存,应用层读时一次读出。

    7.解决方法

    • 调整发送速率:控制发送速度,避免粘包。
    • 发送指定大小数据:发送方发送指定大小数据,接收方也接收指定大小数据。注意跨平台数据传输时结构体对齐问题。
    • 增加分隔符:在应用层为发送的数据增加分隔符,接收方利用分隔符解析数据。
    • 自定义数据帧格式:封装自定义数据帧格式(协议)进行发送,并严格按协议解析。

    四、代码部分

            1.客户端不断从终端接收数据,使用TCP发送给服务端,服务端输出。

            head.h

    #include <sys/types.h>          /* See NOTES */
    #include <sys/socket.h>
    #include <unistd.h>
    #include <stdio.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <string.h>

            client.c

    #include "head.h"int main(int argc, char const *argv[])
    {int sockfd = socket(AF_INET, SOCK_STREAM,0);if(sockfd < 0){perror("socket error");return -1;}struct sockaddr_in seraddr;seraddr.sin_family = AF_INET;//种类seraddr.sin_port = htons(50000);//端口号seraddr.sin_addr.s_addr = inet_addr("192.168.0.192");//ip地址int ret = connect(sockfd, (struct sockaddr *)&seraddr, sizeof(seraddr));if(ret < 0){perror("connect error");return -1;}char buff[1024] = {0};while (1){fgets(buff, sizeof buff, stdin);ssize_t cnt = send(sockfd, buff, strlen(buff), 0);if(cnt < 0){perror("send error");return -1;}printf("cnt = %ld\n", cnt);memset(buff, 0, sizeof(buff));}close(sockfd);return 0;
    }
    

            recv.c

    #include "head.h"int main(int argc, char const *argv[])
    {int sockfd = socket(AF_INET, SOCK_STREAM, 0);if(sockfd < 0){perror("socket error");return -1;}struct sockaddr_in seraddr;seraddr.sin_family = AF_INET;seraddr.sin_port = htons(50000);seraddr.sin_addr.s_addr = inet_addr("192.168.0.192");int ret = bind(sockfd, (struct sockaddr *)&seraddr, sizeof(seraddr));if(ret < 0){perror("bind error");return -1;}ret = listen(sockfd, 10);if(ret < 0){perror("listen error");return -1;}int connfd = accept(sockfd, NULL, NULL);if(connfd < 0){perror("accept error");return -1;}char buff[1024] = {0};while(1){   ssize_t cnt = recv(connfd, buff, sizeof(buff), 0);if(cnt <= 0){printf("recv error");return -1;}printf("cnt = %ld, buff = %s\n", cnt, buff);memset(buff, 0, sizeof(buff));}close(connfd);close(sockfd);return 0;
    }
    
    http://www.xdnf.cn/news/18554.html

    相关文章:

  • Meta AI 剧变:汪滔挥刀重组,Llama 开源路线告急,超级智能梦碎还是重生?
  • 深度学习(深度神经网络)Pytorch框架
  • LoRA 微调
  • Trip Footprint旅行足迹App技术架构全解析
  • 迭代器模式与几个经典的C++实现
  • 机器学习案例——预测矿物类型(模型训练)
  • 【JVM内存结构系列】一、入门:先搞懂整体框架,再学细节——避免从一开始就混淆概念
  • Linux服务器利用Systemd配置定时任务
  • FLOPs、TFLOPs 与 TOPS:计算能力单位
  • 纠删码技术,更省钱的分布式系统的可靠性技术
  • JAVA核心基础篇-枚举
  • Claude Code 新手使用入门教程
  • 【Kubernetes知识点】资源配额与访问控制
  • Qt + windows+exe+msvc打包教程
  • AI热点周报(8.17~8.23):Pixel 10“AI周”、DeepSeek V3.1发布,英伟达再起波澜?
  • 【python】get_dummies()用法
  • AI大模型 限时找我领取
  • 心灵笔记:人生管理模型
  • 简单AI:搜狐公司旗下AI绘画产品
  • 均匀实心球内部引力与半径成正比的牛顿壳层定理证明
  • MATLAB实现CNN-LSTM-Attention 时序和空间特征结合-融合注意力机制混合神经网络模型的风速预测
  • c语言学习_数组使用_扫雷1
  • 1.十天通关常见算法100题(第一天)
  • 科研笔记:博士生手册
  • 【每天一个知识点】训推一体机
  • 数据结构的线性表:顺序表
  • 坑洼铁皮矫平机:把“波浪”变成“镜面”的科学魔法
  • 旅行足迹App技术架构全解析
  • 二、BPMNJS简介
  • 【51单片机非精准延时演示来回流水灯效果】2022-11-10