详细介绍:17.TCP编程(二)和序列化

一.概念回顾

建议先学上篇博客,再向下学习,上篇博客的链接如下:

https://blog.csdn.net/weixin_60668256/article/details/154752573?fromshare=blogdetail&sharetype=blogdetail&sharerId=154752573&sharerefer=PC&sharesource=weixin_60668256&sharefrom=from_link

二.远程命令分析功能

我们还是在原来的代码的基础上,增加一个CommandExec的类(我们可以把我们原来的shell直接拿来)

#pragma once
#include 
#include 
class Command
{
public:
    //给你一个命令字符串"ls -l",让你执行,执行完,把结果进行返回
    std::string Execute(std::string cmdstr)
    {
        //1. pipe
        //2. fork + dup2(pipe[1],1) + exec*,把执行结果交给父进程(pipe[0])
        //3. return
        return std::string();
    }
};

但是有一个接口完成了上面的基本功能

//给你一个命令字符串"ls -l",让你执行,执行完,把结果进行返回
    std::string Execute(std::string cmdstr)
    {
        //1. pipe
        //2. fork + dup2(pipe[1],1) + exec*,把执行结果交给父进程(pipe[0])
        //3. return
        FILE* fp = ::popen(cmdstr.c_str(),"r");
        if(nullptr == fp)
        {
            return std::string("Failed");
        }
        char buffer[line_size];
        std::string result;
        while(true)
        {
            char* ret = ::fgets(buffer,sizeof(buffer),fp);
            if(!ret)
            {
                break;
            }
            result += ret;
        }
        pclose(fp);
        return result.empty() ? std::string("Done") : result;
    }

三.将可执行命令设置进入白名单(防止危险命令)

#pragma once
#include 
#include 
#include 
#include 
const int line_size = 1024;
class Command
{
public:
    Command()
    {
        _white_list.insert("ls");
        _white_list.insert("pwd");
        _white_list.insert("ls -l");
        _white_list.insert("ll");
        _white_list.insert("touch");
        _white_list.insert("who");
        _white_list.insert("whoami");
    }
    bool SafeCheck(const std::string& cmdstr)
    {
        if(_white_list.count(cmdstr))
        {
            return true;
        }
        return false;
    }
    //给你一个命令字符串"ls -l",让你执行,执行完,把结果进行返回
    std::string Execute(std::string cmdstr)
    {
        //1. pipe
        //2. fork + dup2(pipe[1],1) + exec*,把执行结果交给父进程(pipe[0])
        //3. return
        if(!SafeCheck(cmdstr))
        {
            return std::string(cmdstr + "不支持");
        }
        FILE* fp = ::popen(cmdstr.c_str(),"r");
        if(nullptr == fp)
        {
            return std::string("Failed");
        }
        char buffer[line_size];
        std::string result;
        while(true)
        {
            char* ret = ::fgets(buffer,sizeof(buffer),fp);
            if(!ret)
            {
                break;
            }
            result += ret;
        }
        pclose(fp);
        return result.empty() ? std::string("Done") : result;
    }
private:
    std::set _white_list;
};

这里我们采取的是严格匹配,所以可执行的命令较少(可以用shell,但是安全一定要做好)

这里我们就基本完成了TCP套接字的初次使用

四.应用层协议

1.协议讲解

但是这样是不行的,对于我们的(两个机器位数,平台等)不同,这样数据会出现不匹配的问题

2.重新理解read、write、recv、send和tcp为什么支持全双工

这里操作系统会对于一个sockfd创建对应的两个缓冲区,用于发送和接收

两对接收和发送缓冲区,所以对应的就是全双工的了

3.面向字节流

TCP的发送方式就是基于拥塞控制,流量控制等操作,将部分报文进行发送,导致我们读取数据出现错误(所以在OS层面是,不能保证读取正确的)

UDP的发送方式就是用户数据报,发送的信息一定是完整的(和快递类似,只能收到一个完整的快递,不能只收到半个快递)

TCP无法确定报文完整性的,所以我们在用户层可以保证自己报文的完整性

五.网络版本计算器的实现

1.协议的定制

posted @ 2025-12-14 08:16  yangykaifa  阅读(1)  评论(0)    收藏  举报