基于Socket简单的TCP网络程序

小白苦学IT的博客主页

初学者必看:Linux操作系统入门

代码仓库:Linux代码仓库

❤关注我一起讨论和学习Linux系统

TCP单例模式的多线程版本的英汉互译服务器

我们先来认识一下与udp服务器实现的不同的接口:

TCP服务器端

socket():创建一个新的套接字,指定使用的协议族(如IPv4)、套接字类型(如SOCK_STREAM表示TCP)和协议(通常为0,表示使用默认协议)。

bind():将套接字绑定到一个特定的地址和端口号上,这样客户端就可以通过这个地址和端口号连接到服务器。

listen():使套接字进入监听状态,等待客户端的连接请求。可以指定最大连接队列长度。

accept():接受一个客户端的连接请求,并返回一个新的套接字,用于与这个客户端进行通信。原始的套接字继续用于监听其他客户端的连接请求。

read() :从已连接的客户端套接字读取数据。TCP是字节流协议,因此你需要按照某种协议或方式来分割和解析接收到的数据。

write():向已连接的客户端套接字发送数据。

TCP客户端

socket():同样创建一个新的套接字。

connect():发起一个到服务器地址和端口号的连接请求。

read() :从服务器套接字读取数据。

write():向服务器套接字发送数据。

封装TcpSocket

TcpServer.hpp

#pragma once

#include <iostream>
#include <string>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include "Log.hpp"
#include <cstring>
#include<pthread.h>
#include"ThreadPool.hpp"
#include "task.hpp"

const int defaultfd = -1;
const std::string defaultip = "0.0.0.0";
const int backlog = 5;

enum
{
    UsageError = 1,
    SocketError,
    BindError,
    ListenError,
};

class TcpServer;

class ThreadData1
{
public:
    ThreadData1(int fd,const std::string & ip,const uint16_t & port,TcpServer* t)
    :sockfd(fd),clientip(ip),clientport(port),tsvr(t)
    {

    }

public:
    int sockfd;
    std::string clientip;
    uint16_t clientport;
    TcpServer* tsvr;
};

class TcpServer
{

public:
    TcpServer(const uint16_t port, const std::string &ip = defaultip)
        : _listensock(-1), _port(port), _ip(ip)
    {
    }

    void InitServer()
    {
        _listensock = socket(AF_INET, SOCK_STREAM, 0);
        if (_listensock < 0)
        {
            log.LogMessage(FATAL, "create socket error , errno:%d, strerror: %s", errno, strerror(errno));
            exit(SocketError);
        }
        log.LogMessage(INFO, "create socket success ,_listensock:%d", _listensock);

        struct sockaddr_in local;
        memset(&local, 0, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(_port);
        inet_aton(_ip.c_str(), &(local.sin_addr));

        if (bind(_listensock, (struct sockaddr *)&local, sizeof(local)) < 0)
        {
            log.LogMessage(FATAL, "bind error , errno:%d, strerror: %s", errno, strerror(errno));
            exit(BindError);
        }
        log.LogMessage(INFO, "bind socket success ,_listensock:%d", _listensock);

        // Tcp是面向连接的,所以服务器一般是比较“被动”的,服务器一种处于一种
        if (listen(_listensock, backlog) < 0)
        {
            log.LogMessage(FATAL, "listen error , errno:%d, strerror: %s", errno, strerror(errno));
            exit(ListenError);
        }
        log.LogMessage(INFO, "listen success ,_listensock:%d", _listensock);
    }


    void Start()
    {
        ThreadPool<Task>::GetInstance()->Start();
        log.LogMessage(INFO, "tcpServer is running ...");
        for (;;)
        {
            // 1.获取新链接
            struct sockaddr_in client;
            socklen_t len = sizeof(client);
            int sockfd = accept(_listensock, (struct sockaddr *)&client, &len);
            if (sockfd < 0)
            {
                log.LogMessage(WARNING, "accept error , errno:%d, strerror: %s", errno, strerror(errno));
                continue;
            }
            uint16_t clientport = ntohs(client.sin_port);
            char clientip[32];
            inet_ntop(AF_INET, &(client.sin_addr), clientip, sizeof(clientip));

            // 2.根据新连接来进行通信
            log.LogMessage(INFO, "get a new link ... client ip : %s, client port : %d , sockfd:%d", clientip, clientport, sockfd);

            //version4 线程池版本
            Task t(sockfd,clientport,clientip);
            ThreadPool<Task>::GetInstance()->Push(t);
        }
    }

    ~TcpServer() {}

private:
    int _listensock;
    uint16_t _port;
    std::string _ip;
};

ThreadPool.hpp

#pragma once

#include <iostream>
#include <vector>
#include <string>
#include <queue>
#include <pthread.h>
#include <unistd.h>

struct ThreadInfo
{
    pthread_t tid;
    std::string name;
};

static const int defalutnum = 10;

template <class T>
class ThreadPool
{
public:
    void Lock()
    {
        pthread_mutex_lock(&mutex_);
    }
    void Unlock()
    {
        pthread_mutex_unlock(&mutex_);
    }
    void Wakeup()
    {
        pthread_cond_signal(&cond_);
    }
    void ThreadSleep()
    {
        pthread_cond_wait(&cond_, &mutex_);
    }
    bool IsQueueEmpty()
    {
        return tasks_.empty();
    }
    std::string GetThreadName(pthread_t tid)
    {
        for (const auto &ti : threads_)
        {
            if (ti.tid == tid)
                return ti.name;
        }
        return "None";
    }

public:
    static void *HandlerTask(void *args)
    {
        ThreadPool<T> *tp = static_cast<ThreadPool<T> *>(args);
        std::string name = tp->GetThreadName(pthread_self());
        while (true)
        {
            tp->Lock();

            while (tp->IsQueueEmpty())
            {
                tp->ThreadSleep();
            }
            T t = tp->Pop();
            tp->Unlock();

            t();
        }
    }
    void Start()
    {
        int num = threads_.size();
        for (int i = 0; i < num; i++)
        {
            threads_[i].name = "thread-" + std::to_string(i + 1);
            pthread_create(&(threads_[i].tid), nullptr, HandlerTask, this);
        }
    }
    T Pop()
    {
        T t = tasks_.front();
        tasks_.pop();
        return t;
    }
    void Push(const T &t)
    {
        Lock();
        tasks_.push(t);
        Wakeup();
        Unlock();
    }
    static ThreadPool<T> *GetInstance()
    {
        if (nullptr == tp_) // ???
        {
            pthread_mutex_lock(&lock_);
            if (nullptr == tp_)
            {
                std::cout << "log: singleton create done first!" << std::endl;
                tp_ = new ThreadPool<T>();
            }
            pthread_mutex_unlock(&lock_);
        }

        return tp_;
    }

private:
    ThreadPool(int num = defalutnum) : threads_(num)
    {
        pthread_mutex_init(&mutex_, nullptr);
        pthread_cond_init(&cond_, nullptr);
    }
    ~ThreadPool()
    {
        pthread_mutex_destroy(&mutex_);
        pthread_cond_destroy(&cond_);
    }
    ThreadPool(const ThreadPool<T> &) = delete;
    const ThreadPool<T> &operator=(const ThreadPool<T> &) = delete; // a=b=c
private:
    std::vector<ThreadInfo> threads_;
    std::queue<T> tasks_;

    pthread_mutex_t mutex_;
    pthread_cond_t cond_;

    static ThreadPool<T> *tp_;
    static pthread_mutex_t lock_;
};

template <class T>
ThreadPool<T> *ThreadPool<T>::tp_ = nullptr;

template <class T>
pthread_mutex_t ThreadPool<T>::lock_ = PTHREAD_MUTEX_INITIALIZER;

Main.cc

#include"TcpServer.hpp"
#include<memory>
#include<iostream>

void Usage(std::string proc)
{
    std::cout<<"\n\rUsage: "<<proc<<" port[1024+]"<<std::endl;
}

int main(int argc,char* argv[])
{
    if(argc!=2)
    {
        Usage(argv[0]);
        exit(UsageError);
    }

    uint16_t port = std::stoi(argv[1]);
    std::unique_ptr<TcpServer> tcp_svr(new TcpServer(port));
    tcp_svr->InitServer();
    tcp_svr->Start();

    return 0;
}

TcpClient.cc

#include <iostream>
#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <cstring>
#include<unistd.h>

void Usage(std::string proc)
{
    std::cout << "\n\rUsage: " << proc << " serverip  serverport[1024+]" << std::endl;
}

int main(int argc, char *argv[])
{
    if (argc != 3)
    {
        Usage(argv[0]);
        exit(1);
    }
    std::string serverip = argv[1];
    uint16_t serverport = std::stoi(argv[2]);

    int sockfd = socket(AF_INET, SOCK_STREAM, 0);

    if (sockfd < 0)
    {
        std::cerr << "socket error" << std::endl;
        return 1;
    }

    struct sockaddr_in server;
    memset(&server, 0, sizeof(server));
    server.sin_family = AF_INET;
    inet_pton(AF_INET, serverip.c_str(), &(server.sin_addr));
    server.sin_port = htons(serverport);

    // tcp要不要bind? 要bind 要不要显示的bind? 不用显示的bind 系统进行bind,随机端口
    // 客户端发起connect的时候,进行自动随机bind.
    int n = connect(sockfd, (struct sockaddr *)&server, sizeof(server));
    if (n < 0)
    {
        std::cerr << "connect error" << std::endl;
        return 2;
    }

    std::string message;
    std::cout<<"please Enter# ";
    std::getline(std::cin,message);
    write(sockfd,message.c_str(),message.size());

    char inbuffer[4096];
    int r = read(sockfd,inbuffer,sizeof(inbuffer));
    if(r>0)
    {
        inbuffer[r] = 0;
        std::cout<<inbuffer<<std::endl;
    }
    close(sockfd);
    std::cout<<"Connection closed by foreign host"<<std::endl;
    return 0;
}

Init.hpp 

#pragma once

#include<iostream>
#include<string>
#include<fstream>
#include<unordered_map>
#include "Log.hpp"

const std::string dictname = "./translation.txt";
const std::string sep = ":";

static bool Split(std::string & s,std::string *part1,std::string *part2)
{
    auto pos = s.find(sep);
    if(pos==std::string::npos)
    {
        return false;
    }
    *part1 = s.substr(0,pos);
    *part2 = s.substr(pos+1);
    return true;
}

class Init
{
public:
    Init()
    {
        std::ifstream in(dictname);
        if(!in.is_open())
        {
            log.LogMessage(FATAL,"ifstream open %s error",dictname.c_str());
            exit(1);
        }
        std::string line;
        while(std::getline(in,line))
        {
            std::string part1,part2;
            Split(line,&part1,&part2);
            dict.insert({part1,part2});
        }
        in.close();
    }

    std::string translation(const std::string &key)
    {
        auto iter = dict.find(key);
        if(iter == dict.end())
        {
            return "UnKnow";
        }
        else return iter->second;

        
    }
private:
    std::unordered_map<std::string,std::string> dict;

};

Log.hpp 

#pragma once

#include <iostream>
#include <cstdarg>
#include <ctime>
#include <string>
#include <unistd.h>
#include <fstream>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

enum
{
    DEBUG = 0,
    INFO,
    WARNING,
    ERROR,
    FATAL
};

enum
{
    Screen = 10,
    Onefile,
    Classfile
};

std::string LevelToString(int level)
{
    switch (level)
    {
    case DEBUG:
        return "Debug";
    case INFO:
        return "Info";

    case WARNING:
        return "Warning";
    case ERROR:
        return "Error";
    case FATAL:
        return "Fatal";
    default:
        return "Unknown";
    }
}

const int defaultstyle = Screen;
const std::string default_filename = "log.";
const std::string logdir="log";

class Log
{
public:
    Log():style(defaultstyle),filename(default_filename)
    {
        mkdir(logdir.c_str(),0775);
    }

    void Enable(int sty)
    {
        style = sty;
    }

    std::string TimestampToLocalTime()
    {
        time_t curr = time(nullptr);
        struct tm *currtime = localtime(&curr);
        char time_buffer[128];
        snprintf(time_buffer, sizeof(time_buffer), "%d-%d-%d %d:%d:%d",
                 currtime->tm_year + 1900, currtime->tm_mon, currtime->tm_mday, currtime->tm_hour,
                 currtime->tm_min, currtime->tm_sec);

        return time_buffer;
    }

    void WriteLog(const std::string &levelstr, const std::string &message)
    {
        switch (style)
        {
        case Screen:
            std::cout << message<<std::endl;
            break;
        case Onefile:
            WriteLogToOnefile("all", message);
            break;
        case Classfile:
            WriteLogToClassfile(levelstr, message);
            break;
        default:
            break;
        }
    }

    void WriteLogToOnefile(const std::string &logname, const std::string &message)
    {
        umask(0);
        int fd = open(logname.c_str(),O_CREAT | O_WRONLY | O_APPEND,0666);
        if(fd<0)return;
        write(fd,message.c_str(),message.size());
        close(fd);
        // std::ofstream out(logname);
        // if (!out.is_open())
        //     return;
        // out.write(message.c_str(), message.size());
        // out.close();
    }

    void WriteLogToClassfile(const std::string &levelstr, const std::string &message)
    {
        std::string logname = logdir;
        logname+="/";
        logname+=filename;
        logname += levelstr;
        WriteLogToOnefile(logname, message);
    }

    void LogMessage(int level, const char *format, ...) // 类c的日志接口
    {
        char rightbuffer[1024];
        va_list args;
        va_start(args, format);
        vsnprintf(rightbuffer, sizeof(rightbuffer), format, args);
        va_end(args);

        char leftbuffer[1024];
        std::string curtime = TimestampToLocalTime();
        std::string levelstr = LevelToString(level);
        std::string idstr = std::to_string(getpid());
        snprintf(leftbuffer, sizeof(leftbuffer), "[%s][%s][%s]",
                 levelstr.c_str(), curtime.c_str(), idstr.c_str());

        std::string logInfo = leftbuffer;
        logInfo += rightbuffer;

        WriteLog(levelstr, logInfo);
    }
    ~Log() {}

private:
    int style;
    std::string filename;
};


Log log;

class Conf
{
public:
    Conf()
    {
        log.Enable(Screen);
    }
    ~Conf(){}
};

Conf conf;

task.hpp

#pragma once
#include<string>
#include<iostream>
#include"Log.hpp"
#include"Init.hpp"

Init init;

class Task
{
public:
    Task(int sockfd, const uint16_t &clientport, const std::string &clientip)
    :clientip_(clientip),clientport_(clientport),sockfd_(sockfd)
    {}

    void Run()
    {
        char buffer[4096];
        // 测试代码
        ssize_t n = read(sockfd_, buffer, sizeof(buffer));
        if (n > 0)
        {
            buffer[n] = 0;
            std::cout << "client key# " << buffer << std::endl;
            std::string echo_string = init.translation(buffer);

            write(sockfd_, echo_string.c_str(), echo_string.size());
        }
        else if (n == 0)
        {
            log.LogMessage(INFO, "%s:%d quit,server close sockfd:%d", clientip_.c_str(), clientport_, sockfd_);
        
        }
        else
        {
            log.LogMessage(WARNING, "read error,sockfd:%d,clientip:%s ,clientport:%d ", sockfd_, clientip_.c_str(), clientport_);
            
        }
        close(sockfd_);
    }

    void operator()()//运算符重载实现仿函数
    {
        Run();
    }

    ~Task() {}
private:
    int sockfd_;
    std::string clientip_;
    uint16_t clientport_;
};

translation.txt

# 英汉互译键值对  
# English-Chinese Key-Value Pairs  
  
hello: 你好  
world: 世界  
goodbye: 再见  
thank you: 谢谢  
please: 请  
welcome: 欢迎  
happy: 快乐的  
sad: 悲伤的  
angry: 生气的  
excited: 兴奋的  
  
apple: 苹果  
banana: 香蕉  
orange: 橙子  
grape: 葡萄  
peach: 桃子  
watermelon: 西瓜  
strawberry: 草莓  
cherry: 樱桃  
  
morning: 早上  
afternoon: 下午  
evening: 晚上  
night: 夜晚  
weekday: 工作日  
weekend: 周末  
January: 一月  
February: 二月  
March: 三月  
April: 四月

只是写入了部分单词,比较简单,想要实现的更完整可以自行加入一些单词与中文意思及其解释等内容可以让该词典内容更丰富。

 

运行结果:

服务器一直在运行,客户端访问一次就退出了。

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

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

相关文章

基于单片机电子密码锁系统设计

**单片机设计介绍&#xff0c;基于单片机电子密码锁系统设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机电子密码锁系统设计概要主要包括以下几个方面&#xff1a; 一、系统概述 基于单片机电子密码锁系统是一个…

打造你的专属云开发环境:支持任意 IDE,任意云服务 | 开源日报 No.215

loft-sh/devpod Stars: 6.9k License: MPL-2.0 devpod 是一个开源的、仅限客户端的、不受限制的工具&#xff0c;可以与任何集成开发环境&#xff08;IDE&#xff09;一起使用&#xff0c;并允许您在任何云端、Kubernetes 或本地 Docker 上进行开发。 使用 devcontainer.json…

贪心算法|45.跳跃游戏II

力扣题目链接 class Solution { public:int jump(vector<int>& nums) {if (nums.size() 1) return 0;int curDistance 0; // 当前覆盖最远距离下标int ans 0; // 记录走的最大步数int nextDistance 0; // 下一步覆盖最远距离下标for (int i 0;…

qt-C++笔记之QLabel加载图片

qt-C笔记之QLabel加载图片 —— 2024-04-06 夜 code review! 文章目录 qt-C笔记之QLabel加载图片0.文件结构1.方法一&#xff1a;把图片放在项目路径下&#xff0c;在 .pro 文件中使用 DISTFILES添加图片文件1.1.运行1.2.qt_test.pro1.3.main.cpp 2.方法二&#xff1a;不在 .pr…

深入浅出 -- 系统架构之分布式集群的分类

一、单点故障问题 集群&#xff0c;相信诸位对这个概念并不陌生&#xff0c;集群已成为现时代中&#xff0c;保证服务高可用不可或缺的一种手段。 回想起初集中式部署的单体应用&#xff0c;因为只有一个节点&#xff0c;因此当该节点出现任意类型的故障&#xff08;网络、硬件…

go | 上传文件分析 | http协议分析 | 使用openssl 实现 https 协议 server.key、server.pem

是这样的&#xff0c;现在分析抓包数据 test.go package mainimport ("fmt""log""github.com/gin-gonic/gin" )func main() {r : gin.Default()// Upload single filer.MaxMultipartMemory 8 << 20r.POST("/upload", func(c *g…

【单片机】心率传感器,串口发送,MAX30102心率传感器模块

数值还是稳定的&#xff0c;但太贵了&#xff0c;stm32单片机的话&#xff0c;直接用这篇博客&#xff08;https://qq742971636.blog.csdn.net/article/details/137359381&#xff09;的代码&#xff0c;一样稳定。 解析这个模块的数据 char rev_max30102_bufferdata[30]; cha…

Flutter学习12 - SharedPreferences

1、shared_preferences 插件 类似于 Android 中的 SharedPreferences&#xff0c;键值对的形式进行本地存储 1.1、引入插件 在 pubspec.yaml 中引入 dependencies:shared_preferences: ^2.1.0在需要用到的文件中引入 import package:shared_preferences/shared_preference…

安全的通信协议HTTPS被攻击改采用什么防护方案

随着互联网的发展&#xff0c;保护用户在网上交换的敏感信息的安全性变得至关重要。HTTPS&#xff08;Hypertext Transfer Protocol Secure&#xff09;作为一种安全的通信协议&#xff0c;通过加密数据传输&#xff0c;保护用户的隐私和数据安全。然而&#xff0c;尽管HTTPS提…

Ubuntu部署LangChain-Chatchat

个人博客&#xff1a;https://blog.lukeewin.top 更多内容欢迎访问我的博客。 一、环境 OS: Ubuntu 20.04 PyTorch: 2.0.0 Python: 3.8 CUDA: 11.8 GPU: RTX 4090 24GB CPU: 12 vCPU Intel(R) Xeon(R) Platinum 8352V CPU 2.10GHz RAM: 90GB 硬盘: 180GB LLM: Chatglm3-6b E…

ubuntu20.04.6安装sshd服务,并连接到远程服务器

文章目录 sshd 是 OpenSSH 服务器的守护进程OpenSSH下载在 Ubuntu 上&#xff0c;可以按照以下步骤来管理 sshd 服务 防火墙开启22端口使用Mobaxterm链接服务器 sshd 是 OpenSSH 服务器的守护进程 它负责提供远程登录和安全的 shell 服务。通过启动 sshd 服务&#xff0c;可以…

小米汽车su7全色系展示源码

源码简介 小米汽车全色系展示源码&#xff0c;小米汽车su7全色系展示源码 安装教程 纯HTML&#xff0c;直接将压缩包上传网站目录解压即可 首页截图 源码下载 小米汽车su7全色系展示源码-小8源码屋源码简介 小米汽车全色系展示源码&#xff0c;小米汽车su7全色系展示源码 …

015——步进电机模块驱动开发(基于I.MX6uLL、MX-1502和28BYJ-48)

目录 一、电机驱动模块介绍 1.1 特性 1.2 应用范围 1.3 概述 1.4 电气属性 1.5 经典应用线路 二、电机介绍&#xff08;本节内容来自韦东山老师课程资料&#xff09; 三、 代码编写思路 四、 驱动程序 五、应用程序 一、电机驱动模块介绍 1.1 特性  低待机电流 (…

lua学习笔记6(经典问题输出99乘法表)

print("************for循环的99乘法表*************") for i 1, 9 dolocal line "" -- 创建一个局部变量来累积每行的输出--local 是一个关键字&#xff0c;用于声明一个局部变量。for j 1, i doline line .. j .. "*" .. i .. ""…

基于YOLOv8的铁路工人安全作业检测系统

&#x1f4a1;&#x1f4a1;&#x1f4a1;本文摘要&#xff1a;基于YOLOv8的铁路工人安全作业检测系统&#xff0c;属于小目标检测范畴&#xff0c;并阐述了整个数据制作和训练可视化过程&#xff0c; 博主简介 AI小怪兽&#xff0c;YOLO骨灰级玩家&#xff0c;1&#xff0…

考研高数(平面图形的面积,旋转体的体积)

1.平面图形的面积 纠正&#xff1a;参数方程求面积 2.旋转体的体积&#xff08;做题时&#xff0c;若以x为自变量不好计算&#xff0c;可以求反函数&#xff0c;y为自变量进行计算&#xff09;

深入浅出 -- 系统架构之分布式多形态的存储型集群

一、多形态的存储型集群 在上阶段&#xff0c;我们简单聊了下集群的基本知识&#xff0c;以及快速过了一下逻辑处理型集群的内容&#xff0c;下面重点来看看存储型集群&#xff0c;毕竟这块才是重头戏&#xff0c;集群的形态在其中有着多种多样的变化。 逻辑处理型的应用&…

Docker容器与虚拟化技术:OpenEuler 部署 Prometheus 与 Grafana

目录 一、实验 1.环境 2.OpenEuler 部署 Prometheus 3.OpenEuler 部署 Grafana 4.使用cpolar内网穿透 二、问题 1.拉取镜像失败 2.如何导入Grafana监控模板&#xff08;ES&#xff09; 一、实验 1.环境 &#xff08;1&#xff09;主机 表1 主机 系统架构版本IP备注…

【简单讲解下epoll】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

ELK报错,索引变成只读状态。

问题描述 今天发现当天的索引在ES中并没有创建&#xff0c;logstash中不停的报错&#xff1a; [2021-05-24T05:47:51,904][INFO ][logstash.outputs.elasticsearch] retrying failed action with response code: 403 ({“type”>“cluster_block_exception”, “reason”&g…