详解TCP和UDP通信协议

目录

OSI的七层模型的主要功能

tcp是什么

TCP三次握手

为什么需要三次握手,两次握手不行吗

TCP四次挥手

挥手会什么需要四次

什么是TCP粘包问题?发生的原因

原因

解决方案

UDP是什么

TCP和UDP的区别

网络层常见协议

利用socket进行tcp传输代码示例

客户端

服务端

利用socket进行udp传输代码示例

客户端

服务端

注意tcp的send/recv和udp的sendto/recvfrom有一点区别

OSI的七层模型的主要功能

  • **物理层:**利用传输介质为数据链路层提供物理连接,实现比特流的透明传输。
  • **数据链路层:**接收来自物理层的位流形式的数据,并封装成帧,传送到上一层
  • **网络层:**将网络地址翻译成对应的物理地址,并通过路由选择算法为分组通过通信子网选择最适当的路径。
  • **传输层:**在源端与目的端之间提供可靠的透明数据传输
  • **会话层:**负责在网络中的两节点之间建立、维持和终止通信
  • **表示层:**处理用户信息的表示问题,数据的编码,压缩和解压缩,数据的加密和解密
  • **应用层:**为用户的应用进程提供网络通信服务

tcp是什么

TCP(Transmission Control Protocol 传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议,即位于传输层。

TCP三次握手

三次握手(Three-way Handshake)其实就是指建立一个TCP连接时,需要客户端和服务器总共发送3个包。进行三次握手的主要作用就是为了确认双方的接收能力和发送能力是否正常、指定自己的初始化序列号为后面的可靠性传送做准备。实质上其实就是连接服务器指定端口,建立TCP连接,并同步连接双方的序列号和确认号,交换TCP窗口大小 信息。

为什么需要三次握手,两次握手不行吗

TCP四次挥手

建立一个连接需要三次握手,而终止一个连接要经过四次挥手(也有将四次挥手叫做四次握手的)。这由TCP的半关闭(half-close)造成的。所谓的半关闭,其实就是TCP提供了连接的一端在结束它的发送后还能接收来自另一端数据的能力。
TCP 的连接的拆除需要发送四个包,因此称为四次挥手(Four-way handshake),客户端或服务器均可主动发起挥手动作。

挥手会什么需要四次

什么是TCP粘包问题?发生的原因

一个完整的业务可能会被TCP拆分成多个包进行发送,也有可能把多个小的包封装成一个大的数据包发送,即是无边界的流传输,这个就是TCP的粘包问题。

  • 封包:封包就是在发送数据报的时候为每个TCP数据包加上一个包头,将数据报分为包头和包体两个部分。包头是一个固定长度的结构体,里面包含该数据包的总长度。
  • 拆包:接收方在接收到报文后提取包头中的长度信息进行截取。

原因

1、应用程序写入数据的字节大小大于套接字发送缓冲区的大小.

2、进行MSS大小的TCP分段。( MSS=TCP报文段长度-TCP首部长度)

3、以太网的payload大于MTU进行IP分片。(MTU指:一种通信协议的某一层上面所能通过的最大数据包大小。)

解决方案

1、消息定长。
2、在包尾部增加回车或者空格符等特殊字符进行分割
3、将消息分为消息头和消息尾
4、使用其它复杂的协议,如RTMP协议等。

UDP是什么

是一种提供无连接的,尽最大努力的数据传输服务(不保证数据传输的可靠性)的通信协议,即位于传输层。

TCP和UDP的区别

1、TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的前不需要建立连接

2、TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付

3、TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流:UDP是面向报文的,UDP没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(对实时应用很有用,如IP电话,实时视频会议等)

4、每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信

5、TCP首部开销20字节;UDP的首部开销小,只有8个字节

6、TCP的逻辑通信信道是全双工的可靠信道,UDP则是不可靠信道

7、UDP是面向报文的,发送方的UDP对应用层交下来的报文,不合并,不拆分,只是在其上面加上首部后就交给了下面的网络层,论应用层交给UDP多长的报文,它统统发送,一次发送一个。而对接收方,接到后直接去除首部,交给上面的应用层就完成任务了。因此,它需要应用层控制报文的大小

TCP是面向字节流的,它把上面应用层交下来的数据看成无结构的字节流会发送,可以想象成流水形式的,发送方TCP会将数据放入“蓄水池”(缓存区),等到可以发送的时候就发送,不能发送就等着TCP会根据当前网络的拥塞状态来确定每个报文段的大小。

网络层常见协议

利用socket进行tcp传输代码示例

客户端

#include <iostream>
#include <cstring>
#include <unistd.h>
#include <arpa/inet.h>

#define PORT 8080

int main() {
    int sock = 0;
    struct sockaddr_in serv_addr;
    char buffer[1024] = {0};

    // 创建 socket 文件描述符
    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        std::cout << "Socket creation error" << std::endl;
        return -1;
    }

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(PORT);

    // 将服务端地址转换为二进制
    if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) {
        std::cout << "Invalid address / Address not supported" << std::endl;
        return -1;
    }

    // 连接到服务器
    if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
        std::cout << "Connection Failed" << std::endl;
        return -1;
    }

    // 发送数据到服务器
    const char *hello = "Hello from client";
    send(sock, hello, strlen(hello), 0);
    std::cout << "Hello message sent" << std::endl;

    // 读取服务器发送的数据
    int valread = read(sock, buffer, 1024);
    std::cout << "Received: " << buffer << std::endl;

    close(sock);
    return 0;
}

服务端

#include <iostream>
#include <cstring>
#include <unistd.h>
#include <arpa/inet.h>

#define PORT 8080

int main() {
    int server_fd, new_socket;
    struct sockaddr_in address;
    int opt = 1;
    int addrlen = sizeof(address);
    char buffer[1024] = {0};

    // 创建 socket 文件描述符
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }

    // 将 socket 绑定到端口 8080
    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
        perror("setsockopt");
        close(server_fd);
        exit(EXIT_FAILURE);
    }
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(PORT);

    if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
        perror("bind failed");
        close(server_fd);
        exit(EXIT_FAILURE);
    }

    // 监听连接
    if (listen(server_fd, 3) < 0) {
        perror("listen");
        close(server_fd);
        exit(EXIT_FAILURE);
    }

    // 接受客户端连接
    if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {
        perror("accept");
        close(server_fd);
        exit(EXIT_FAILURE);
    }

    // 读取客户端发送的数据
    int valread = read(new_socket, buffer, 1024);
    std::cout << "Received: " << buffer << std::endl;

    // 发送数据到客户端
    const char *hello = "Hello from server";
    send(new_socket, hello, strlen(hello), 0);
    std::cout << "Hello message sent" << std::endl;

    close(new_socket);
    close(server_fd);
    return 0;
}

利用socket进行udp传输代码示例

客户端

#include <iostream>
#include <cstring>
#include <unistd.h>
#include <arpa/inet.h>

#define PORT 8080

int main() {
    int sockfd;
    char buffer[1024];
    struct sockaddr_in servaddr;

    // 创建 socket 文件描述符
    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 = INADDR_ANY;

    // 发送消息到服务器
    const char *hello = "Hello from client";
    sendto(sockfd, hello, strlen(hello), MSG_CONFIRM, (const struct sockaddr *)&servaddr, sizeof(servaddr));
    std::cout << "Hello message sent." << std::endl;

    // 接收服务器消息
    int n;
    socklen_t len;
    n = recvfrom(sockfd, (char *)buffer, 1024, MSG_WAITALL, (struct sockaddr *)&servaddr, &len);
    buffer[n] = '\0';
    std::cout << "Server : " << buffer << std::endl;

    close(sockfd);
    return 0;
}

服务端

#include <iostream>
#include <cstring>
#include <unistd.h>
#include <arpa/inet.h>

#define PORT 8080

int main() {
    int sockfd;
    char buffer[1024];
    struct sockaddr_in servaddr, cliaddr;

    // 创建 socket 文件描述符
    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; // IPv4
    servaddr.sin_addr.s_addr = INADDR_ANY;
    servaddr.sin_port = htons(PORT);

    // 绑定 socket
    if (bind(sockfd, (const struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {
        perror("bind failed");
        close(sockfd);
        exit(EXIT_FAILURE);
    }

    int n;
    socklen_t len;
    len = sizeof(cliaddr); // 客户端地址长度

    // 接收客户端消息
    n = recvfrom(sockfd, (char *)buffer, 1024, MSG_WAITALL, (struct sockaddr *)&cliaddr, &len);
    buffer[n] = '\0';
    std::cout << "Client : " << buffer << std::endl;

    // 发送消息到客户端
    const char *hello = "Hello from server";
    sendto(sockfd, hello, strlen(hello), MSG_CONFIRM, (const struct sockaddr *)&cliaddr, len);
    std::cout << "Hello message sent." << std::endl;

    close(sockfd);
    return 0;
}

注意tcp的send/recv和udp的sendto/recvfrom有一点区别

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/786505.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

查看oracle ojdbc所支持的JDBC驱动版本

oracle jcbc驱动的下载地址参考&#xff1a;JDBC and UCP Downloads page 其实上文中对ojdbc所支持的JDBC驱动版本已经有说明了&#xff0c;不过&#xff0c;因为oracle的驱动包很多时间&#xff0c;都是在公司内部私服里上传维护的&#xff0c;上传的时候&#xff0c;可能又没…

鲸发卡系统 /pay/xinhui/request_post 任意文件读取漏洞复现

0x01 产品简介 鲸发卡系统 致力于解决虚拟商品的快捷发卡服务&#xff0c;为商户及其买家 提供&#xff0c;便捷、绿色、安全、快速的销售和购买体验。框架已升级TP最新版本&#xff0c;无安全BUG&#xff0c;重新开发将近80&#xff05;&#xff0c;原创功能10项&#xff0c;…

static-02

三个注意点 1.静态方法中无this关键字 2.静态方法只能访问静态资源 3.非静态方法可以访问所有 1.静态方法中无this关键字--------(非静态)普通方法里有this关键字(隐藏的) this关键字:代表方法调用者的地址值----这个方法的调用者的就是一个具体的对象 非静态的东西通常跟…

使用virt-manager添加宿主机上的U盘

1、打开virt-manager管理界面 [rootkvm4 ~]# virt-manager 2、打开需要添加U盘的虚拟机 3、进入Hardware管理器 4、选择插入U盘的设备&#xff0c;点Finish 5、进入虚拟机&#xff0c;确认U是否添加OK

基层医院、专科医院云HIS系统,支持电子病历四级,全套源码交付

云HIS系统采用B/S架构云端SaaS服务的方式提供&#xff0c;使用用户通过浏览器即能访问&#xff0c;无需关注系统的部署、维护、升级等问题&#xff0c;系统充分考虑了模板化、配置化、智能化、扩展化等设计方法&#xff0c;覆盖了基层医院的主要工作流程&#xff0c;能够与监管…

倩女幽魂游戏攻略:装备攻略大全与云手机助力教程!

在《倩女幽魂》这片古风奇幻的江湖中&#xff0c;装备不仅是角色的外在装扮&#xff0c;更是提升实力、闯荡三界的关键所在。本文将从装备的颜色、类别、词缀及获取途径等多个维度&#xff0c;为玩家呈现一份详尽而深入的装备攻略&#xff0c;助你成为三界中的佼佼者。 在倩女幽…

PDM系统中物料分类与编码规则生成方案

在企业管理软件中&#xff0c;PDM系统是企业管理的前端软件&#xff0c;用于管理研发图纸、BOM等数据&#xff0c;然后生成相关物料表或BOM&#xff0c;递交给后端ERP系统进行生产管理。在PDM系统中&#xff0c;有两种方式可以生成物料编码。 1第一种是用户可以通过软件接口将…

windows10下的游戏怎么卸载?

在Windows 10中卸载游戏可以通过多种途径进行&#xff0c;下面是一些常见的方法&#xff1a; 方法一&#xff1a;通过“设置”应用卸载 1. 点击左下角的“开始”按钮&#xff0c;打开“开始”菜单。 2. 选择“设置”图标&#xff08;齿轮形状&#xff09;。 3. 在“设置”窗…

【系统架构设计】计算机组成与体系结构(一)

计算机组成与体系结构 计算机系统组成计算机硬件组成控制器运算器主存储器辅助存储器输入设备输出设备 计算机系统结构的分类存储程序的概念Flynn分类 复杂指令集系统与精简指令集系统总线 存储器系统流水线 兜兜转转&#xff0c;最后还是回到了4大件&#xff0c;补基础&#x…

通过PLC地址来切换威纶通触摸屏界面

Step 1 元件-PLC控制 Step 2 新增 选择设备 选择切换基本窗口功能 选择触发地址 Step 3 离线仿真测试 在数值框中输入对应的页面号 可以看到页面可以正常切换 分享创作不易&#xff0c;请多多支持&#xff0c;点赞、收藏、关注&#xff01; Ending~

如何在抖音小程序上展示VR全景?

如果您或者您服务的甲方需要在抖音小程序中打开720全景漫游链接&#xff0c;就需要在720云平台进行小程序校验。总体来说&#xff0c;在720云平台提交对应小程序信息后&#xff0c;您将获得720云业务域名&#xff0c;将此业务域名配置到抖音小程序后台&#xff0c;即完成校验&a…

神经网络中的激活函数

目录 一、什么是激活函数&#xff1a;二、如何选择激活函数&#xff1a;1.Sigmoid激活函数&#xff1a;2.线性激活函数&#xff1a;3.ReLU激活函数&#xff1a; 一、什么是激活函数&#xff1a; 激活函数是神经网络中的一种函数&#xff0c;它在神经元中起到了非线性映射的作用…

长期保存数据用什么硬盘安全?硬盘数据丢失怎么解决?一文读懂

关乎硬盘数据丢失的恢复窍门&#xff0c;这篇文章您可一定要收藏妥当。在硬盘的使用进程中&#xff0c;诸多情形都会致使数据丢失&#xff0c;像是硬盘跌落、病毒侵袭、系统文件受损等等。在这种时候&#xff0c;务必要运用正确的方式&#xff0c;全力抢救硬盘里存储的珍贵数据…

下载安装Microsoft DirectX SDK(June 2010)

官方下载网址如下&#xff1a; Microsoft DirectX SDK(June 2010)链接 下载后是一个.exe文件 在安装之前&#xff0c;需要先检查你的电脑中是否已经安装过&#xff08;如果你安装过VS&#xff0c;那么一定会有这两个文件&#xff09; Microsoft Visual C 2010 x86 Redistribu…

登录Google账号时报400的错误是什么含义?什么原因导致的?如何解决?

一个朋友的谷歌账号在登录的时候提示账号异常&#xff0c;需要输入手机号码进行验证。但是输入自己的手机号和朋友的手机号还是无法验证&#xff0c;要不提示这个号码无法用于进行验证&#xff0c;要么提示这个号码用于验证次数过多。验证码发不出来。 后来我给了他号码以后终…

保姆级教程:Linux (Ubuntu) 部署流光卡片开源 API

流光卡片 API 开源地址 Github&#xff1a;https://github.com/ygh3279799773/streamer-card 流光卡片 API 开源地址 Gitee&#xff1a;https://gitee.com/y-gh/streamer-card 流光卡片在线使用地址&#xff1a;https://fireflycard.shushiai.com/ 等等&#xff0c;你说你不…

一文玩转【relation-graph 关系图谱】再也不怕遇到这样的需求

✨ 关于 relation-graph relation-graph是支持Vue2、Vue3、React的关系数据展示组件&#xff0c;支持通过【插槽】让使用者使用"普通HTML元素、Vue组件、React组件"来完全自定义图形元素&#xff0c;并提供实用的API接口让使用者轻松构建可交互的图形应用。 官网文档…

Java面试八股之MySQL的redo log和undo log

MySQL的redo log和undo log 在MySQL的InnoDB存储引擎中&#xff0c;redo log和undo log是两种重要的日志&#xff0c;它们各自服务于不同的目的&#xff0c;对数据库的事务处理和恢复机制至关重要。 Redo Log&#xff08;重做日志&#xff09; 功能 redo log的主要作用是确…

uniapp版即时通讯软件 IM社交交友聊天系统 语音视频通话双端APP 聊天交友APP源码 (含搭建教程)

修复音视频&#xff08;官方团队插件&#xff0c;无二次费用&#xff09;&#xff0c;文件发送&#xff0c;公告&#xff0c;签到&#xff0c;发现页&#xff0c;朋友圈删除&#xff0c;轮询客服&#xff0c;马甲等 可内嵌第三方网页连接&#xff0c;后台添加&#xff0c;带完…

Java面经知识点汇总版

Java面经知识点汇总版 算法 14. 最长公共前缀&#xff08;写出来即可&#xff09; Java 计算机基础 数据库 基础 SQL SELECT first_name, last_name, salary FROM employees WHERE department Sales AND salary > (SELECT AVG(salary)FROM employeesWHERE department Sal…