百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

c++ socket (3) IPv4、IPv6兼容处理

nanshan 2024-10-04 18:03 22 浏览 0 评论

IP6是大势所趋(十多年前我也是这样听说的, 哈), 所以要考虑IPv4\IPv6的兼容性.

代码示例

a、IPv6兼容IPv4,所以在服务器监听时,尽量使用IPv6.

b、客户端通过getaddrinfo 获取服务端地址

公共部分头文件(socket.h)

#ifndef __SOCKET_H__
#define __SOCKET_H__

#include <memory>
#include <string>
#include <memory.h>

#ifdef _WIN32
#include <WinSock2.h>
#include <ws2tcpip.h>

#define socket_t SOCKET
#define invalid_socket INVALID_SOCKET
#define socklen_t int

#pragma comment(lib, "ws2_32.lib")  
#endif // _WIN32

#ifdef __linux__
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>  
#include <netinet/in.h>  
#include <arpa/inet.h>  
#include <netdb.h>

#define socket_t int
#define invalid_socket -1
#define closesocket close
#endif

class Socket {

    static bool init_socket()
    {
#ifdef _WIN32
        WSADATA ws;
        static bool _init = (0 == WSAStartup(MAKEWORD(2, 2), &ws));
        return _init;
#endif
        return true;
    }

public:
    //创建服务器(优先使用IPv6)
    static socket_t CreateServer(int port, int type = SOCK_STREAM)
    {
        init_socket();
        struct addrinfo hints;
        memset(&hints, 0, sizeof hints);
        hints.ai_family = AF_UNSPEC; // 任何地址家族  
        hints.ai_socktype = type; // 任何套接字类型  
        hints.ai_protocol = (type == SOCK_STREAM) ? IPPROTO_TCP : IPPROTO_UDP;
        hints.ai_flags = AI_PASSIVE;

        int ret = 0;
        struct addrinfo* res;
        if ((ret = getaddrinfo(nullptr, std::to_string(port).c_str(), &hints, &res)) != 0) {
            std::cout << "err getaddrinfo:" << gai_strerror(ret) << std::endl;
            return invalid_socket;
        }

        int reuseAddr = 1;
        socket_t skt = invalid_socket;
        for (struct addrinfo* p = res; p != 0; p = p->ai_next) {

            if ((p->ai_family != AF_INET && p->ai_family != AF_INET6)
                || (skt != invalid_socket && p->ai_family == AF_INET)) {
                continue;
            }
            //关闭之前的IPv4
            if (skt != invalid_socket) {
                closesocket(skt);
                skt = invalid_socket;
            }
            //创建socket 及 bind
            if (invalid_socket == (skt = socket(p->ai_family, p->ai_socktype, p->ai_protocol))
                || 0 != setsockopt(skt, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuseAddr, sizeof(int))
                || 0 != bind(skt, (const struct sockaddr*)p->ai_addr, p->ai_addrlen)) {

                if (skt != invalid_socket) {
                    closesocket(skt);
                    skt = invalid_socket;
                }
                continue;
            }
            //如果是IPv6,就不必再继续了
            if (skt != invalid_socket && p->ai_family == AF_INET6) {
                break;
            }
        }
        freeaddrinfo(res);
        return skt;
    }

    //连接服务端
    static socket_t ConnectServer(const char* addr, int port)
    {
        init_socket();
        struct addrinfo hints;
        memset(&hints, 0, sizeof hints);
        hints.ai_family = AF_UNSPEC;
        hints.ai_socktype = SOCK_STREAM;
        hints.ai_protocol = IPPROTO_TCP;

        int ret = 0;
        struct addrinfo* res;
        if ((ret = getaddrinfo(addr, std::to_string(port).c_str(), &hints, &res)) != 0) {
            std::cerr << "getaddrinfo:" << gai_strerror(ret) << std::endl;
            return invalid_socket;
        }

        int reuseAddr = 1;
        socket_t skt = invalid_socket;
        for (struct addrinfo* p = res; p != 0 && skt == invalid_socket; p = p->ai_next) {

            if ((p->ai_family != AF_INET && p->ai_family != AF_INET6)) {
                continue;
            }
            //创建socket 及 connect
            if (invalid_socket != (skt = socket(p->ai_family, p->ai_socktype, p->ai_protocol))
                && 0 != connect(skt, (const struct sockaddr*)p->ai_addr, p->ai_addrlen)) {
                std::cerr << "connect:" << strerror(errno);
                closesocket(skt);
                skt = invalid_socket;
            }
        }
        freeaddrinfo(res);
        return skt;
    }
};

#endif

服务器

int main()
{
    socket_t skt;
    if (invalid_socket == (skt = Socket::CreateServer(80))) {
        std::cerr << "CreateServer : " << strerror(errno) << std::endl;
        return 0;
    }
    if (0 != listen(skt, 255)) {
        return 0;
    }
    char addr[128] = { 0 };
    socklen_t addrLen = 28;
    socket_t client = accept(skt, (struct sockaddr*)addr, &addrLen);
    //获取对端地址
    char node[128] = { 0 };
    char port[32] = { 0 };
    if (0 == getnameinfo((const sockaddr*)addr, addrLen, node, 128, port, 32, 0)) {
        if (0 == memcmp(node, "::ffff:", strlen("::ffff:"))) {
            std::cout << "IPv4 connect : " << node + strlen("::ffff:") << " : " << port << std::endl;
        }
        else {
            std::cout << "IPv6 connect :" << node << " : " << port << std::endl;
        }
    }
    //.....
    closesocket(client);
    closesocket(skt);
    return 0;
}

客户端

int main() 
{
    socket_t skt;
    if (invalid_socket != (skt = Socket::ConnectServer("www.baidu.com", 80))) {
        std::cout << "connect www.baidu.com ok" << std::endl;
        closesocket(skt);
    }
    if (invalid_socket != (skt = Socket::ConnectServer("learn.microsoft.com", 80))) {
        std::cout << "connect learn.microsoft.com ok" << std::endl;
        closesocket(skt);
    }
    if (invalid_socket != (skt = Socket::ConnectServer("fe80::53bd:b44a:cf4a:d202", 80))) {
        std::cout << "connect fe80::53bd:b44a:cf4a:d202 ok" << std::endl;
        closesocket(skt);
    }
    if (invalid_socket != (skt = Socket::ConnectServer("192.168.1.21", 80))) {
        std::cout << "connect 192.168.1.21 ok" << std::endl;
        closesocket(skt);
    }
    return 0;
}

文心一言代码解析:

init_socket()函数: 这个函数是用来初始化套接字库的。

如果代码在Windows平台上运行(通过#ifdef _WIN32判断),它将调用WSAStartup()函数来初始化Windows套接字库,并检查是否成功初始化。如果成功,返回true;否则返回false。在其他平台上,这个函数总是返回true

CreateServer()函数: 这个函数尝试创建一个服务器套接字并绑定到指定的端口。函数的参数包括端口号和套接字类型(默认为SOCK_STREAM,即TCP)。

  1. 首先,它调用init_socket()来初始化套接字库。
  2. 然后,它使用getaddrinfo()函数来获取与给定端口和地址家族相关的地址信息。这个函数返回一个地址信息链表,包含了所有可能的地址(IPv4和IPv6)。
  3. 接着,函数遍历这个地址链表,尝试为每个地址创建一个套接字并绑定它。如果成功,它会关闭之前创建的所有套接字(如果有的话),然后继续处理下一个地址。
  4. 如果成功创建了套接字并绑定了某个地址,并且这个地址是IPv6地址,那么函数会停止处理其他地址,并返回创建的套接字。
  5. 最后,无论成功与否,都会使用freeaddrinfo()函数释放之前获取的地址信息。 CreateServer主要目的是为了确保服务器套接字优先使用IPv6地址。如果系统支持IPv6,并且可以绑定到IPv6地址,那么它就会停止处理其他地址并返回套接字。否则,它将尝试使用IPv4地址。这有助于确保应用程序可以同时支持IPv4和IPv6,从而提供更好的网络连接性。

ConnectServer(): 这个函数用于连接到服务器。

  1. 它首先调用init_socket()来初始化套接字库。然后,它使用getaddrinfo()函数来获取与给定地址和端口相关的地址信息。如果getaddrinfo()返回非零值,表示出现错误,该错误消息会被打印到标准错误输出,并返回一个无效的套接字描述符。
  2. 接下来,代码会遍历获取到的地址信息,尝试为每个地址创建一个套接字并连接到该地址。如果成功,它会继续尝试下一个地址。如果套接字创建或连接失败,它会关闭套接字并继续处理下一个地址。
  3. 最后,使用freeaddrinfo()函数释放之前获取的地址信息,并返回创建的套接字描述符。如果连接成功,它将是一个有效的套接字描述符;如果连接失败,它将是一个无效的套接字描述符。

函数说明:

getaddrinfo 函数 (ws2tcpip.h) - Win32 apps | Microsoft Learn

getnameinfo 函数 (ws2tcpip.h) - Win32 apps | Microsoft Learn

getaddrinfo(3) - Linux manual page

getnameinfo(3) - Linux manual page

getaddrinfo()是一个用于网络编程的函数,它用于将主机名和服务名解析为网络地址结构。这个函数是在套接字编程中经常使用的,特别是在处理DNS查找和地址解析时。

函数原型通常如下:

int getaddrinfo(const char *node, const char *service,
               const struct addrinfo *hints,
               struct addrinfo **res);

参数说明:

  • node:主机名或IP地址字符串。如果为NULL,表示使用通配地址。
  • service:服务名或端口号字符串。如果为NULL,表示使用默认服务。
  • hints:指向一个addrinfo结构体的指针,该结构体包含用于指导地址解析的提示信息。例如,可以指定地址族、套接字类型和协议。
  • res:指向一个指向addrinfo结构的指针的指针,该结构体将包含解析出的地址信息。 返回值:
  • 如果成功,返回0,并将res指向一个链表,链表中包含解析出的地址信息。
  • 如果失败,返回一个非零错误码,并将res设置为NULL。

使用getaddrinfo()函数,你可以将主机名和服务名解析为网络地址结构,这在创建套接字、绑定地址和进行网络通信时非常有用。该函数能够处理各种地址类型和协议,使得在网络编程中更加灵活和方便。

getnameinfo()是一个用于网络编程的函数,它用于将网络地址结构(通常由getaddrinfo()函数返回)转换为主机名和服务名。这个函数是在套接字编程中经常使用的,特别是在处理DNS查找和地址解析时。

函数原型通常如下:

int getnameinfo(const struct sockaddr *sa, socklen_t salen,
               char *host, size_t hostlen,
               char *serv, size_t servlen, int flags);

参数说明:

  • sa:指向一个sockaddr结构的指针,该结构包含要解析的网络地址。
  • salensockaddr结构的大小。
  • host:指向一个字符数组的指针,用于存储解析出的主机名。
  • hostlenhost数组的大小。
  • serv:指向一个字符数组的指针,用于存储解析出的服务名。
  • servlenserv数组的大小。
  • flags:一组标志位,用于控制函数的行为。例如,NI_NUMERICHOST表示主机名应以数字形式返回,而NI_NUMERICSERV表示服务名应以数字形式返回。 返回值:
  • 如果成功,返回0。
  • 如果失败,返回一个非零错误码。

使用getnameinfo()函数,你可以将网络地址转换为可读的主机名和服务名,这在调试、日志记录或用户界面中可能是非常有用的。

getaddrinfo一些资料

它的由来:

getaddrinfo函数的由来可以追溯到IPv4和IPv6共存的时期。在早期,网络编程主要使用gethostbyname系列函数来将主机名转换为IP地址。然而,随着IPv6的普及和网络协议的发展,传统的gethostbyname函数逐渐无法满足需求。由于IPv6地址是128位,传统的点分十进制表示法不再适用,需要使用新的表示法。此外,随着网络协议的多样化和复杂化,应用程序需要更灵活的方式来处理不同的协议和套接字类型。

为了解决这些问题,getaddrinfo函数被引入到网络编程中。它是在1990年代末期设计的,并在POSIX.1-2001标准中被正式定义。该函数最初是为了支持IPv6而设计的,但后来也被扩展到支持IPv4。

getaddrinfo函数的设计目标是提供一个统一的接口,用于将主机名和服务名转换为套接字地址结构,同时支持IPv4和IPv6。它隐藏了底层协议的复杂性,使得应用程序可以更加方便地处理网络地址和端口的转换。

该函数最初是在Unix-like操作系统中实现的,但后来也被移植到了其他操作系统中,如Windows。在Windows系统中,getaddrinfo函数是通过Winsock2 API提供的,并且与IPv6的兼容性更好。

综上所述,getaddrinfo函数的由来是为了解决IPv4和IPv6共存时期的需求,提供一种更加灵活、方便的网络地址转换接口。它是在1990年代末期设计的,并在POSIX标准中被定义。该函数最初是为了支持IPv6而设计的,但后来也被扩展到支持IPv4,并且被广泛应用于各种操作系统中。

该函数的作用主要包括

1. 名字到地址以及服务到端口的转换。它返回一个sockaddr结构的链表,这些sockaddr地址结构随后可有套接口函数(socket、bind、connect、listen等)直接调用,将协议相关性隐藏在该函数内部。

2. 隐藏协议相关性。应用程序只要处理由getaddrinfo函数填写的套接口地址结构,不需要考虑数据尾端,地址转换等。

getaddrinfo的原理是:根据hints参数指定的参数要求,获取服务器信息,并将获取的结果存储到res中。如果应用程序需要使用主机名代替IP地址,或服务名代替端口号,需要先把对应关系增加到对应的配置文件中,否则getaddrinfo会解析出错。

此外,getaddrinfo函数在POSIX规范中定义,它能够处理协议无关的转换,既可用于IPv4也可用于IPv6。它能够根据给定的主机名和服务名,返回一个包含用于创建套接字对象的五元组(包含地址族、套接字类型、协议等)。


getaddrinfo函数还有一些其他的特点和作用:

1. 地址和端口号转换:除了将主机名转换为IP地址外,getaddrinfo还可以将服务名转换为端口号。这对于一些非标准的服务名(如“http”或“ftp”)尤其有用,这些服务名无法通过传统的getservbyname函数直接转换。

2. 套接字类型和协议处理:getaddrinfo可以根据需要进行协议和套接字类型的转换。这使得应用程序可以更灵活地处理不同的网络协议和套接字类型,而无需自行处理底层细节。

3. 错误处理:getaddrinfo函数在出现错误时会返回一个特定的错误码,而不是直接失败。这使得应用程序能够更好地处理错误情况,并采取适当的措施。

4. 异步操作:getaddrinfo函数支持异步操作,这意味着它可以在后台进行地址解析,而不会阻塞应用程序的主线程。这对于需要快速响应的应用程序非常有用。

5. 可移植性:getaddrinfo函数的设计考虑到了跨平台可移植性。无论是在IPv4还是IPv6环境下,它都能够返回适用于任何协议族的地址。这使得使用getaddrinfo的应用程序更加易于移植和维护。

总的来说,getaddrinfo函数在网络编程中起着重要的作用,它使得应用程序可以更方便、灵活地处理网络地址和端口的转换,同时还隐藏了底层协议的复杂性。


除了上述提到的特点,getaddrinfo函数还有以下一些重要功能:

1. 负载均衡和故障转移:通过getaddrinfo函数,可以获取主机名对应的多个IP地址,从而实现负载均衡和故障转移。当某个IP地址出现故障时,可以自动切换到其他可用的IP地址上。

2. 可重入性:getaddrinfo函数的可重入性取决于其内部调用的gethostbyname和getservbyname函数是否是它们的可重入版本。这意味着该函数可以在多线程环境中安全使用,而不会产生竞态条件。

3. IPv6支持:getaddrinfo函数是协议无关的,既可用于IPv4也可用于IPv6。在IPv6环境中,它能够处理IPv6地址的转换,使得应用程序能够更好地支持IPv6协议。

4. 地址结构链表:getaddrinfo函数返回的是一个addrinfo结构的链表,每个结构体包含了一个地址的信息,包括IP地址、端口号、协议类型等。这个链表可以由套接字函数直接使用,简化了网络编程的复杂性。

5. 兼容性:getaddrinfo函数兼容了传统的gethostbyname和getservbyname函数,这意味着在某些情况下,可以使用这些函数作为替代方案。然而,由于getaddrinfo函数具有更多的功能和更好的性能,因此推荐使用该函数进行网络名称解析。

综上所述,getaddrinfo函数在网络编程中起着非常重要的作用,它提供了一种方便、灵活、可靠的方式来处理网络地址和端口的转换。通过使用该函数,应用程序可以更好地支持各种网络协议和地址类型,同时简化网络编程的复杂性。

函数的原理:

getaddrinfo函数的原理是通过DNS(Domain Name System)进行主机名解析。DNS是一个分布式的命名系统,用于将主机名转换为IP地址。当使用getaddrinfo函数时,它会调用系统的DNS解析库,向DNS服务器发送查询请求,获取主机名对应的IP地址。

getaddrinfo函数的设计目标是提供一个统一的接口,用于将主机名和服务名转换为套接字地址结构,同时支持IPv4和IPv6。它隐藏了底层协议的复杂性,使得应用程序可以更加方便地处理网络地址和端口的转换。

工作原理可以分为以下几个步骤:

1. 参数检查:getaddrinfo函数首先会检查传入的参数是否有效。这些参数包括主机名、服务名、套接字类型和协议类型等。如果参数无效,函数将返回错误码。

2. 模板检查:getaddrinfo函数可以接受一个名为hints的参数,该参数指定了期望的地址类型。函数会根据hints参数中的值来过滤返回的地址结构。如果hints参数为空,函数将返回所有可用的地址结构。

3. DNS查询:getaddrinfo函数调用系统的DNS解析库,向DNS服务器发送查询请求,以获取主机名对应的IP地址。如果主机名是一个域名,函数将尝试将其解析为IP地址。如果主机名是一个IP地址,函数将直接使用该地址。

4. 地址转换:在获取到IP地址后,getaddrinfo函数会根据hints参数中的值进行地址转换。如果hints参数指定了特定的套接字类型或协议类型,函数将尝试将其转换为对应的地址结构。

5. 链表构建:getaddrinfo函数将返回一个addrinfo结构的链表,每个结构体包含了一个地址的信息,包括IP地址、端口号、协议类型等。这个链表可以由套接字函数直接使用,简化了网络编程的复杂性。

6. 错误处理:如果在查询过程中出现错误,getaddrinfo函数将返回一个错误码。应用程序可以通过检查返回值来判断是否出现了错误,并根据需要进行相应的处理。

综上所述,getaddrinfo函数的原理是通过DNS进行主机名解析,并返回一个addrinfo结构的链表。它通过隐藏底层协议的复杂性,使得应用程序可以更加方便地处理网络地址和端口的转换。

getaddrinfo函数虽然具有很多优点,但也存在一些缺点。以下是一些可能的缺点:

1. 性能开销:相对于传统的gethostbyname函数,getaddrinfo函数需要进行DNS查询,这会增加一定的性能开销。对于频繁进行地址转换的应用程序,可能会影响性能。

2. 依赖DNS:getaddrinfo函数依赖于DNS进行主机名解析,如果DNS服务器不可用或者网络连接出现问题,可能会导致函数调用失败。这对于需要可靠的网络连接的应用程序可能会造成问题。

3. 参数复杂:getaddrinfo函数的参数相对较多,使用起来可能比传统的gethostbyname函数更复杂。对于不熟悉该函数的应用程序开发者,可能需要花费更多的时间和精力来理解和使用它。

4. IPv4和IPv6的兼容性:虽然getaddrinfo函数可以同时支持IPv4和IPv6,但在处理不同协议的地址时需要进行相应的转换。这可能增加了代码的复杂性和开发难度。

5. 错误处理:虽然getaddrinfo函数在出现错误时会返回一个特定的错误码,但对于某些错误情况可能没有提供足够的上下文信息。这可能使得错误处理变得困难,特别是当错误发生在异步操作中时。

综上所述,虽然getaddrinfo函数具有很多优点,但也存在一些缺点。在使用该函数时,需要权衡其优点和缺点,并根据应用程序的需求进行选择。在一些特定的情况下,可能需要使用其他的网络编程接口或方法来满足需求。

应用场景:

getaddrinfo函数广泛应用于各种需要进行网络连接的场景中,尤其是在处理主机名和服务名到套接字地址的转换时。以下是几个常见的应用场景:

1. 简单的HTTP客户端:可以使用getaddrinfo函数来实现一个简单的HTTP客户端,用于向Web服务器发送HTTP请求。通过将主机名和服务名转换为套接字地址结构,可以方便地建立与远程服务器的连接。

2. DNS查询:在DNS查询过程中,getaddrinfo函数可以用于将域名解析为IP地址。当应用程序需要将主机名转换为IP地址时,可以使用该函数来获取对应的IP地址列表。

3. 网络连接建立:在网络应用程序中,当需要建立与服务器的连接时,可以使用getaddrinfo函数来获取服务器端的IP地址和端口号。然后,使用这些信息来创建套接字并建立连接。

4. 负载均衡和故障转移:通过getaddrinfo函数,可以获取主机名对应的多个IP地址,从而实现负载均衡和故障转移。当某个IP地址出现故障时,可以自动切换到其他可用的IP地址上。

5. 多协议支持:getaddrinfo函数能够处理协议无关的转换,既可用于IPv4也可用于IPv6。在多协议环境下,应用程序可以使用该函数来处理不同协议的网络地址转换。

综上所述,getaddrinfo函数在各种需要进行网络连接的场景中都有广泛的应用,无论是简单的HTTP客户端还是复杂的网络应用程序,都可以通过该函数来方便地处理网络地址和端口的转换。

相关推荐

详解 HTTPS、TLS、SSL、HTTP区别和关系

一、什么是HTTPS、TLS、SSLHTTPS,也称作HTTPoverTLS。TLS的前身是SSL,TLS1.0通常被标示为SSL3.1,TLS1.1为SSL3.2,TLS1.2为SSL...

锐安信SSL证书自动化运维系统:灵活管理SSL/TLS证书全生命周期

点击上方关注“锐成云分销”,云建站解决方案专家!域名、SSL证书、DNS、主机一站选齐在SSL/TLS证书的生命周期管理中,证书的各种操作方式是基础且核心的部分之一,更是保障用户数据传输加密的关键。这...

宝塔免费的 SSL/TLS 证书如何续签

申请之前,请确保域名已解析,如未解析会导致审核失败(包括根域名)宝塔SSL申请的是免费版TrustAsiaDVSSLCA-G5证书,仅支持单个域名申请有效期1年,不支持续签,到期后需要重新申...

HTTPS、HTTP、TLS/SSL工作及握手原理、PKI/CA密钥体系

一、HTTPS与HTTP介绍二、TLS/SSL工作原理三、TSL/SSL握手过程四、HTTPS性能优化五、PKI体系一、HTTPS与HTTP介绍1.Https(SecureHypetextTran...

什么是SSL证书卸载 SSL证书卸载有什么作用

SSL证书是数字证书的一种,安装部署的话可以对网站起到身份验证和数据加密的作用。网站部署SSL证书,相对就必然会有SSL证书卸载,那么SSL证书卸载是什么呢?SSL证书卸载有什么作用?随着SSL通信量...

让SSL/TLS协议流行起来:深度解读SSL/TLS实现1

一前言SSL/TLS协议是网络安全通信的重要基石,本系列将简单介绍SSL/TLS协议,主要关注SSL/TLS协议的安全性,特别是SSL规范的正确实现。本系列的文章大体分为3个部分:SSL/TLS协...

苹果、谷歌、微软等一致同意!SSL/TLS证书最长有效期锐减至47天

快科技4月14日消息,苹果此前向CA/B论坛(负责管理SSL/TLS证书的行业组织)提议,将所有证书有效期缩短至45天。日前CA/B论坛服务器证书工作组投票通过SC-081v3提案,最终决定将SSL/...

Android怎么设置端口转发,将访问本设备的端口转到另外一台设备

一、Android系统怎么设置端口转发,将访问本设备的端口转到另外一台设备?要设置端口转发,您需要先在Android设备上安装一个支持端口转发的应用程序。其中一个常用的应用是"Termux&#...

大神级产品:手机装 Linux 运行 Docker 如此简单

本内容来源于@什么值得买APP,观点仅代表作者本人|作者:灵昱Termux作为一个强大的Android终端模拟器,能够运行多种Linux环境。然而,直接在Termux上运行Docker并不可行,需要...

关于H3C交换机的SSH功能配置方法(华三交换机ssh配置)

对于交换机的初步学习,作为初学者的我,还望诸位不吝赐教。若存在不足之处,烦请大家多提宝贵意见。同样身为初学者的我们,亦可携手共进,相互分享技术经验。一、本地用户配置(核心步骤)1.创建用户并设置密码...

Linux常用操作ssh(linux中的ssh命令)

ssh#p是小写ssh-p22user@hostsftp#连接sftp-P22root@host#将文件上传到服务器上:put[本地文件的地址][服务器上文件存储的位置]#将...

小白心得,如何使用SSH连接飞牛系统(fnos)?

一、背景作为一个刚接触飞牛系统的小白,在研究飞牛os的时候,发现很多功能都需要连接ssh,但是如何使用SSH连接飞牛系统成为入门飞牛os的一道坎。下面以自己的学习经历详细记录下过程吧。二、系统设置1、...

如何在 Windows 11 或 10 上使用 Winget 安装 OpenSSH

SSH(SecureShell)是大多数开发人员和系统管理员用来通过Linux远程连接托管服务器或任何云服务的工具,因为SSH在Linux中是内置的。然而,对于Windows呢?是的...

linux文件之ssh配置文件的含义与作用

ssh远程登录命令是操作系统(包括linux和window系统)下常用的操作命令,可以帮助用户,远程登录服务器系统,查看,操作系统相关信息。linux系统对于ssh命令有专门保存其相关配置的目录和文件...

害怕Linux SSH不安全?这几个小妙招安排上!

ssh是访问远程服务器最常用的方法之一,同时,其也是Linux服务器受到攻击的最常见的原因之一。不过别误会...我们并不是说ssh有什么安全漏洞,相反,它在设计上是一个非常安全的协议。但是安...

取消回复欢迎 发表评论: