Window下CLion实现本机通过socket通信-C++

news2024/11/28 7:31:36

1.引言-什么是socket

socket即套接字,用于描述地址和端口,是一个通信链的句柄。应用程序通过socket向网络发出请求或者回应。

sockets(套接字)编程有三种,流式套接字(SOCK_STREAM),数据报套接字(SOCK_DGRAM),原始套接字(SOCK_RAW);前两种较常用。基于TCP的socket编程是采用的流式套接字

有可能多种协议使用同一种数据传输方式,所以在socket编程中,需要同时指明数据传输方式和协议。

2. socket常用函数

2.1 sockaddr_in

struct sockaddr_in这个结构体用来处理网络通信的地址

struct sockaddr_in {
    short            sin_family;       // 2 bytes e.g. AF_INET, AF_INET6
    unsigned short   sin_port;    //16位 2 bytes e.g. htons(3490)
    struct in_addr   sin_addr;     //32位 4 bytes see struct in_addr, below
    char             sin_zero[8];     // 8 bytes zero this if you want to
};
//另一个结构体 in_addr存放32位ip地址
struct in_addr {
    unsigned long s_addr;          // 4 bytes load with inet_pton()
};

端口号需要用 htons() 函数转换

2.2 htons()、 inet_addr()和inet_ntoa()

htons()作用是将端口号由主机字节序转换为网络字节序的整数值。(host to net)

inet_addr()作用是将一个IP字符串转化为一个网络字节序的整数值,用于sockaddr_in.sin_addr.s_addr。

inet_ntoa()作用是将一个sin_addr结构体输出成IP字符串(network to ascii)。比如:

printf("%s",inet_ntoa(mysock.sin_addr));

htonl()作用和htons()一样,不过它针对的是32位的(long),而htons()针对的是两个字节,16位的(short)。

与htonl()和htons()作用相反的两个函数是:ntohl()和ntohs()。

2.3 socket()

创建套接字

int socket(int af, int type, int protocol);

afIP地址的类型

  • AF_INET : IPv4

  • AF_INET6: IPV6

type:数据传输方式

  • SOCK_STREAM:面向连接的数据传输方式

  • SOCK_DGRAM:无连接的数据传输方式

protocol:传输协议

  • IPPROTO_TCP:TCP传输协议

  • IPPTOTO_UDP:UDP传输协议

返回值

  • 成功:0

  • 失败:-1

2.4 bind()

地址绑定,将套接字与地址关联

int bind(int sockfd, struct sockaddr *addr, socklen_t addrlen);

sockfd:socket文件描述符

addr:sockaddr 结构体变量的指针

addrlen:addr 变量的大小

返回值

  • 成功:0

  • 失败:-1

2.5 connect()

建立连接,创建与指定外部端口的连接

int connect(int sockfd, struct sockaddr *serv_addr, socklen_t addrlen);

sockfd:socket文件描述符

addr:sockaddr 结构体变量的指针

addrlen:addr 变量的大小

返回值

  • 成功:0

  • 失败:-1

2.6 listen()

让套接字进入被动监听状态(指当没有客户端请求时,套接字处于”睡眠“状态,只有当接收到客户端请求时,套接字才会被“唤醒”来响应请求),使得一个进程可以接收其他进程的请求,从而成为一个服务器进程

int listen(int sockfd, int backlog);

sockfd:被监听的套接字的标识符

backlog:请求队列的最大长度(能存放多少个客户端请求)

  • 请求队列:当套接字正在处理客户端请求时,如果有新的请求进来,套接字将把新的请求放入缓冲区,再从缓冲区取出请求 ,此缓冲区称为请求队列

返回值

  • 成功:0

  • 失败:-1

2.7 accept()

在一个套接口接收一个连接,当套接字处于监听状态时,可以通过accept()函数来接受客户端请求,accept()会阻塞程序进行,直到有新的请求到来

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

sockfd:服务器端套接字的标识符

addr:sockaddr 结构体变量的指针

addrlen:addr 变量的大小

返回值

  • 成功:返回接收到的套接字的描述符

  • 失败:-1

2.8 send()

发送数据,将数据由指定的socket传给对方主机

int send(int s, const void * msg, int len, unsigned int falgs);

s:以建立好连接的socket标识符

msg:发送的消息内容

len:发送内容的长度

falgs:一般设为0

返回值

  • 成功:返回实际传送出去的字符数

  • 失败:-1

2.9 recv()

接受数据,接收远端主机经过指定的socket传来的数据,并把数据存到buf指定的内存空间

int recv(int sock, void *buf, int len, unsigned int flags);

sock:接收端套接字描述符

buf:指定缓冲区,存放接收到的数据

len:缓冲区的长度

flags:一般设为0

返回值

  • 成功:返回接收到的字符数

  • 失败:-1

3.客户端/服务端模式

在TCP/IP(Transmission Control Protocol Internet Protocol / 传输控制协议和网际协议,TCP/IP是一种网络协议,由TCP和IP两个协议组成。它负责在计算机网络中传输数据,并确保数据传输的可靠性,同时确定数据在网络中的路径。TCP/IP是网络通信的基础,也是网络上最常用的协议之一)网络应用中,通信的两个进程相互作用的主要模式是客户/服务器模式,即客户端向服务器发出请求,服务器接收请求后,提供相应的服务。因此需要一种机制为希望通信的进程间建立联系,为二者的数据交换提供同步,这就是基于客户/服务端模式的TCP/IP。

3.1 什么是TCP

TCP有三个关键步骤:三次握手,传输确认和四次挥手

构建思路:

服务端:建立socket,声明自身的端口号和地址并绑定到socket,使用listen打开监听,然后不断用accept去查看是否有连接,如果有,捕获socket,并通过recv获取消息的内容,通信完成后调用closeSocket关闭这个对应accept到的socket,如果不再需要等待任何客户端连接,那么用closeSocket关闭掉自身的socket。

客户端:建立socket,通过端口号和地址确定目标服务器,使用Connect连接到服务器,send发送消息,等待处理,通信完成后调用closeSocket关闭socket。

3.2 编程步骤

(1)服务端

1、加载套接字库,创建套接字(WSAStartup()/socket());

2、绑定套接字到一个IP地址和一个端口上(bind());

3、将套接字设置为监听模式等待连接请求(listen());

4、请求到来后,接受连接请求,返回一个新的对应于此次连接的套接字(accept());

5、用返回的套接字和客户端进行通信(send()/recv());

6、返回,等待另一个连接请求;

7、关闭套接字,关闭加载的套接字库(closesocket()/WSACleanup());

(2)客户端

1、加载套接字库,创建套接字(WSAStartup()/socket());

2、向服务器发出连接请求(connect());

3、和服务器进行通信(send()/recv());

4、关闭套接字,关闭加载的套接字库(closesocket()/WSACleanup());

3.3 学习代码

#include <stdio.h>
#include <winsock2.h>

#pragma comment(lib, "ws2_32.lib")

int main(int argc, char* argv[]) 
{
        WORD sockVersion = MAKEWORD(2, 2);
        WSADATA wsaData;
        if (WSAStartup(sockVersion, &wsaData) != 0)
        {
                return 0;
        }
        
        SOCKET slisten = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if (slisten == INVALID_SOCKET)
        {
                printf("socket error !");
                return 0;
        }
        
        sockaddr_in sin;
        sin.sin_port = htons(8888);
        sin.sin_family = AF_INET;
        sin.sin_addr.S_un.S_addr = INADDR_ANY;
        if (bind(slisten, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR)
        {
                printf("bind error !");
        }
        
        if (listen(slisten, 5) == SOCKET_ERROR)
        {
                printf("listen error !");
                return 0;
        }
        
        SOCKET sClient;
        sockaddr_in remoteAddr;
        int nAddrlen = sizeof(remoteAddr);
        char revData[255];
        while (true)
        {
                printf("Wating for connecting... \r\n");
                sClient = accept(slisten, (SOCKADDR *)&remoteAddr, &nAddrlen);
                if (sClient == INVALID_SOCKET)
                {
                        printf("accept error !");
                        continue;
                }
                printf("accept a connection: %s \r\n", inet_ntoa(remoteAddr.sin_addr));
                
                int ret = recv(sClient, revData, 255, 0);
                if (ret > 0)
                {
                        revData[ret] = 0x00;
                        printf(revData);
                }
                
                const char * sendData = "hello, TCP Client";
                send(sClient, sendData, strlen(sendData), 0);
                closesocket(sClient);
                 
        }
        
        closesocket(slisten);
        WSACleanup();
        return 0;
}

client.cpp

#include <WINSOCK2.H>
#include <STDIO.H>
#include <iostream>
#include <cstring>
using namespace std;
#pragma comment(lib, "ws2_32.lib")

int main()
{
    WORD sockVersion = MAKEWORD(2,2);
    WSADATA data;
    if (WSAStartup(sockVersion, &data) != 0)
    {
        return 0;
    }

    while (true)
    {
        SOCKET sclient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if (sclient == INVALID_SOCKET)
        {
            printf("Invalid socket!");
            return 0;
        }

        sockaddr_in serAddr;
        serAddr.sin_family = AF_INET;
        serAddr.sin_port = htons(8888);
        serAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
        if (connect(sclient, (sockaddr *)&serAddr, sizeof(serAddr)) == SOCKET_ERROR)
        {
            printf("connect error!");
            closesocket(sclient);
            return 0;
        }

        string data;
        cin>>data;
        const char * sendData;
        sendData = data.c_str();
        send(sclient, sendData, strlen(sendData), 0);

        char recData[255];
        int ret = recv(sclient, recData, 255, 0);
        if (ret > 0)
        {
            recData[ret] = 0x00;
            printf(recData);
        }
        closesocket(sclient);
    }

    WSACleanup();
    return 0;
}

3.4 客户端一直发送数据代码

server.cpp

#include <stdio.h>
#include <winsock2.h>

#pragma comment(lib, "ws2_32.lib")

int main(int argc, char* argv[])
{
    WORD sockVersion = MAKEWORD(2,2);
    WSADATA wsadata;
    if (WSAStartup(sockVersion, &wsadata) != 0)
    {
        return 0;
    }

    SOCKET slisten = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (slisten == INVALID_SOCKET)
    {
        printf("socket error!");
        return 0;
    }

    sockaddr_in sin;
    sin.sin_family = AF_INET;
    sin.sin_port = htons(6000);
    sin.sin_addr.S_un.S_addr = INADDR_ANY;
    if(bind(slisten, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR)
    {
        printf("bind error!");
        return 0;
    }

    if (listen(slisten, 5) == SOCKET_ERROR)
    {
        printf("listen error!");
        return 0;
    }

    SOCKET sClient;
    sockaddr_in remoteAddr;
    int nAddrlen = sizeof(remoteAddr);
    char revData[255];
    while (true)
    {
        printf("Waiting for connecting... \n");
        sClient = accept(slisten, (SOCKADDR *)&remoteAddr, &nAddrlen);
        if (sClient == SOCKET_ERROR)
        {
            printf("accept error !");
            continue;
        }
        int ret = recv(sClient, revData, 255, 0);
        if (ret > 0 )
        {
            revData[ret] = 0x00;
            printf("Received: %s\n", revData);
        }

        const char * sendData = "Hello World from Server";
        send(sClient, sendData, strlen(sendData), 0);
        printf("Sent: %s\n", sendData);

        // Keep receiving messages
        while (true)
        {
            ret = recv(sClient, revData, 255, 0);
            if (ret > 0)
            {
                revData[ret] = 0x00;
                printf("Received: %s\n", revData);
            }
        }

        closesocket(sClient);
    }

    closesocket(slisten);
    WSACleanup();
    return 0;
}

client.cpp

#include <winsock2.h>
#include <stdio.h>
#include <iostream>
#include <cstring>

#pragma comment(lib, "ws2_32.lib")

int main()
{
    WORD sockVersion = MAKEWORD(2,2);
    WSADATA data;
    if(WSAStartup(sockVersion, &data) != 0)
    {
        return 0;
    }

    SOCKET sclient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if(sclient == INVALID_SOCKET)
    {
        printf("Invalid socket!");
        return 0;
    }

    sockaddr_in serAddr;
    serAddr.sin_family = AF_INET;
    serAddr.sin_port = htons(6000);
    serAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
    if (connect(sclient, (sockaddr *)&serAddr, sizeof(serAddr)) == SOCKET_ERROR)
    {
        printf("connect error!");
        closesocket(sclient);
        return 0;
    }

    const char * sendData = "Hello World from Client";
    send(sclient, sendData, strlen(sendData), 0);
    printf("Sent: %s\n", sendData);

    char recData[255];
    int ret = recv(sclient, recData, 255, 0);
    if (ret > 0)
    {
        recData[ret] = 0x00;
        printf("Received: %s\n", recData);
    }

    // Keep sending messages
    while (true)
    {
        const char * helloData = "Hello";
        send(sclient, helloData, strlen(helloData), 0);
        printf("Sent: %s\n", helloData);

        // Sleep for 1 second
        Sleep(1000);
    }

    closesocket(sclient);
    WSACleanup();
    return 0;
}

3.5 用户在客户端输入数据代码

server.cpp

#include <stdio.h>
#include <winsock2.h>

#pragma comment(lib, "ws2_32.lib")

int main(int argc, char* argv[])
{
    WORD sockVersion = MAKEWORD(2,2);
    WSADATA wsadata;
    if (WSAStartup(sockVersion, &wsadata) != 0)
    {
        return 0;
    }

    SOCKET slisten = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (slisten == INVALID_SOCKET)
    {
        printf("socket error!");
        return 0;
    }

    sockaddr_in sin;
    sin.sin_family = AF_INET;
    sin.sin_port = htons(6000);
    sin.sin_addr.S_un.S_addr = INADDR_ANY;
    if(bind(slisten, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR)
    {
        printf("bind error!");
        return 0;
    }

    if (listen(slisten, 5) == SOCKET_ERROR)
    {
        printf("listen error!");
        return 0;
    }

    SOCKET sClient;
    sockaddr_in remoteAddr;
    int nAddrlen = sizeof(remoteAddr);
    char revData[255];

    while (true)
    {
        printf("Waiting for connecting... \n");
        sClient = accept(slisten, (SOCKADDR *)&remoteAddr, &nAddrlen);
        if (sClient == SOCKET_ERROR)
        {
            printf("accept error !");
            continue;
        }

        // Keep receiving messages
        while (true)
        {
            int ret = recv(sClient, revData, 255, 0);
            if (ret > 0)
            {
                revData[ret] = 0x00;
                printf("Received: %s\n", revData);
            }
            else if (ret == 0) // Connection closed
            {
                printf("Client disconnected.\n");
                closesocket(sClient);
                break;
            }
            else if (ret == SOCKET_ERROR) // Error receiving
            {
                printf("recv error!\n");
                closesocket(sClient);
                break;
            }
        }
    }

    closesocket(slisten);
    WSACleanup();
    return 0;
}

client.cpp

#include <winsock2.h>
#include <stdio.h>
#include <iostream>
#include <cstring>

#pragma comment(lib, "ws2_32.lib")

int main()
{
    WORD sockVersion = MAKEWORD(2,2);
    WSADATA data;
    if(WSAStartup(sockVersion, &data) != 0)
    {
        return 0;
    }

    SOCKET sclient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if(sclient == INVALID_SOCKET)
    {
        printf("Invalid socket!");
        return 0;
    }

    sockaddr_in serAddr;
    serAddr.sin_family = AF_INET;
    serAddr.sin_port = htons(6000);
    serAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
    if (connect(sclient, (sockaddr *)&serAddr, sizeof(serAddr)) == SOCKET_ERROR)
    {
        printf("connect error!");
        closesocket(sclient);
        return 0;
    }

    char sendData[255];

    while (true)
    {
        std::cout << "Enter message: ";
        std::cin.getline(sendData, 255);
        if (strlen(sendData) == 0) {
            continue;
        }
        send(sclient, sendData, strlen(sendData), 0);
        printf("Sent: %s\n", sendData);
    }

    closesocket(sclient);
    WSACleanup();
    return 0;
}

4.在CLion建立客户端和服务端

修改CLion配置如下图

切换到此,点击运行即可进行通信

5. 运行效果

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

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

相关文章

Ubuntu18.04.6 LTS安装opencv3.3.0(详细步骤教程)

本章教程在Ubuntu18.04.6LTS上安装opencv3.3.0版本,亲测已安装成功。 一、下载opencv安装包 1、下载 wget https://github.com/opencv/opencv/archive/3.3.0.zip2、解压 unzip opencv-3.3.0.zip如果没有unzip命令,需要先安装一下 apt install unzip

2024第八届自然语言处理与信息检索国际会议 (NLPIR 2024)即将召开!

2024第八届自然语言处理与信息检索国际会议 (NLPIR 2024)将于2024年12月13-15日在日本冈山的冈山大学举行。NLPIR 2024将为自然语言处理与信息检索领域的专家学者提供一个交流与合作的平台&#xff0c;推动该领域的学术进步和技术创新。同时&#xff0c;本次会议也将为相关企业…

Spring -- 使用XML开发MyBatis

T04BF &#x1f44b;专栏: 算法|JAVA|MySQL|C语言 &#x1faf5; 今天你敲代码了吗 文章目录 MyBatis XML配置文件开发配置连接字符串和MyBatis写Mapper层代码添加mapper接口添加UserInfoXmLMapper.xml 操作数据库INSERTDELETE & UPDATE MyBatis XML配置文件开发 实际上,除…

JAVA基础 - 枚举类

目录 一. 简介 二. 声明 属性 方法 三. 常用方法 四. 使用技巧 五. 使用情景 六. 总结 一. 简介 在 Java 中&#xff0c;枚举类&#xff08;Enum Class&#xff09;是一种特殊的类&#xff0c;用于定义一组有限的、预定义的常量值。 枚举类的主要特点和优势包括&#x…

Cyberchef基础概念之-循环语句操作-Jump/Label

在本专栏的前面的文章介绍了fork,merge,subsection,register等多种概念来解决实际场景的问题。本文将介绍的Jump/Label的操作类似于编程语言中的for和while的功能&#xff0c;相信在学会使用jump操作后&#xff0c;将有助于解决更为复杂的数据处理问题。 本文将详细的介绍该操…

Linux冯诺依曼体系、操作系统、进程概念、进程状态、进程切换

个人主页&#xff1a;仍有未知等待探索-CSDN博客 专题分栏&#xff1a;Linux 目录 一、冯诺依曼体系结构 二、操作系统 1、概念 2、为什么要有操作系统&#xff1f; 3、理解操作系统 1.管理的本质 2.管理的概念 3.操作系统结构图 4.为什么要有操作系统&#xff1f; 三…

【计算机网络】ICMP报文实验

一&#xff1a;实验目的 1&#xff1a;掌握ICMP报文的各种类型及其代码。 2&#xff1a;掌握ICMP报文的格式。 3&#xff1a;深入理解TTL的含义&#xff08;Time to Live&#xff0c;生存时间&#xff09;。 二&#xff1a;实验仪器设备及软件 硬件&#xff1a;RCMS-C服务器…

ocrbench:on the hidden mystery of ocr in large multimodel models

【多模态】29、OCRBench | 为大型多模态模型提供一个 OCR 任务测评基准-CSDN博客文章浏览阅读1.9k次,点赞26次,收藏22次。本文主要介绍 OCRBench_ocrbenchhttps://blog.csdn.net/jiaoyangwm/article/details/138414709OpenCompass司南 - 评测榜单评测榜单旨在为大语言模型和多…

LINUX 孤儿进程和僵尸进程

1、孤儿进 一个父进程退出&#xff0c;而它的一个或多个子进程还在运行&#xff0c;那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养&#xff0c;并由init进程对它们完成状态收集工作 为了释放子进程的占用的系统资源&#xff1a; 进程结束之后&#xf…

CAPL通过回调函数applILTxPending模拟E2E失败

文章目录 问题解决办法之前的文章 CANoe CAPL通过回调函数applILTxPending实现E2E模拟发送 问题 问题:在使用CANoeIL仿真模拟E2E报文时,在一台电脑可以仿真成功,同样的工程复制到另外一台电脑就不行了,E2E不计算,这是因为什么? 两台机柜用的都是15版本,模拟失败的是从…

C++ //练习 15.30 编写你自己的Basket类,用它计算上一个练习中交易记录的总价格。

C Primer&#xff08;第5版&#xff09; 练习 15.30 练习 15.30 编写你自己的Basket类&#xff0c;用它计算上一个练习中交易记录的总价格。 环境&#xff1a;Linux Ubuntu&#xff08;云服务器&#xff09; 工具&#xff1a;vim 代码块&#xff1a; /********************…

昇思25天学习打卡营第24天|基于MindSpore的红酒分类实验

相关知识 KNN k临近算法K nearest neighbor&#xff0c;用于分类和回归。主要思想为&#xff0c;训练一个样本和所有训练样本之间的举例&#xff0c;找到和这个样本最接近的k个样本&#xff0c;根据这k个样本的类别进行投票&#xff0c;票数最高的类就是分类的结果。模型效果…

全网最最实用--模型高效推理:量化基础

文章目录 一、量化基础--计算机中数的表示1. 原码&#xff08;Sign-Magnitude&#xff09;2. 反码&#xff08;Ones Complement&#xff09;3. 补码&#xff08;Twos Complement&#xff09;4. 浮点数&#xff08;Floating Point&#xff09;a.常用的浮点数标准--IEEE 754(FP32…

力扣 459重复的子字符串

思路&#xff1a; KMP算法的核心是求next数组 next数组代表的是当前字符串最大前后缀的长度 而求重复的子字符串就是求字符串的最大前缀与最大后缀之间的子字符串 如果这个子字符串是字符串长度的约数&#xff0c;则true /** lc appleetcode.cn id459 langcpp** [459] 重复…

LangChain 一 hello LLM

本来想先写LangChain系列的&#xff0c;但是最近被AutoGen、LlamaIndex给吸引了。2023就要过去了&#xff0c;TIOBE数据编程语言排名Python都第一了&#xff0c;可见今年AI开发之热。好吧&#xff0c;一边学习业界通用的LangChain框架&#xff0c;一边准备跨年吧。 前言 先是O…

基于FPGA的YOLOV5s神经网络硬件部署

一 YOLOV5s 本设计以YOLOV5s部署于FPGA上为例进行分析概述。YOLOV5s网络主要包括backbone、neck、head三部分。 涉及的关键算子&#xff1a; Conv&#xff1a;卷积&#xff0c;包括3*3、1*1&#xff0c;stride1/2Concat&#xff1a;Upsample:Pooling&#xff1a;ADD 二 评估 …

oncoPredict:根据细胞系筛选数据预测体内或癌症患者药物反应和生物标志物

在14年的时候&#xff0c;oncoPredict函数的开发团队在Genome Biology上发了一篇文章。 这篇文章的核心目的是阐释了使用治疗前基线肿瘤基因表达数据去预测患者化疗反应。开发团队发现使用细胞系去预测临床样本的药物反应是可行的。 鉴于之前的理论&#xff0c;该研究团队首先…

docker Docs相关使用文档链接

Docker Docshttps://docs.docker.com/ docker compose | Docker Docshttps://docs.docker.com/reference/cli/docker/compose/docker | Docker Docshttps://docs.docker.com/reference/cli/docker/

【计算机网络】静态路由实验

一&#xff1a;实验目的 1&#xff1a;掌握通过静态路由方法实现网络的连通性。 二&#xff1a;实验仪器设备及软件 硬件&#xff1a;RCMS-C服务器、网线、Windows 2019/2003操作系统的计算机等。 软件&#xff1a;记事本、WireShark、Chrome浏览器等。 三&#xff1a;实验方…

linux集群架构--高可用--keepalived(13985字详解)

linux架构高可用 a.概述 高可用&#xff1a;HA HighAvailablity —>Keepalived生成VIP&#xff0c;DNS解析到这个IP地址即可 b.原理 keepalived 是基于VRRP协议实现高可用VRRP虚拟路由器冗余协议&#xff0c;最开始是给网络设备实现高可用&#xff0c;目前keepalive实现v…