确保当前登陆账号为root或是其他管理员账户

cd ~ && mkdir .ssh
#新建.ssh以存放密钥文件
chmod 700 .ssh && cd .ssh
#修改.ssh目录权限为700,并进入目录
ssh-keygen -t rsa -b 4096
#生成一对4096位的私钥与公钥
#Enter file in which to save the key (/root/.ssh/id_rsa):(回车)
#Enter passphrase (empty for no passphrase): (此处可输入你要的密钥密码,也可以不输)
#Enter same passphrase again: (重复一遍上面的密码)
#Your identification has been saved in id_rsa.
#Your public key has been saved in id_rsa.pub.
#-----------
cat id_rsa.pub > authorized_keys && chmod 600 authorized_keys
#把公钥文件复制成authorized_keys文件
cp -n /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
#这步是把原sshd配置备份为.bak,以防修改错误
nano /etc/ssh/sshd_config
#使用编辑器进入ssh的配置文件,调整参数(nano编辑器对小白更友好)
#查找并修改以下参数
#RSAAuthentication yes   -> RSAAuthentication yes
PubkeyAuthentication yes -> PubkeyAuthentication yes   //允许使用公钥验证登录
#找到上面这两个项,把各自行头的#去掉,如果行尾的值是no则改成yes

修改完毕后,退出nano编辑模式,Ctrl + X,按Y保存,再回车Enter确认

systemctl restart sshd
#重启sshd服务,以启用sshd的密钥验证登录方式

!> 以上操作完成后,最好先尝试使用密钥文件(id_rsa)登录,确认无误再修改为仅密钥登录

确认无误后,再重新编辑sshd_config,修改以下配置

PasswordAuthentication yes -> PasswordAuthentication no   //禁止使用密码口令登录
#(把行头#去掉,如果没有就不用管)把yes改成no

修改完毕后,退出nano编辑模式,Ctrl + X,按Y保存,再回车Enter确认

一键修改sshd_config命令

sed -i 's/^#RSAAuthentication.*/RSAAuthentication yes/g' /etc/ssh/sshd_config
sed -i 's/^#PubkeyAuthentication.*/PubkeyAuthentication yes/g' /etc/ssh/sshd_config
sed -i 's/^PasswordAuthentication.*/PasswordAuthentication no/g' /etc/ssh/sshd_config

使用WinSCP之类的文件管理器,通过SFTP协议,输入账号密码登陆上去,链接到"/root/.ssh"目录,把目录内的3个文件全部拖到本地目录。

然后在WinSCP新建一个会话,窗口左下角“工具-运行PuTTYgen”,点击新的窗口的顶栏的“Conversions-Import key”,选择你刚刚保存的id_rsa文件(不带.pub后缀的),点Save private key,保存到你存放密钥的目录,保管好,这将是你唯一的登陆Linux的方式。

使用你的ssh管理软件,修改ssh的连接登录方式,选择 使用密钥验证,然后选择你刚刚保存的private.ppk文件,保存。

尝试一下登陆,如果提示登陆成功,即可以重启sshd服务以执行禁用密码登录、允许使用密钥登陆。

systemctl restart sshd
#重启sshd服务,执行完毕即可使用密钥进行登陆

本教程基于Online.net的€2.99独立服务器,通过 odhcp6 配置 IPv6,并实现可连接。
系统环境:Debian/Ubuntu (经测试官方CentOS7.7系统也可实现)

1. 获取IPv6地址

登录控制台后,打开 https://console.online.net/en/network/
获取IPv6地址页面
图中所需的信息是IPv6 Block和DUID,记录下来下面步骤需要用到
如果你只有一台服务器,那么直接用这第一个地址就可以了;如果有多台就去 Create subnet 新建 IPv6 段了,再用新的地址就可以了。
√> 如果没有IPv6地址,可以在当前页面免费创建

2. 服务器配置IPv6

2.1. 安装所需依赖

根据自己的系统选择相应的命令

apt-get -y install wget cmake make gcc unzip     //Debian、Ubuntu
yum -y install wget cmake make gcc unzip         //CentOS

安装odhcp6

wget https://github.com/sbyx/odhcp6c/archive/master.zip -O odhcp6c.zip
unzip odhcp6c.zip
cd odhcp6c-master
cmake .
make
make install

2.2. 启用IPv6

首先检测IP地址信息

ip addr

检测IP信息
如图,大多数默认情况网卡口是eth0,inet是IPv4地址,inet6是IPv6地址(fe80开头的是本地IPV6单播地址,不影响)。
然后执行

odhcp6c -P 掩码不带斜杠 -c IPv6子网的DUID eth0 -d
ip -6 a a IPv6子网地址 dev eth0          //其中"IPv6地址"要加上如"/48"的掩码位
ip -6 r a IPv6子网地址 dev eth0

大体到这一步就完成了,可以通过 ping6 google.com ,看是否正确响应。

3. 添加自启动(可选)

i> Ubuntu下该步骤仅适用于 18.04 版本之前
执行以下命令,修改rc.local文件

vim /etc/rc.local

在 exit 0 的前面将如下的命令添加进去,保存即可实现开机自启。

odhcp6c -P 掩码不带斜杠 -c IPv6子网的DUID eth0 -d
ip -6 a a IPv6子网地址/56 dev eth0
ip -6 r a IPv6子网地址/56 dev eth0

算法思想----以输入结束标记作为链表创建的结束

1)构造带头结点的空链表
2)读入一个元素的值
3)当读入的元素值不是“输入结束标记”时,循环4)-7),如果是“输入结束标记”时,转步骤8)
4)申请一个新结点
5)将读入的元素值存入新结点的值域
6)将新结点插入在链表中
7)读入下一个元素的值,转步骤3)
8)建立完毕,返回头指针

尾插法建表(向后插入法):

将新结点插到当前单链表的表尾上。
思路:增加一个尾指针p,使之指向当前单链表的表尾。

头插法建表(向前插入法):

从一个空表开始,生成新结点,读入数据
将读入数据存放到新结点的数据域中,然后新结点插入到当前链表的头结点之后。

编制C/C++程序,利用链接存储方式实现下列功能:从键盘输入数据建立一个线性表(整数),并输出该线性表,输入输出要有相应的字幕提示
#include <iostream>
using namespace std;
typedef int ElemType;        //数据元素的类型为ElemType,将ElemType定义为int类型
//单链表结点的类型定义
typedef struct node
{
    ElemType data;
    node *next;
};

node* Create1()            //尾插法创建单链表
{
    ElemType x;
    node * h, *s, *p;
    h = new node;
    h->next = NULL;
    p = h;
    cin >> x;
    while (x != -1)
    {
        s = new node;
        s->data = x;
        p->next = s;
        p = s;
        cin >> x;
    }
    p->next = NULL;
    return h;
}

node* Create2()        //头插法创建单链表
{
    ElemType x;
    node *h, *s;
    h = new node;
    h->next = NULL;
    cin >> x;
    while (x != -1)
    {
        s = new node;
        s->data = x;
        s->next = h->next;
        h->next = s;
        cin >> x;
    }
    return h;
}
void Print(node *head)        //顺序输出单链表
{
    node *p;
    p = head->next;
    while (p != NULL)
    {
        cout << p->data << ",";
        p = p->next;
    }
}

int main()
{
    node *head;        //创建头指针
    cout << "请输入链表的数据,以-1作为结束:\n";
    //head = Create1();
    head = Create2();
    //cout << "这个链表数据为(尾插法):\n";
    cout << "这个链表数据为(头插法):\n";
    Print(head);
    system("pause");
    return 0;
}

线性表的顺序存储结构定义

是指用一组地址连续的存储单元依次存储线性表中的各个元素,使得线性表中在逻辑结构上相邻的数据元素存储在相邻的物理存储单元中。
i> 采用顺序存储结构的线性表通常称为顺序表。

i> 1、当线性表采用顺序存储结构称为顺序表,是用一段地址连续的存储单元依次存储线性表的数据元素,通常用一维数组来实现。
2、顺序表中数据元素之间的逻辑关系是用存储位置表示的,即逻辑上相邻的数据元素,在存储位置上也是相邻,以此来保证元素之间的逻辑关系。

插入操作

指在表的第i (1≤i≤n+1)个位置,插入一个新元素e,使长度为n的线性表 (a1,…,ai-1,ai,…,an) 变成长度为n+1的线性表(a1,…,ai-1,e,ai,…,an)。

删除操作

指将表的第i(1≤i≤n)个元素删去,使长度为n的线性表 (a1,…,ai-1,ai,ai+1,…,an),变成长度为n-1的线性表(a1,…,ai-1, ai+1,…,an)。

编制C/C++程序,利用顺序存储方式实现下列功能:从键盘输入数据建立一个线性表(整数),并输出该线性表;然后根据屏幕提示,进行数据的插入或删除等操作,并在插入或删除数据后输出线性表。
#include <iostream>
using namespace std;

#define MAXSIZE 1000        //根据需要设置为线性表可能达到的最大长度
typedef int ElemType;        //数组元素的类型为ElemType,将ElemType定义为int类型

//顺序表的建立:定义了一个名为SqList的结构体
typedef struct
{
    ElemType *data;        //存储空间的基地址
    int length;            //顺序表的当前长度(实际已经存入的元素个数)
}SqList; 

//顺序表的初始化
void InitList(SqList &L) 
{
    L.data = new ElemType[MAXSIZE];        //构造一个新的顺序表L,并为之分配大小为MAXSIZE的空间
    if (L.data == NULL)
    {
        cout << "存储空间分配失败!\n";
        exit(0);        //存储空间分配失败退出
    }
    L.length = 0;
    cout << "顺序表初始化完成!\n";
}

//通过顺序表读入值的方式,创建顺序表
void Create(SqList &L, int n) 
{
    ElemType e;
    for (int i = 0; i < n; i++) 
    {
        cin >> e;
        L.data[i] = e;
        L.length++;
    }
}

//顺序表插入值
/*在指定位置插入InsList(&L,i,e);                                *
 *要求在表的第i个位置,插入一个值为e的新元素。*/
void Insert(SqList &L, int i, ElemType e)
{
    if ((i < 1) || (i > L.length + 1))
    {
        cout << "插入地址不合法!\n";
        exit(0);
    }
    if (L.length == MAXSIZE)
    {
        cout << "存储空间已满!\n";
        exit(0);
    }
    for (int j = L.length - 1; j >= i - 1; j--)
    {
        L.data[j + 1] = L.data[j];
    }        //以上是从后比较的方法,可以边比较边移动
    L.data[i - 1] = e;
    ++L.length;
}
/*删除数据元素Delete(&L,i)
将顺序表的第i个元素删去*/
void Delete(SqList &L, int i)
{
    if ((i < 1) || (i > L.length))
    {
        cout << "删除地址不合法!\n";
        exit(0);
    }
    for (int j = i; j <= L.length - 1; j++)
    {
        L.data[j - 1] = L.data[j];
    }
    L.length--;
}
/*遍历并输出顺序表Print(L);
按照顺序表中元素的顺序依次输出每个元素的值*/
void Print(SqList L)
{
    if (L.length == 0)
    {
        cout << "线性表长度为0\n";
        exit(0);
    }
    for (int k = 0; k < L.length; k++)
    {
        if (k == L.length - 1)
        {
            cout << L.data[k];
        }
        else
        {
            cout << L.data[k] << ' ';
        }
    }
 }
/*清空顺序表ClearList(L);
清空顺序表:即表示将顺序表设置为长度为0的空表*/
void ClearList(SqList &L)
{
    L.length = 0;
}
/*判断顺序表是否存满IsListEmpty(L)
判断顺序表是都为空:如果空返回1,否则返回0*/
int IsListEmpty(SqList L)
{
    if (L.length == 0)
        return 1;
    else
        return 0;
}
/*求顺序表的长度ListLength(L)
要求返回线性表L的长度*/
int ListLength(SqList L)
{
    return L.length;
}
/*按序号查找GetData(L,I,e)
要求查找线性表L中第i个数据元素*/
void GetData(SqList L, int i, ElemType &e)
{
    if ((i < 1) || (i > L.length))
    {
        cout << "删除地址不合法!\n";
        exit(0);
    }
    e = L.data[i - 1];
}
/*按值查找Locate(L,e)
要求查找线性表中与给定值e相等的数据元素,
若在表L中找到与e相等的元素,则返回该元素在顺序表中的序号;
若找不到,则返回一个“空序号“,如'0'                                        */
int Locate(SqList L, ElemType e)
{
    int i = 1;
    while ((i <= L.length) && (L.data[i - 1] != e))
        i++;
    if (i <= L.length)        //找到,返回位序i+1
        return i;
    else
        return 0;        //未找到,返回位序0
}
int main()
{
    int n, i;
    ElemType e;
    cout << "请输入线性表的整数个数n:";
    cin >> n;
    SqList L;        //给线性表分配内存空间
    InitList(L);        //顺序表的初始化
    cout << "请输入线性表的各个元素:";
    Create(L, n);        //通过顺序表读入值的方式,创建顺序表
    cout << "原线性表如下:\n";
    Print(L);        //输出顺序表
    cout << "\n请输入要插入的元素及其所要插入的位置:";
    cin >> e >> i;
    Insert(L, i, e);
    cout << "插入之后的数组:\n";
    Print(L);
    cout << "\n请输入要删除的元素的位置:";
    cin >> i;
    Delete(L, i);
    cout << "删除之后的数组:\n";
    Print(L);
    cout << "\n请输入要查找的位置:";
    cin >> i;
    GetData(L, i, e);
    cout << "该值是:" << e;
    cout << "\n请输入要查找的值:";
    cin >> e;
    i = Locate(L, e);
    cout << "该值所在的位置是:" << i;
    system("pause");
    return 0;
}

DNSPod 今天15周年活动,发放一些优惠券,被loc论坛大佬开发出了以下比较划算的使用方法

本次优惠券优惠仅限于 注册6-9位数字的.xyz后缀域名

10年域名23元(不过好看点的数字几乎没剩多少了)

i> 本次活动不限新老用户 !

i> 腾讯云新客户还可以无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得:https://url.cn/5QtnQgB

1. 领取优惠券

地址:https://url.cn/5vcQRXS

 上面一张 -6的注册券,划到页面下面有20-10的续费券5张(领完刷新一下页面继续领,一共5张)

地址:https://www.dnspod.cn/promo/domainscarnival?source=newDNSPod&from=index_Banner#anch_getVoucher

 有一张-5的续费券,点一下分享按钮,然后关掉分享界面(不用真的分享)点一键领取就可以了

2. 注册域名

!> 有个坑的地方,一共三个入口,只有常规入口可以注册,其他的如果搜索,会提示被注册,比如全民大普惠,然后你再返回常规入口也会提示被注册了,所以一定要从常规入口进入,搜索到了马上注册,否则第二遍搜索就是被注册了。

i> 通过这个入口注册域名:https://dnspod.cloud.tencent.com/

先选好要注册的数字xyz,注册1年,用-6券,等于0元1年

在域名控制台续费,选择4年,用20-10券,等于11元4年

重复上面步骤,续费4年,用20-10券,等于11元4年

最后续费1年,用 -5券,等于1元1年

总花费23元,10年域名到手

(备注:连续续费时,中间最好间隔1分钟,不然会订单冲突)

√> 注册完了别忘了抽奖一下,有人抽到-200无门槛代金券的,有抽到-10代金券的

最后还剩 3张 20-10 的代金券,随意使用。

领券页面其实还有张40-20的券,注册/续费com都可以用,有需要的可以看看

!> Q: 为什么我续费显示是69/年
A:请先看下你买的是不是 6-9数字 的xyz

!> Q:为什么这么便宜
A:注册局这么定价的~ 其他商家也是这个价(6-9数字xyz,阿里云6块/年,西部7块/年...

!> Q:显示是溢价域名有什么问题吗
A:没问题,所有的6-9数字xyz都显示是溢价。不是真的溢价,只是标明和普通的xyz有区别,
普通xyz 69/年,这个溢价 -63元

!> Q:xyz域名要北岸才能用吗
A:不用北岸,要实名

!> Q:为什么我注册不了,提示溢价域名暂不支持注册
A:要通过这个入口注册域名 https://dnspod.cloud.tencent.com