第一次跟风吃火鸡面,我感觉我要羽化而登仙了

这家伙泡完了并拌上酱之后长这个样子:

火鸡面

我为什么要作死去“品尝”它呢?这得怪机房的一个新生头一天晚上在机房吃这玩意,还给我尝了一口(只吃一点点的话味道还是不错的)…嗯…都是你的错,你背了良心债…

毫不夸张,我吃第一个大口的时候就要喷火了,这玩意最初入口的时候味道还不错,但过不上三秒,辣劲就会上来。此后,除了辣味和甜味之外再无其他味道。

如果要我形容“火鸡面”的味道,那我会说:此面辣的生硬,甜的毫无特点,就像辣椒油里加了抹了甜面酱的面条一样。

也是实在搞不懂为什么这么难吃的东西却在学校的超市卖的那么火爆,可能我真的老了吧…

再见,2017

都快2018年了,我为什么感觉08年的北京奥运会仿佛是昨天才开完…

为了迎接新年,我的博客也做了如下变动:

  1. 将网站架构从wordpress迁移到了更加轻量级的typecho上。
  2. 更换了一套小清新模板,使用异步加载技术,以求加快页面展现速度。
  3. web服务器压缩算法从gzip改成了brotli。
  4. web服务器启用了HTTP 2.0协议。
  5. SQL服务器从MySQL 5.7改成了MariaDB 10.1。
  6. 启用谷歌开发的网页优化工具:PageSpeed。
  7. PHP由7.1版本升级为7.2版本。
  8. 启用Redis缓存。

最后,祝愿大家在新的一年中都可以结好运发大财~

C11新增多线程支持库-threads.h参考手册

线程管理

int thrd_create(thrd_t *thr,  thrd_start_t func,  void *arg);

thrd_create创建一个新线程,该线程的工作就是执行func(arg)调用,程序员需要为线程编写一个函数,函数签名为:thrd_start_t ,即int (*)(void*)类型的函数。新创建的线程的标识符存放在thr内。

thrd_t thrd_current(void);

thrd_current函数返回调用线程的标识符。

int thrd_detach(thrd_t thr);

thrd_detach会通知操作系统,当该线程结束时由操作系统负责回收该线程所占用的资源。

int thrd_equal(thrd_t thr0, thrd_t thr1);

thrd_equal用于判断两个线程标识符是否相等(即标识同一线程),thrd_t是标准约定的类型,可能是一个基础类型,也可能会是结构体,开发人员应该使用thrd_equal来判断两者是否相等,不能直接使用==。即便==在某个平台下表现出来是正确的,但它不是标准的做法,也不可跨平台。

void thrd_exit(int res)

thrd_exit函数提早结束当前线程,res为它的退出状态码。这与进程中的exit函数类似。

int thrd_join(thrd_t thr, int *res)

thrd_join将阻塞当前线程,直到线程thr结束时才返回。如果res非空,那么res将保存thr线程的结束状态码。如果某一线程内没有调用thrd_detach函数将自己设置为detach状态,那么当它结束时必须由另外一个线程调用thrd_join函数将它留下的僵死状态变为结束,并回收它所占用的系统资源。

void thrd_sleep(const xtime *xt)

thrd_sleep函数让当前线程中途休眠,直到由xt指定的时间过去后才醒过来。

void thrd_yield(void)

thrd_yield函数让出CPU给其它线程或进程。

互斥对象和函数

threads.h中提供了丰富的互斥对象,用户只需在mtx_init初始化时,指定该互斥对象的类型即可。

int mtx_int(mtx_t  *mtx, int type);

mtx_init函数用于初始化互斥对象,type决定互斥对象的类型,一共有下面6种类型:

  • mtx_plain –简单的,非递归互斥对象
  • mtx_timed –非递归的,支持超时的互斥对象
  • mtx_try –非递归的,支持锁检测的互斥对象
  • mtx_plain | mtx_recursive –简单的,递归互斥对象
  • mtx_timed | mtx_recursive –支持超时的递归互斥对象
  • mtx_try | mtx_recursive –支持锁检测的递归互斥对象
int mtx_lock(mtx_t *mtx)
int mtx_timedlock(mtx_t *mtx, const xtime *xt)
int mtx_trylock(mtx_t *mtx)

mtx_xxxlock函数对mtx互斥对象进行加锁 , 它们会阻塞,直到获取锁,或者xt指定的时间已过去。而trylock版本会进行锁检测,如果该锁已被其它线程占用,那么它马上返回thrd_busy

int mtx_unlock(mtx_t *mtx)

mtx_unlock对互斥对象mtx进行解锁。

条件变量

threads.h通过mtx对象和条件变量来实现wait-notify机制。

int cnd_init(cnd_t *cond)

初始化条件变量,所有条件变量必须初始化后才能使用。

int cnd_wait(cnd_t *cond, mtx_t *mtx)
int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const xtime *xt)

cnd_wait函数自动对mtx互斥对象进行解锁操作,然后阻塞,直到条件变量condcnd_signalcnd_broadcast调用唤醒,当前线程变为非阻塞时,它将在返回之前锁住mtx互斥对象。cnd_timedwait函数与cnd_wait类似,例外之处是当前线程在xt时间点上还未能被唤醒时,它将返回,此时返回值为thrd_timeoutcnd_waitcnd_timedwait函数在被调用前,当前线程必须锁住mtx互斥对象。

int cnd_signal(cnd_t *cond)
int cnd_broadcast(cnd_t *cond)

cnd_broadcast唤醒那些当前已经阻塞在cond条件变量上的所有线程,而cnd_signal只唤醒其中之一。

void cnd_destroy(cnd_t *cond)

销毁条件变量。

初始化函数

试想一下,如何在一个多线程同时执行的环境下来初始化一个变量,即著名的延迟初始化单例模式。你可能会使用DCL技术。但在C11中,你可以直接使用call_once函来实现。

void call_once(once_flag *flag, void (*func)(void))

call_once函数使用flag来保确func只被调用一次。第一个线程使用flag去调用call_once时,函数func会被调用,而接下来的使用相同flag来调用的call_oncefunc均不会再次被调用,以保正func在多线程环境只被调用一次。

线程专有数据(TSD) 和线程局部数据 (TLS)

在多线程开发中,并不是所有的同步都需要加锁的,有时巧妙的数据分解也可减少锁的碰撞。每个线程都拥有自己私有数据,使用它可以减少线程间共享数据之间的同步开销。

如果要将一些遗留代码进行线程化,很多函数都使用了全局变量,而在多线程环下,最好的方法可能是将这些全局量变量换成线程私有的全局变量即可。

TSDTLS就是专门用来处理线程私有数据的。 它的生存周期是整个线程的生存周期,但它在每个线程都有一份拷贝,每个线程只能read-write-update属于自己的那份。如果通过指针方式来read-write-update其它线程的备份,它的行为是未定义的。

TSD可认为线程私有内存下的void *组数,每个数据项的key对应于数组的下标,用于索引功能。当一个新线程创建时,线程的TSD区域将所有key关联的值设置为NULLTSD是通过函数的方式来操作的。C11TSD提供的标准函数如下:

int tss_create(tss_t *key,  tss_dtor_t dtor)
void tss_delete(tss_t key)
void *tss_get(tss_t key)
int tss_set(tss_t key, void *val)

tss_create函数创建一个keydtor为该key将要关联value的析构函数。当线程退出时,会调用dtor函数来释放该key关联的value所占用的资源,当然,如果退出时value值为NULLdtor将不被调用。tss_delete函数删除一个keytss_get/tss_set分别获得或设置该key所关联的value

通过上述TSD来操作线程私有变量的方式,显得相对繁琐; C11提供了TLS方法,可以像一般变量的方式去访问线程私有变量。做法很简单,在声明和定义线程私变量时指定_Thread_local存储修饰符即可,关于_Thread_local,C11 有如下的描述:

  1. 在声明式中,_Thread_local只能单独使用,或者跟staticextern一起使用。
  2. 在某一区快中声明某一对象,如果声明存储修饰符有_Thread_local,那么必须同时有staticextern
  3. 如果_Thread_local出现在一对象的某个声明式中,那么此对象的其余各处声明式都应该有_Thread_local存储修饰符。
  4. 如果某一对象的声明式中出现_Thread_local存储修饰符,那么它有线程储存期。该对象的生命周期为线程的整个执行周期,它在线程出生时创建,并在线程启动时初始化。每个线程均有一份该对象,使用声明时的名字即可引用正在执行当前表达式的线程所关联的那个对象。

TLS方式与传统的全局变量或static变量的使用方式完全一致,不同的是,TLS变量在不同的线程上均有各自的一份。线程访问TLS时不会产生data race,因为不需要任何加锁机制。TLS方式需要编译器的支持,对于任何_Thread_local变量,编译器要将之编译并生成放到各个线程的private memory区域,并且访问这些变量时,都要获得当前线程的信息,从而访问正确的物理对象,当然这一切都是在链接过程早已安排好的。

以下列出本文参考的资料,在此向原作者致敬。

使用C11新增的多线程支持库-threads.h进行多线程编程

2019年12月6日更新

首先要感谢评论区的热心的同学们的提醒,经本人亲自验证:

VS 2019中移除了对threads.h的支持(评论区有同学提到单独安装v140工具集可以实现支持,但是测试发现没有效果),而GCC方面则在最新版中加入了对该头文件的支持。

以下为原文(程序代码部分更新了Linux版Dome)。


导语

threads.h是C11标准新增的多线程支持库,在此之前C语言实现多线程,除了使用系统API外用的最多的就是pthread.h了,threads.h在语法上和pthread.h非常相似。
当然,对于新出的C语言标准,各大编译器厂商并不会马上就支持。就比如说,Linux下主流的C语言编译器————GCC,直到GCC7.2版本都没能支持该库(PS:看到老外网站上说要安装最新版glibc才能获得对该库的支持,然而亲测无卵用)。相反,VS在这方面做的就很不错,VS2017已经可以完美支持该库了,本文也将基于VS2017社区版对该库的使用方法做介绍。

注:本文仅对多线程编程的概念及threads.h库文件的使用方法做简单介绍,并不会详尽介绍该库下的所有函数,如果你需要一个函数功能的参考手册可以参考此篇文章:C11新增多线程支持库-threads.h参考手册

以一个小程序为例子

本程序中使用到的库函数及宏:

  • thrd_t //此宏定义用于存放线程标识符的数据类型
  • thrd_create //此函数用于创建线程
  • thrd_detach //此函数用于通知操作系统,当线程结束时由操作系统负责释放资源
  • thrd_exit //此函数用于结束当前线程

程序功能:

主线程每2秒打印一次“I love ibadboy.net~~~”,共打印10次。子线程每1秒打印一次“He love ibadboy.net!!!”,共打印10次。我们知道,在只有一个主线程的C程序中该功能是无法实现的,因为后一段程序代码必须等待前一段代码执行完毕才可执行。但,在多线程编程中,各个线程可以一起执行(这里涉及到的同步、异步等等的高阶技术就不讨论了)。举个例子:在游戏开发中,如果程序需要实时监控用户键盘的输入,就不能把这段代码放到主线程中,因为这样的话该段代码就会被程序的其他部分阻塞掉而无法做到真正的“实时”,这时就可以利用多线程技术来化解尴尬啦!话不多说,直接上代码!

程序代码Linux版本

#include <stdio.h>
#include <unistd.h>	//包含sleep等函数
#include <stdbool.h>
#include <threads.h>	//包含多线程支持库头文件
#include <stdlib.h>	//包含exit等函数

int thr_fun(void *);

int main(void) {
    thrd_t thr;
    int ret; //保存thrd_create函数的返回值用于判断线程是否创建成功:0为成功,1为失败。
    ret = thrd_create(&thr, thr_fun, NULL); //将thr_fun函数放在一个新的线程中执行
    if (ret != thrd_success) {
        printf("error!!!\n");
        getchar();
        exit(-1);
    }
    ret = thrd_detach(thr); //通知操作系统,该线程结束时由操作系统负责释放资源。
    if (ret != thrd_success) {
        printf("error!!!\n");
        getchar();
        exit(-1);
    }
    for (int i = 0; i < 10; i++) {
        sleep(2);
        printf("I love ibadboy.net~~~\n");
    }
    getchar();
    return 0;
}

int thr_fun(void *argv) {
    int i = 0;
    while (true) {
        i++;
        sleep(1);
        printf("He love ibadboy.net!!!\n");
        if (i == 10) {
            thrd_exit(0);
        }
    }
}

编译命令:

gcc a.c -std=c11 -lpthread

程序代码Windows版本(经测试在VS 2019中已无法编译通过):

#include<stdio.h>
#include<stdbool.h>
#include<thr/threads.h>        //包含多线程支持库头文件
#include<Windows.h>
void thr_fun(void);
int main(void) {
    thrd_t thr;
    int ret;    //保存thrd_create函数的返回值用于判断线程是否创建成功:0为成功,1为失败。
    ret = thrd_create(&thr, thr_fun, NULL);        //将thr_fun函数放在一个新的线程中执行
    if (ret != thrd_success) {
        printf("error!!!\n");
        getchar();
        exit(-1);
    }
    ret = thrd_detach(thr);    //通知操作系统,该线程结束时由操作系统负责释放资源。
    if (ret != thrd_success) {
        printf("error!!!\n");
        getchar();
        exit(-1);
    }
    for (int i = 0; i < 10; i++) {
        Sleep(2000);
        printf("I love ibadboy.net~~~\n");
    }
    getchar();
    return 0;
}
void thr_fun(void) {
    int i = 0;
    while (true) {
        i++;
        Sleep(1000);
        printf("He love ibadboy.net!!!\n");
        if (i == 10) {
            thrd_exit(0);
        }
    }
}

程序输出:

C语言多线程演示小程序的代码输出

程序中用到的库函数介绍:

thrd_create函数用于创建新线程,如果创建成功,该函数会返回thrd_success,否则返回thrd_error

函数原型:

int thrd_create(thrd_t *thr, thrd_start_t func, void *arg);

参数说明:

  • thr:指向放置新线程标识符的内存位置的指针。
  • func:要放在子线程中执行的函数。
  • arg:传递给执行的函数的参数,无参数填NULL。

thrd_detach函数用于通知操作系统,当线程结束后由操作系统负责释放资源,如果成功,则返回thrd_success,否则为thrd_error,如不调用该函数,则线程所使用的资源将在程序全部执行完后才会释放。

函数原型:

int thrd_detach( thrd_t thr );

参数说明:

  • thr:要作用的线程的标识符

thrd_exit函数用于结束当前进程,值得一提的是:使用该函数可以在不影响子进程的情况下结束主进程,而使用exit函数的话结束主进程将会连带结束整个程序。

函数原型:

_Noreturn void thrd_exit( int res );

参数说明:

  • res:要返回的值

结语

看完此篇文章相信你已经对使用threads.h库进行C语言的多线程开发有了初步了解,如果还有什么问题的话欢迎在评论区留言哦~

FTP服务器-vsftpd

前言:

vsftpd是Linux/Unix操作系统上常用的FTP服务器软件,它可以运行在诸如 Linux, BSD, Solaris, HP-UX 以及 IRIX 上面,支持很多其他的FTP 服务器不支持的特征。

vsfptd的配置十分简单,本专题介绍vsfptd的简单配置方法,并交代vsftpd中比较重要的虚拟用户的配置过程。其余小功能的实现可以对照文章列表中的“vsftpd配置文件中常用选项的中文手册”进行查找。

实验环境:

服务器操作系统:CentOS 6.5
所用软件包:vsftpd.x86_64 0:2.2.2-11.el6_4.1
客户机操作系统:Windows 7
FTP客户端:FileZilla

文章列表:

一、CentOS 6下使用vsftpd配置简单FTP服务器
二、为vsftpd配置虚拟用户
三、vsftpd配置文件中常用选项的中文手册

常见问题的解决方案:

一、解决vsftpd虚拟用户和系统用户无法共存的问题
二、解决vsftpd登录时间过长的问题
三、使用匿名用户登录vsftpd服务器时提示:500 OOPS的解决方法
四、vsftpd配置虚拟用户后登录提示530错误的解决方法

Python小程序-迭代输出多层嵌套列表中的每个元素并显示嵌套列表的层次结构

程序代码:

def iteration(list_name,indent = False,level = 0):
    '''此函数的作用是迭代输出一个列表及其中的嵌套列表中的每个元素。
    其包含三个参数,第一个参数是要传入的列表的名称,第二个参数是控
    制是否使用缩进来显示列表中的嵌套的层次结构,第三个参数是控制输
    出时是否首行缩进,其数值就是使用Tab缩进的次数'''
    for i in list_name:
        if isinstance(i,list):
            iteration(i,indent,level + 1) #利用递归函数处理嵌套列表
        else:
            if indent:
                print('\t' * level,end='')
            print(i)
list1=['aa',['bb',['cc',['dd','ee']]],'ff'] #定义一个待处理的多层嵌套列表
iteration(list1,True,0) #调用iteration函数对其处理

程序输出:

aa
    bb
        cc
            dd
            ee
ff

Python的异常处理机制

程序在运行时难免会因为各种“意外因素”或程序本身的逻辑问题导致出错,严重时这将使程序彻底崩溃。解决这些问题常规的思路就是增加大量的逻辑判断语句来消灭种种可能引起问题的“意外因素”,但这无疑会使程序代码变得复杂而庞大,并且十分脆弱。有没有更好的解决办法呢?如果没有的话也不会有你看到的这篇文章了,哈哈哈~

可以在错误(Python中称之为“异常”)产生时捕获异常,并按照给定的异常恢复代码尝试恢复异常。当然,如果你不捕获异常,那么当异常发生时,程序就必死无疑了。

先来看一个小程序。

给出一个文本文件“file.txt”,文件内容如下所示。要求:利用Python字符串的split()方法来分别获取每行字符串中”:”两边的字符,以第一行字符串为例,要求最终输出为此形式:aa said: aaa

aa:aaa
bb:bbb
(ccc)
dd:ddd
ee:eee
ff:fff:fff

编写程序如下。

file_data = open('file.txt','r',encoding='UTF-8')        #打开"file.txt"文件
for i in file_data:                 #利用for循环迭代读取"file.txt"文件的内容
    (a,b) = i.split(':',1)          #利用字符串的split()方法,以":"为切割条件(只切割一次),对每行字符串进行分割操作,最后将生成的列表中的两个元素分别赋值给变量a、b。
    print(a,end = '')               #输出变量a
    print(' said: ',end = '')       #输出字符串" said "
    print(b,end = '')               #输出变量b
file_data.close()                   #关闭文件

看似程序的逻辑上是没有问题的,但是运行后会发现Python的解释器抛出了如下异常。

aa said: aaa               #按照程序中预设的逻辑正确输出了处理后的字符串
bb said: bbb               #正确输出
Traceback (most recent call last):      #抛出了一个Traceback类型的异常!!!
 File "./a.py", line 5, in &lt;module&gt;
 (aa,bb) = i.split(':',1)
ValueError: not enough values to unpack (expected 2, got 1)

上面的异常的内容大致是:没有足够的值来赋给变量,应该有两个值,但现在只有一个。

查看”file.txt”文件的内容,可以发现,第三行的内容是:

(ccc)

这个字符串中没有包含“:”,理所当然的,split()方法并没有将其切割为列表的两个元素,所以在赋值时就产生了错误。

解决这个错误可以用逻辑判断语句来针对特定的场景给出特定的解决方法(预防异常产生),如下:

file_data = open('file','r',encoding='UTF-8')
for i in file_data:
    if not i.find(':') == -1:        #增加一个判断,只有当字符串中包含“:”字符时才执行相关语句。
        (aa,bb) = i.split(':',1)
        print(a,end = '')
        print(' said: ',end = '')
        print(b,end = '')
file_data.close()

这种方法虽然能解决问题,但需要对每一种可能出现的错误情况给出特定的逻辑判断语句及其他程序代码才能避免异常,这样做的弊端是显而易见的,毕竟且不论编写这样的代码有多么繁琐,光是考虑日后维护代码的工作量就已经令人窒息。

下面来看另一种解决方法:利用异常处理来解决此问题(允许异常产生,但会捕获异常并进行修复)。

file_data = open('file','r',encoding='UTF-8')
for i in file_data:
    try:             #捕获异常
        (a,b) = i.split(':',1)
        print(a,end = '')
        print(' said: ',end = '')
        print(b,end = '')
    except:          #给出修复异常的程序代码
        continue     #跳过本次循环
file_data.close()

程序正确执行并给出如下输出:

aa said: aaa
bb said: bbb
dd said: ddd
ee said: eee
ff said: fff:fff

异常处理的工作原理就是像文章开头说的那样,捕获一个异常,然后按照给定的恢复的代码来尝试恢复异常,就这么简单。

上边的例子中,我们捕获了全部的异常,并对所有的异常应用了同一段恢复代码,那该如何针对某一类型的异常执行某一特定的恢复代码呢?

可以这样写,这里只对IOError类型的错误应用恢复代码:

try :
    ...
except IOError:
    ...

以上介绍的就是Python的异常处理机制是简单用法,异常处理的好处就是可以让你能更加专注实现程序本身的功能,而不必费时费力的预先考虑各种可能产生的错误并写出预防错误的相应的逻辑判断及额外代码。

Python利用递归函数迭代输出多层嵌套列表中的每个元素

Python的列表很强大也很灵活,如何运用好列表就是一门大学问啦!在列表中经常见到下面这种形式:

list1=['aa',['bb',['cc',['dd','ee']]],'ff']

如果使用for循环迭代输出列表中的每个元素会得到下面的结果:

>>> list1=['aa',['bb',['cc',['dd','ee']]],'ff']
>>> for i in list1:
...    print(i)
...
aa
['bb', ['cc', ['dd', 'ee']]]
ff

可以看到,列表中嵌套的列表被整个当成一个元素输出了出来,那么该怎样做才能将嵌套的列表中的每个元素单独输出出来呢?

先看一下常规的实现方法——for循环嵌套。

>>> list1=['aa',['bb',['cc',['dd','ee']]],'ff']
>>> for i in list1:
...     if isinstance(i,list):
...         for a in i:
...             print(a)
...     else:
...         print(i)
...
aa
bb
['cc', ['dd', 'ee']]
ff

上面的例子中可以看到,使用for循环嵌套一层之后列表中的第一层嵌套的列表中的每个元素成功被输出出来了,但是第二层、第三层嵌套的列表中的每个元素依旧没有被依次输出。

这时候就需要用到for循环的多层嵌套了,但多层嵌套的for循环不仅写起来繁琐,读起来更要命。有没有其他更好的解决方法呢?当然有的——利用递归函数来轻松实现!

>>> list1=['aa',['bb',['cc',['dd','ee']]],'ff']
>>> def iteration(a):
...     for b in a:
...         if isinstance(b,list):
...             iteration(b)
...         else:
...             print(b)
...
>>> iteration(list1)
aa
bb
cc
dd
ee
ff

根据上面例子的输出可以看到,完美实现了要求的功能。本文仅仅演示下如何利用递归函数来解决此类问题,不对其做详细介绍。

CentOS 7下配置网卡信息

1、编辑网卡配置文件

CentOS 7的网卡命名规则与CentOS 6中的不一样,下面列出CentOS 7中的网卡命名规则,只要了解即可,不必深究。

  • 规则1:如果Firmware或者BIOS提供的设备索引信息可用就用此命名。比如eno1。否则使用规则2
  • 规则2:如果Firmware或Bios的PCI-E扩展插槽可用就用此命名。比如ens1,否则使用规则3
  • 规则3:如果硬件接口的位置信息可用就用此命名。比如enp2s0
  • 规则4:根据MAC地址命名,比如enx7d3e9f。默认不开启。
  • 规则5:上述均不可用时回归传统命名方式
  • 上面的所有命名规则需要依赖于一个安装包:biosdevname

使用vim文本编辑器打开网卡配置文件,

[root@localhost home]# vi /etc/sysconfig/network-scripts/ifcfg-enp0s3

CentOS 7中的网卡配置信息的写法和CentOS 6中的也稍有不同,主要体现在:新加的各个选项后面都要加上一个“0”,不知为何~

以下为网卡完整配置信息,新增及修改内容已着重标记(写配置文件的时候请不要把我加的注释也写上去=_=…)。

TYPE=Ethernet
PROXY_METHOD=none
BROWSER_ONLY=no
BOOTPROTO=static                           //IP获取方式,由原来的dhcp修改为static(手动指定)
DEFROUTE=yes
IPV4_FAILURE_FATAL=no
IPV6INIT=yes
IPV6_AUTOCONF=yes
IPV6_DEFROUTE=yes
IPV6_FAILURE_FATAL=no
IPV6_ADDR_GEN_MODE=stable-privacy
NAME=enp0s3
UUID=a7b862e4-5d61-468e-a6ab-31c7ee01d790
DEVICE=enp0s3
ONBOOT=yes                                //开机时是否启用网卡,由原来的no改为yes
--------------------------------------------------------------------------------------------
                                     以下为添加的配置内容
--------------------------------------------------------------------------------------------
IPADDR0=192.168.162.27                    //配置IP地址,注意IPADDR后面有一个0
NETMASK0=255.255.255.0                    //配置子网掩码,注意NETMASK后面有一个0
GATEWAY0=192.168.162.254                  //配置网关地址,注意GATEWAY后面有一个0
DNS1=114.114.114.114                      //配置首选DNS
DNS2=8.8.8.8                              //配置备用DNS

2、重启网络

[root@localhost ~]# service network restart
Restarting network (via systemctl): [ OK ]

3、验证配置

查看网络配置信息参考此篇文章。

https://www.ibadboy.net/archives/2099.html

验证网路是否连通可以尝试ping一下www.baidu.com。

[root@localhost home]# ping -c 4 www.baidu.com
PING www.a.shifen.com (61.135.169.121) 56(84) bytes of data.
64 bytes from 61.135.169.121 (61.135.169.121): icmp_seq=1 ttl=54 time=19.3 ms
64 bytes from 61.135.169.121 (61.135.169.121): icmp_seq=2 ttl=54 time=19.4 ms
64 bytes from 61.135.169.121 (61.135.169.121): icmp_seq=3 ttl=54 time=19.5 ms
64 bytes from 61.135.169.121 (61.135.169.121): icmp_seq=4 ttl=54 time=19.6 ms
--- www.a.shifen.com ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3033ms
rtt min/avg/max/mdev = 19.396/19.508/19.674/0.107 ms

在局域网下则可以尝试ping一下网关或同网段下的其他计算机,再或者ping自己的本地IP也行。。。

CentOS 7下查看网络配置信息

导语:

本文中介绍在CentOS 7下查看IP、MAC、DNS、网关等常用网络配置信息的方法

查看网卡IP及MAC:

CentOS7中默认不提供ifconfig命令,那么该如何查看网卡信息呢?

可以使用ip addr命令,如下所示:

[root@localhost ~]# ip addr
1: lo: &lt;LOOPBACK,UP,LOWER_UP&gt; mtu 65536 qdisc noqueue state UNKNOWN qlen 1
 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
 inet 127.0.0.1/8 scope host lo
 valid_lft forever preferred_lft forever
 inet6 ::1/128 scope host
 valid_lft forever preferred_lft forever
2: enp0s3: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc pfifo_fast state UP qlen 1000
 link/ether 08:00:27:8d:54:2e brd ff:ff:ff:ff:ff:ff
 inet 192.168.162.27/24 brd 192.168.162.255 scope global enp0s3
 valid_lft forever preferred_lft forever
 inet6 fe80::26dd:b64f:6c1c:508f/64 scope link
 valid_lft forever preferred_lft forever

其中,lo为本地回环网卡,enp0s3为第一块网卡的名称。

每块网卡区域中,link后面跟的是网卡的MAC地址,inet后面跟的是该网卡的IP v4地址,inet6后面跟的是IP v6地址。

查看DNS:

[root@localhost ~]# cat /etc/resolv.conf
# Generated by NetworkManager
nameserver 114.114.114.114
nameserver 8.8.8.8

其中,每个nameserver关键字后面接的都是DNS地址,排在上方的优先级高。

查看网关:

[root@localhost ~]# ip route
default via 192.168.162.254 dev enp0s3 proto static metric 100
192.168.162.0/24 dev enp0s3 proto kernel scope link src 192.168.162.41 metric 100

default via后面接的就是网关地址,其后的dev后面接的是该网关所属的网卡的名称。

Linux下实现在指定目录中遍历所有文件查找指定字符串

要实现此功能只要使用grep命令就好啦,具体可以看下下边这个小例子:

查找/home目录及其子目录中所有包含”hello”字符串的文件,并显示出该字符串在文件中所处的行数。

[root@localhost ~]# grep -nR "hello" /home
/home/a:8:hello,world!
/home/b/a:10:hello,it7e!

grep命令相关参数介绍

  1. -n 是显示行号
  2. -R 查找所有文件包含子目录
  3. -i 忽略大小写

minicom常用组合键介绍

minicom 组合键的用法是:先按Ctrl+A组合键,然后松开这两个键,再按完成特定功能的按键。常用的功能按键如下

  • S键:发送文件到目标系统中;
  • W键:自动卷屏。当显示的内容超过一行之后,自动将后面的内容换行。这个功能在查看内核的启动信息时很有用;
  • C键:清除屏幕的显示内容;
  • B键:浏览Minicom的历史显示;
  • X键:退出Minicom,会提示确认退出。

从新开始,全新启程;潜心修炼,待到来日——再决雌雄!

人生总不可能是完美的,所以每个人都在不完美中努力追求着完美。
但追求的路上从没有一帆风顺,每当遇见坎坷和挫折的时候,就需要静下心来思考自己从这次经历中收获了什么。
一次挫折就是一次成长,不历经挫折磨砺的人怎能在日后的生活中坚强勇敢呢?

今天,全新的站点风格、全新的目标、全新的认知、全新的心情……一切都是新的,从新开始,全新启程。

两年后,在《云计算技术与应用》项目的赛场上,希望我不会再留有遗憾!

未来,我来了!你准备好了吗?

附加信息

旧版站点风格:

2017年11月4日,改版后:

2017年山东省技能大赛《网络搭建与应用》项目落榜原因总结

应信息科科长及我的指导老师的共同要求,在此,我对“2017年山东省技能大赛《网络搭建与应用》项目”未能得奖的原因仅做出个人主观上的总结,并为解决每条“失败原因”给出我个人的建议。

祝愿威海水校在以后的该项目比赛中能取得满意的成绩。

落榜原因:

  1. 备赛时间不足:仅半年备赛时间。而外校则普遍无双休及寒暑假,并至少训练一年以上
  2. 指导教师备赛经验不足:完全无经验,指导教师间不能形成默契的配合,无统一的备赛方案及教学计划,导致训练任务杂碎选手注意力无法集中
  3. 指导教师参赛经验不足:完全无经验,比赛时选住的酒店房间靠近马路,选手晚上无法好好休息
  4. 赛前模拟练习不够:无老师统一组织模拟训练,选手自发组织的能力十分差劲,导致长期“各干各的”最后比赛时配合的一塌糊涂
  5. 缺乏参考资料与训练试题:网络部分参考资料只有产品说明文档,服务器部分参考资料在互联网上现用现查,训练试题全是八九年前甚至十年前的老旧市赛题目
  6. 选手做完的模拟试题无人检查:选手做完题后往往自我感觉良好,实际上会存在很多问题,亟待老师发现并予以更正
  7. 缺乏教师指导且学校不够重视:学校不给予赛项指导教师经济上的奖励与精神上的激励,加之教师日常杂事较多,严重影响指导教师的备赛积极性
  8. 选手个人素质较差(此处不针对个人,是所有选手缺点的总结):仓促应赛,无充足生源供选拔选手。临时选拔的选手学习能力差、自制力差、独立思考的能力差、心理素质差、存在交流障碍
  9. 同批次的“后备小组”严重影响训练:打游戏、喧哗等影响参赛小组备赛
  10. 我个人的心理问题(李海亮老师建议补充):把比赛看得过重,导致赛前一晚外面越吵我越焦躁,难以入眠,很大程度上影响了第二天比赛的发挥

解决以上问题的个人建议:

备赛时间不足

在学生入学的第一学年起即开始选拔参赛选手,按照大赛规定:任意一级学生均可参加大赛,且可跨年级组队。对有能力的学生可以从第一学年入学起就选入技能小组培训一年,第二学年直接参赛,若未得奖,则该生可继续在第三学年参赛,此时获奖几率大大提升。

指导教师备赛及参赛经验不足

这里主要靠指导教师的个人经验积累。

赛前模拟训练不够(此处再次声明:所述建议仅代表个人看法)

基础训练进行一段时间,待两名参赛选手都对各自所负责的部分的知识有了初步认识后,指导教师即可将两名参赛选手放在一起进行试题的模拟训练,通过做正规赛题一点一点磨合知识点及选手间的配合,从而提高答题速度及做题的得分率。

网络部分若按照神州数码官方给出的实验手册一个一个做,愚以为是出力不讨好的事。毕竟基础实验的数量很大,每个实验中包含的知识点又很少很零碎,但完成每个实验均需重新连线及做基础配置,极度浪费时间。不如直接做赛题,在一次基础配置做完后可以很方便的在其上配置各种细节功能,一次生二次熟,每份赛题经过多次的重复做,知识点也就掌握的差不多了。这方面,前期需要指导教师为选手整理出各个赛题的参考答案,以方便选手对知识点的学习,避免选手把时间浪费在“扣题”上。

做题的另一个好处是:每年的市赛及省赛都会有很多往年的原题,除国赛外很少会完全自主出题,其考察的知识点也基本不超出历年国赛的知识范围,能熟练完成14年以后的所有国赛题,且选手间配合无误,至少省赛二等奖。

缺乏参考资料与训练试题

获取赛题及资料有多种途径,这里指导老师与我共同收集了14年至17年共13份国赛赛题(15年十份),其中11份带参考答案;17年两市市赛题,均带参考答案;16年山东省赛题,无参考答案。

注:收集上述赛题时已距比赛开始不满10天,完全无时间练习。
以上所有赛题及参考答案均已上传至网络小组QQ群中。

我的个人网站:https://www.ibadboy.net(百度搜:坏蛋的博客)中也有很多关于大赛中涉及到的各种服务的搭建及问题处理的文章,可供参考。此外,我会将每个服务都单独写成一个专题,专题中集中罗列该服务的各种功能实现的方法及常见问题处理的方法,专题文章列表的URL:https://www.ibadboy.net/archives/category/special

同时,建议水校多与外校交流,可以适当派选手到外校“拉练”,在交流过程中互相学习经验及交换学习资料。

选手做完的模拟试题无人检查

指导教师日常杂事繁重,然而检查试题所用时间却远远超出做一份题所用的时间(测试及论证费时费力)。在学校不给予指导教师“特殊照顾”的情况下教师很难做到选手做一份题就检查一份题。

缺乏教师指导且学校不够重视

涉及学校政策及其他因素,不敢妄议。

选手个人素质较差

增加选拔选手的生源范围,可跨年级,并从所有计算机专业的学生中选拔选手。

按大赛规定:只要选手在同一所学校即可,无论年级与班级,且同一选手只要未在国赛得奖,便可重复参赛。

同批次“后备小组”严重影响训练

建议取消同批次参赛队的“后备小组”。《网络搭建与应用》项目备赛过程枯燥,且难度较大,而中职学生普遍学习能力差且自控能力弱,两个年纪能找到两个合适的人进行组队已实属不易,盲目凑人数最后的结果往往是在没有老师的情况下学生们结伴扯闲话及打游戏,非常影响正常的训练。

这里着重解释下(如果有合适人选):一年级选拔一个选手,二年级选拔一个选手,两个选手同时训练。比赛后,二年级学生已升入三年级,无法再次参加比赛,而一年级选手升入二年级,此时其拥有一次比赛经验,在下次新生入学时可再为其挑选一名合适的队友组队比赛,得奖几率大大提升。

最后,再次祝愿威海水校在日后的该项目比赛中能节节攀升,夺得一等奖!

总结人:威海水校信息科2015级学生——孙锡源

日期:2017年11月2日

个人网站:https://www.ibadboy.net

附件:

2017年山东省技能大赛《网络搭建与应用》项目落榜原因总结