计算机网络(4) --- 协议定制

news2024/11/17 3:31:17

计算机网络(3) --- 网络套接字TCP_哈里沃克的博客-CSDN博客https://blog.csdn.net/m0_63488627/article/details/132035757?spm=1001.2014.3001.5501

目录

1. 协议的基础知识

TCP协议通讯流程

​编辑

2.协议

1.介绍

2.手写协议

1.内容

2.接口

3.序列化和反序列化

4.协议化

5.读操作

3.客户端和服务端的业务逻辑

1.服务端

2.客户端


1. 协议的基础知识

TCP协议通讯流程

 1.不论是三次握手四次挥手还是数据的传输,其实都是操作系统进行执行的。那么两边的函数也只是操作系统的调用接口,操作系统依然是整体的执行者

2.那么我们不能简单的认为accept就是构建链接,因为链接的建立是操作系统提供的,accept更多的是以一种接收管理的姿态。那么三次握手有没有aceept其实不大有关系。

3.链接其实是一种结构体,该结构体是用于存储客户端连接服务器时对客户端的描述,毕竟连接服务端的不一定只有一个客户端,只要客户端多起来,就一定需要被管理,那么aceept的作用就是将接收到的链接进行描述管理

2.协议

1.介绍

1.协议是一种 "约定"。 socket api的接口,之前写的套接字在读写数据时, 都是按 "字节流" 的方式来发送接收的。

2.但是我们需要传输一些"结构化的数据",比如图片,视频之类的东西。设计为了这些功能的实现,我们将这些东西对应的字节流组成一个结构体,那么由该结构体存储,只要我们将这些字节流存储到结构体内,随后进行序列化得到一个字节流,之后传入到网络中去。接收方接收,得到的则是一个字节流,反序列化出结构体再将所有的数据拿出来,这样就实现了所有形式的数据都能被一个报文直接转发过来。

3.同时也要保证接收方收到一个完整的报文。udp不需要考虑,因为它面向数据报的;tcp不同,它是传输字节流的,需要考虑。

2.手写协议

1.内容

1.为了保证接收方收到一个完整的报文,我们需要自己设计报文和报文之间的边界。

2.除了物理层都没有返送和接收的直接连接,应用层的数据想要发送,其实这些数据都在应用层的缓冲区中,而发送的过程,其实是像tcp/ip层进行拷贝,把应用层的缓冲区拷贝到tcp/ip层的发送缓冲区,而另一边的主机则是通过tcp/ip层的接收缓冲区拷贝下层传上来的数据。这些数据最终是通过网络发送的。应用层的函数调用write和read接口都是拷贝函数。那考虑最终结果其实呈现出的是:C的发送缓冲区的数据拷贝到S的接收缓冲区,反之亦然。

3.由于两边都拥有发送和接收缓冲区,那么也就意味着两边同时的传输是不影响的,这种工作模式是全双工的

4.发送数据很多,并且对端不处理这些发送过来的数据,难免出现数据扎堆出现在缓冲区中,那么读取这些数据就想要分离出以一个报文为单位的数据。这种划分有三种方法:定长,定特殊符号或者这自描述方法

2.接口

与read的作用一致,都是把字节流发送出去

 

 与write的作用一致,都是把字节流接收会来

3.序列化和反序列化

#define SEP " "
#define SEP_LEN strlen(SEP) // 不要使用sizeof
#define LINE_SEP "\r\n"
#define LINE_SEP_LEN strlen(LINE_SEP) // 不要使用sizeof

class Request
{
public:
    Request()
    {
    }

    Request(int x_, int y_, char op_)
        : x(x_), y(y_), op(op_)
    {
    }

    bool serialize(std::string *out)
    {
        *out = "";
        std::string x_string = std::to_string(x);
        std::string y_string = std::to_string(y);
        *out = x_string;
        *out += SEP;
        *out += op;
        *out += SEP;
        *out += y_string;
        *out += LINE_SEP;
    }

    bool deserialize(const std::string &in)
    {
        auto left = in.find(SEP);
        auto right = in.find(SEP);
        if (left == std::string::npos || right == std::string::npos)
            return false;
        if (left == right)
            return false;
        if (right - (left + SEP_LEN))
            return false;

        std::string x_string = in.substr(0, left);
        if (x_string.empty())
            return false;
        std::string y_string = in.substr(right + SEP_LEN);
        if (y_string.empty())
            return false;
        x = std::stoi(x_string);
        y = std::stoi(y_string);

        op = in[left + SEP_LEN];
        return true;
    }

public:
    int x;
    int y;
    char op;
};

class Response
{
public:
    Response()
    {
    }

    Response(int exitcode_, int result_)
        : exitcode(exitcode_), result(result_)
    {
    }

    bool serialize(std::string *out)
    {
        *out = "";
        std::string ec_string = std::to_string(exitcode);
        std::string res_string = std::to_string(result);

        *out = ec_string;
        *out += SEP;
        *out += res_string;
        *out += LINE_SEP;
        return true;
    }

    bool deserialize(const std::string &in)
    {
        auto mid = in.find(SEP);
        if (mid == std::string::npos)
            return false;
        std::string ec_string = in.substr(0, mid);
        std::string res_string = in.substr(mid + SEP_LEN);

        if (ec_string.empty() || res_string.empty())
            return false;

        exitcode = std::stoi(ec_string);
        result = std::stoi(res_string);
        return true;
    }

public:
    int exitcode;
    int result;
};

基于计算的业务处理逻辑下:

1.request表示请求,即接收方接收的数据

2.response表示应答,即发送方得到接收方处理结果后的数据

3.不论发送还是接收方,其request和response都是想要有序列化和反序列化的。想要注意的是,序列化和反序列化是一种结构化的类型,不表示协议,它是协议的有效载荷部分

4.序列化的逻辑:将当前存储的一系列想要被操作的数据,通过存储在out中。通过分隔符进行组合

5.反序列化的逻辑:接受到了in,将in的数据拆分回原来的结构,拆分的依据就是分隔符

4.协议化

std::string enLength(const std::string &text)
{
    std::string send_string = std::to_string(text.size());
    send_string += LINE_SEP;
    send_string += text;
    send_string += LINE_SEP;

    return send_string;
}

bool deLength(const std::string &package, std::string *text)
{
    auto pos = package.find(LINE_SEP);
    if (pos == std::string::npos)
        return false;
    std::string text_len_string = package.substr(0, pos);
    int text_len = std::stoi(text_len_string);
    *text = package.substr(pos + LINE_SEP_LEN, text_len);
    return true;
}

1.规定的协议为:当前序列化的字节流长度大小作为前面的一个字节流且用\r\n来进行分隔序列化的字节流,大概模式为XXX\r\nYYY\r\n

2.加协议enLength:就是将传入的text之前算出text的大小,先加入大小后填入分隔符最后加入序列化的字节流

3.减协议deLength:先找到第一个分隔符,得到整个序列化字节流的大小,随后通过大小长度收录整个序列化的字节流

5.读操作

bool recvPackage(int sock, std::string &inbuffer,std::string *text)
{
    char buffer[1024];
    while (true)
    {
        ssize_t n = recv(sock, buffer, sizeof(buffer) - 1, 0);
        if (n > 0)
        {
            buffer[n] = 0;
            inbuffer += buffer;
            auto pos = inbuffer.find(LINE_SEP);
            if (pos == std::string::npos)
                continue;
            std::string text_len_string = inbuffer.substr(0, pos);
            int text_len = std::stoi(text_len_string);
            int total_len = text_len_string.size() + 2 * LINE_SEP_LEN + text_len;
            if (inbuffer.size() < total_len)
                continue;

            *text = inbuffer.substr(0, total_len);
            inbuffer.erase(0, total_len);
            break;
        }
        else
            return false;
    }
    return true;
}

3.客户端和服务端的业务逻辑

1.服务端

void handerEnter(int sock, func_t func)
    {
        std::string inbuffer;
        while (true)
        {
            // 1.读取
            // 1.1读取完整的一个报文
            std::string req_text;
            if (!recvRequest(sock, inbuffer, &req_text))
                return;
            // 1.2读取完整的报文
            std::string req_str;
            if (!deLength(req_text, &req_str))
                return;

            // 2.反序列化
            // 2.1得到一个结构化的请求对象
            Request req;
            if (!req.deserialize(req_str))
                return;

            // 3.计算业务
            // 3.1得到一个结构化的响应
            Response resp;
            func(req, resp);

            // 4.对响应进行序列化
            // 4.1得到一个字符串
            std::string resp_str;
            resp.serialize(&resp_str);

            // 5.然会发送给客户端一个响应
            // 5.1构造新报文
            std::string send_string = enLength(resp_str);
            send(sock, send_string.c_str(), send_string.size(), 0);
        }
    }

2.客户端

void start()
        {
            // 5.要发起链接
            struct sockaddr_in server;
            memset(&server, 0, sizeof server);
            server.sin_family = AF_INET;
            server.sin_port = htons(_serverport);
            server.sin_addr.s_addr = inet_addr(_serverip.c_str());

            if (connect(_sock, (struct sockaddr *)&server, sizeof server) != 0)
            {
                std::cerr << "connect error: " << errno << " : " << strerror(errno) << std::endl;
            }
            else
            {
                std::string msg;
                std::string inbuffer;
                while (true)
                {
                    std::cout << "mycal>>> ";
                    std::getline(std::cin, msg);

                    //msg要拆分
                    Request req(msg);
                    std::string content;
                    req.serialize(&content);
                    std::string send_string = enLength(content);
                    send(_sock, send_string.c_str(), send_string.size(), 0);

                    std::string package, text;
                    if (!recvPackage(_sock, inbuffer, &package))
                        continue;
                    if (!deLength(package, &text))
                        continue;
                    Response resp;
                    resp.deserialize(text);
                    std::cout << "exitcode: " << resp.exitcode << std::endl;
                    std::cout << "result: " << resp.result << std::endl;
                }
            }
        }

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Vulnhub: blogger:1靶机

kali&#xff1a;192.168.111.111 靶机&#xff1a;192.168.111.176 信息收集 端口扫描 nmap -A -sC -v -sV -T5 -p- --scripthttp-enum 192.168.111.176 在80端口的/assets/fonts/目录下发现blog目录&#xff0c;访问后发现为wordpress 利用wpscan发现wordpress插件wpdisc…

WiFi爆破实战

提示&#xff1a;本文记录了博主的一次WiFi爆破实战 文章目录 写在前面一、将网卡连接Kali虚拟机二、网卡配置骤2.1 识别网卡2.2 净化环境2.3 启动监听2.4 探测周边WiFi 三、实施攻击3.1 对选定的目标WiFi实施监听3.2 发起DOS攻击3.3 实施爆破 写在最后 写在前面 提示&#xf…

LNMP搭建及论坛搭建

一、LNMP LNMP架构是目前成熟的企业网站应用模式之一&#xff0c;指的是协同工作的一整套系统和相关软件&#xff0c; 能够提供动态Web站点服务及其应用开发环境。LNMP是一个缩写词&#xff0c;具体包括Linux操作系统、nginx网站服务器、MySQL数据库服务器、PHP&#xff08;或…

实用,3分钟免费生成中小学新生录取查询系统

在新学期开始之际&#xff0c;作为招生负责人&#xff0c;您是否已经做好准备来迎接新学年的招生工作呢&#xff1f;录取新生所需的任务包括成绩信息的录入、招生要求的核对以及新生录取信息的查询公布&#xff0c;这些繁重的工作给负责招生的老师带来了巨大的压力和挑战。 为…

Dockerfile构建LNMP镜像

建立工作目录 [rootlocalhost ~]# mkdir lnmp [rootlocalhost ~]# cd lnmp/ 编写Dockerfile文件 [rootlocalhost lnmp]# vim Dockerfile [rootlocalhost lnmp]# ll 总用量 4 -rw-r--r--. 1 root root 774 8月 3 14:54 Dockerfile [rootlocalhost lnmp]# vim Dockerfile #基础…

2023年华数杯A题

A 题 隔热材料的结构优化控制研究 新型隔热材料 A 具有优良的隔热特性&#xff0c;在航天、军工、石化、建筑、交通等 高科技领域中有着广泛的应用。 目前&#xff0c;由单根隔热材料 A 纤维编织成的织物&#xff0c;其热导率可以直接测出&#xff1b;但是 单根隔热材料 A 纤维…

软件为什么要进行性能压力测试?

软件为什么要进行性能压力测试&#xff1f;随着软件应用的不断增多和复杂度的提高&#xff0c;软件的性能对用户体验和业务成功至关重要。性能问题可能导致软件运行缓慢、崩溃或无响应&#xff0c;给用户带来不便甚至损失。为了确保软件能够在高负载和压力下正常运行&#xff0…

spring-bean的生命周期和怎么配置spring-bean的后置处理器

&#x1f600;前言 本章是spring基于XML 配置bean系类中第6篇讲解spring-bean的生命周期和怎么配置spring-bean的后置处理器 &#x1f3e0;个人主页&#xff1a;尘觉主页 &#x1f9d1;个人简介&#xff1a;大家好&#xff0c;我是尘觉&#xff0c;希望我的文章可以帮助到大家…

Storm学习之使用官方Docker镜像快速搭建Storm运行环境

文章目录 0.前言搭建完的效果 1.教程1.1.docker 安装 zookeeper1.2. 安装 storm nimbus1.3.docker 安装 supervisor1.4.docker 安装 storm-ui1.5.查看已经启动的容器1.6.提交topology到 storm集群 2.总结3.参考文档 0.前言 Apache Storm 官方也出了Docker 镜像 https://hub.do…

Python3 高级教程 | Python3 CGI编程(二)

目录 一、什么是CGI 二、网页浏览 三、CGI架构图 四、Web服务器支持及配置 五、第一个CGI程序 六、HTTP头部 七、CGI环境变量 八、GET和POST方法 &#xff08;一&#xff09;使用GET方法传输数据 &#xff08;二&#xff09;简单的url实例&#xff1a;GET方法 &#x…

CSPM国标项目管理认证未来值得期待吗?

一、CSPM认证背景信息 CSPM是由全国项目管理标准化技术委员会&#xff08;SAC/TC343&#xff09;和中国国际人才交流基金会&#xff08;原外专局&#xff09;联合发起的项目管理专业认证。 首先&#xff0c;让我们了解下这两个国字号单位的来历。全国项目管理标准化技术委员会…

教你如何轻松做一个生鲜蔬果小程序商城

在现代社会中&#xff0c;生活节奏加快&#xff0c;人们对生鲜蔬果的需求也越来越高。为了方便用户购买生鲜蔬果&#xff0c;无需开发的生鲜蔬果配送小程序应运而生。今天&#xff0c;我们将向大家介绍如何在三分钟内搭建这样一个小程序。 首先&#xff0c;我们需要登录乔拓云平…

React 之 Redux - 状态管理

一、前言 1. 纯函数 函数式编程中有一个非常重要的概念叫纯函数&#xff0c;JavaScript符合函数式编程的范式&#xff0c;所以也有纯函数的概念 确定的输入&#xff0c;一定会产生确定的输出 函数在执行过程中&#xff0c;不能产生副作用 2. 副作用 表示在执行一个函数时&a…

轻松批量文件改名!一键翻译重命名文件夹/文件,省时高效!」

繁忙的数字时代&#xff0c;我们经常需要处理大量的文件和文件夹。而手动逐个更改文件名不仅费时费力&#xff0c;还容易出错。因此&#xff0c;我们为您带来了一款强大的工具——批量文件改名软件&#xff01;现在&#xff0c;您可以一键翻译重命名文件夹和文件&#xff0c;轻…

【设计模式——学习笔记】23种设计模式——访问者模式Visitor(原理讲解+应用场景介绍+案例介绍+Java代码实现)

文章目录 案例引入要求传统方案 介绍基本介绍应用场景登场角色尚硅谷版本《图解设计模式》版本 案例实现案例一实现拓展 案例二(个人感觉这个案例较好)实现分析拓展一拓展二拓展三 总结额外知识双重分发 文章说明 案例引入 要求 测评系统需求&#xff1a;将观众分为男人和女人…

MySQL数据库——多表操作

文章目录 前言多表关系一对一关系一对多/多对一关系多对多关系 外键约束创建外键约束插入数据删除带有外键约束的表的数据删除外键约束 多表联合查询数据准备交叉连接查询内连接查询外连接查询左外连接查询右外连接查询满外连接查询 子查询子查询关键字ALL 关键字ANY 和 SOME 关…

2023年华数杯数学建模A题思路代码分析 - 隔热材料的结构优化控制研究

# 1 赛题 A 题 隔热材料的结构优化控制研究 新型隔热材料 A 具有优良的隔热特性&#xff0c;在航天、军工、石化、建筑、交通等 高科技领域中有着广泛的应用。 目前&#xff0c;由单根隔热材料 A 纤维编织成的织物&#xff0c;其热导率可以直接测出&#xff1b;但是 单根隔热…

详解Spring Bean的生命周期

详解Spring Bean的生命周期 Spring Bean的生命周期包括以下阶段&#xff1a; 1. 实例化Bean 对于BeanFactory容器&#xff0c;当客户向容器请求一个尚未初始化的bean时&#xff0c;或初始化bean的时候需要注入另一个尚未初始化的依赖时&#xff0c;容器就会调用createBean进…

剑指Offer 05.替换空格

剑指Offer 05.替换空格 目录 剑指Offer 05.替换空格05.替换空格题目代码&#xff08;容易想到的&#xff09;利用库函数的方法题解&#xff08;时间复杂度更低&#xff09;面试&#xff1a;为什么java中String类型是不可变的 05.替换空格 题目 官网题目地址 代码&#xff08;…

【Python小笔记】零碎同步

1.多字段连接&#xff0c;连接字段名不一致–left_on\right_on对应列示后可匹配 import pandas as pd df_A1pd.read_excel(E:\Mercy\data\mytest\A.xlsx,sheet_name0) df_A2pd.read_excel(E:\Mercy\data\mytest\A.xlsx,sheet_name1)df_Adf_A1.merge(rightdf_A2,howleft,left_o…