linux下到最底

2017-12-20 17:34:47 qq_22075041 阅读数 243802
  • Linux根目录和常见目录

    区块链游戏开发的入门深入了解 学到linux命令行;EOS环境安装;C++;HTML;CSS;JavaScript;React;Redux等知识。

    13人学习 张云波
    免费试看

安装Erlang

由于RabbitMQ依赖Erlang, 所以需要先安装Erlang。

Erlang的安装方式大概有两种:

  1. 从Erlang Solution安装(此方式安装的erlang版本较高,和下文教程中rabbitMQ的版本不一致,建议安装高版本的rabbitMQ

     # 添加erlang solutions源
     $ wget https://packages.erlang-solutions.com/erlang-solutions-1.0-1.noarch.rpm
     $ sudo rpm -Uvh erlang-solutions-1.0-1.noarch.rpm
     
     $ sudo yum install erlang
    
  2. 从EPEL源安装(此方式安装的Erlang版本可能不是最新的,有时候不能满足RabbitMQ需要的最低版本)

     # 启动EPEL源
     $ sudo yum install epel-release 
     # 安装erlang
     $ sudo yum install erlang  

 

安装RabbitMQ

先下载rpm:

wget http://www.rabbitmq.com/releases/rabbitmq-server/v3.6.6/rabbitmq-server-3.6.6-1.el7.noarch.rpm

下载完成后安装:

yum install rabbitmq-server-3.6.6-1.el7.noarch.rpm 

安装时如果遇到下面的依赖错误

Error: Package: socat-1.7.2.3-1.el6.x86_64 (epel)
       Requires: libreadline.so.5()(64bit)

可以尝试先执行

$ sudo yum install socat

关于RabbitMQ的一些基本操作

$ sudo chkconfig rabbitmq-server on  # 添加开机启动RabbitMQ服务
$ sudo /sbin/service rabbitmq-server start # 启动服务
$ sudo /sbin/service rabbitmq-server status  # 查看服务状态
$ sudo /sbin/service rabbitmq-server stop   # 停止服务

# 查看当前所有用户
$ sudo rabbitmqctl list_users

# 查看默认guest用户的权限
$ sudo rabbitmqctl list_user_permissions guest

# 由于RabbitMQ默认的账号用户名和密码都是guest。为了安全起见, 先删掉默认用户
$ sudo rabbitmqctl delete_user guest

# 添加新用户
$ sudo rabbitmqctl add_user username password

# 设置用户tag
$ sudo rabbitmqctl set_user_tags username administrator

# 赋予用户默认vhost的全部操作权限
$ sudo rabbitmqctl set_permissions -p / username ".*" ".*" ".*"

# 查看用户的权限
$ sudo rabbitmqctl list_user_permissions username

更多关于rabbitmqctl的使用,可以参考帮助手册

开启web管理接口

如果只从命令行操作RabbitMQ,多少有点不方便。幸好RabbitMQ自带了web管理界面,只需要启动插件便可以使用。

$ sudo rabbitmq-plugins enable rabbitmq_management

然后通过浏览器访问

http://localhost:15672

输入用户名和密码访问web管理界面了。

配置RabbitMQ

关于RabbitMQ的配置,可以下载RabbitMQ的配置文件模板/etc/rabbitmq/rabbitmq.config, 然后按照需求更改即可。
关于每个配置项的具体作用,可以参考官方文档
更新配置后,别忘了重启服务哦!

开启用户远程访问

默认情况下,RabbitMQ的默认的guest用户只允许本机访问, 如果想让guest用户能够远程访问的话,只需要将配置文件中的loopback_users列表置为空即可,如下:

{loopback_users, []}

另外关于新添加的用户,直接就可以从远程访问的,如果想让新添加的用户只能本地访问,可以将用户名添加到上面的列表, 如只允许admin用户本机访问。

{loopback_users, ["admin"]}

更新配置后,别忘了重启服务哦!

 sudo /sbin/service rabbitmq-server status  # 查看服务状态

 

这里可以看到log文件的位置,转到文件位置,打开文件:

这里显示的是没有找到配置文件,我们可以自己创建这个文件

cd /etc/rabbitmq/
vi rabbitmq.config

编辑内容如下:

[{rabbit, [{loopback_users, []}]}].

这里的意思是开放使用,rabbitmq默认创建的用户guest,密码也是guest,这个用户默认只能是本机访问,localhost或者127.0.0.1,从外部访问需要添加上面的配置。

保存配置后重启服务:

service rabbitmq-server stop
service rabbitmq-server start

此时就可以从外部访问了,但此时再看log文件,发现内容还是原来的,还是显示没有找到配置文件,可以手动删除这个文件再重启服务,不过这不影响使用

rm rabbit\@mythsky.log 
service rabbitmq-server stop
service rabbitmq-server start

注意:记得要开放5672和15672端口

/sbin/iptables -I INPUT -p tcp --dport 5672 -j ACCEPT
/sbin/iptables -I INPUT -p tcp --dport 15672 -j ACCEPT

 

 

 

2015-10-28 22:11:20 ccy950903 阅读数 5694
  • Linux根目录和常见目录

    区块链游戏开发的入门深入了解 学到linux命令行;EOS环境安装;C++;HTML;CSS;JavaScript;React;Redux等知识。

    13人学习 张云波
    免费试看

自己也是刚学习kettle不久,还没有精通,以下是我linux下部署kettle的学习笔记和心得,接下来就让我们开始吧!

一、首先先看一下允许kettle的最低版本的JDK,编辑查看spoon.bat可以看到


可以看出,最低版本是1.6的JDK,所以安装的JDK版本应该在1.6之上

二、登录linux(直接在root用户下操作即可)

1、  安装JDK(这里就不多说关于安装java的命令了)(我的是1.7的JDK)

确保自己的linux系统下已安装了JDK,因为kettle试运行在java环境下。

如果不确定的话,使用命令:java –version 验证一下

如果出现如上图所示的提示,说明安装JDK完成

三、上传文件,开始部署

1.    data-integration.zip上传到linux服务器

2. 使用unzip命令解压data-integration.zip   unzip data-integration.zip-d "/usr/local"(如果上传的是文件夹,忽略此步骤)

3. 进入解压目录,找到./kitchen.sh


4.键入./kitchen.s看输出信息

会看到BASH/ kitchen.sh的:权限被拒绝,所以得知,kitchen.sh缺少执行权限

所以,我们赋予.sh文件以执行权限(x

命令为:chmod +x *.sh

可以看见


所以如上图,说明赋值完成!

再次键入./kitchen.sh,回车,等待信息


如果出现上图,则说明部署成功!!

一、调出spoon界面

如果是在远程连接上会出现报错,这里使用图形界面的服务

1、执行 xhost +(xhost+是使所有用户都能访问Xserver.)

2、在data-integration执行./spoon.sh


出现以上信息,说明环境有错误!

3、修改./kettle文件(位于C:\Users\lenovo目录下)

修改其中的.spoonrc文件,如下:


将Y换为N,保存,然后将其放在根目录即(~)下

(一般情况下在winscp下传到 ~ 目录下是不可得的)

我的做法是:

先把./kettle文件复制到/usr/local目录下,然后再把./kettle文件复制到根目录(~)下

命令(在/usr/local目录下):cp  –r  .kettle  ~(因为.kettle是一个文件,其还包含着其他的文件,所以要用-r)


然后在根目录下查询就可以看见.kettle文件了


再次执行 ./spoon.sh 就可以进入kettle的图形界面了!



出现图形界面,说明spoon调出成功!!!接下来就可以在linux下玩转kettle啦!





2016-06-06 21:49:10 loryliu 阅读数 12725
  • Linux根目录和常见目录

    区块链游戏开发的入门深入了解 学到linux命令行;EOS环境安装;C++;HTML;CSS;JavaScript;React;Redux等知识。

    13人学习 张云波
    免费试看

Linux 命令less 技巧 从文件底部往上看

对于一些很大的log文件,我们用more查看时会很费劲,没有办法直接跳到末尾再向前查看。 
我们可以用less来解决,less查看一个文件时,可以使用类似vi的command命令,在command模式下按G跳到文件末尾,再使用f或B来翻页

less filename 
:G 跳到底部,就可以用 向上 向下 箭头 或 向滚动鼠标来查看log了


2018-07-13 18:13:49 qq_38410730 阅读数 8864
  • Linux根目录和常见目录

    区块链游戏开发的入门深入了解 学到linux命令行;EOS环境安装;C++;HTML;CSS;JavaScript;React;Redux等知识。

    13人学习 张云波
    免费试看

Linux系统简介

Linux系统的结构及特点

Linux系统的结构图如下图所示:

从上图可以看出,Linux是一个典型的宏内核(一体化内核)结构。硬件系统上面时硬件抽象层,在硬件抽象层上面时内核服务功能模块,这些模块通过系统调用接口向用户进程提供服务。

  • Linux进程管理的系统调用包括:进程的创建、调度、中止、等待等。
  • Linux支持内存管理控制器MMU,使用虚拟内存管理机制。虚拟内存管理系统调用包括:内存分配、内存回收、请求分页和交换页等。
  • 由于Linux使用了虚拟文件管理系统VFS,从而使它能够支持不同的文件系统。文件管理系统允许用户进程通过一组通用的系统调用(例如:open、close、read、write、chmod等)对不同文件系统中的文件进行访问。

所谓嵌入式Linux,是指对标准Linux经过小型化剪裁处理之后,能够固化在容量只有几KB或者几MB的存储器芯片或者单片机中,适合于特定嵌入式应用场合的专用Linux操作系统。

与其他的操作系统相比,Linux具有以下一系列显著的特点:

  • 模块化程度高:Linux的内核设计非常精巧,分成进程调度、内存管理、进程间通信、虚拟文件系统和网络接口五大部分;其独特的模块机制可根据用户的需要进行裁剪,很适合嵌入式系统的需求;
  • 源码公开;
  • 广泛地硬件支持:Linux能支持x86、ARM、MIPS、ALPHA和PowerPC等多种体系结构的微处理器;
  • 安全性和可靠性好;
  • 具有优秀的开发工具:嵌入式Linux为开发者提供了一套很完整的工具链,能够很方便地实现从操作系统到应用软件的各个级别的调试;
  • 有很好的网络支持和文件系统支持。

但由于Linux不是为实时而设计的,因此这就成了Linux在实时系统中应用的最大遗憾。

Linux的内核版本

Linux的内核版本号的编排规则为“x.yy.zz”,其中:

  • x的取值范围为0-9;
  • yy的取值范围为0-99;
  • zz的取值范围为0-99。

 

Linux系统的嵌入式应用

实现实时Linux的思路

Linux应用于实时应用中时存在如下的一些问题:

  • Linux系统中的调度单位为10ms,所以它不能够提供精确的定时;
  • 当一个进程调用系统调用进入内核态运行时,它是不可被抢占的;
  • Linux内核实现中使用了大量的封中断操作会造成中断的丢失;
  • 由于使用虚拟内存技术,当发生页出错时,需要从硬盘中读取交换数据,但硬盘读写由于存储位置的随机性会导致随机的读写时间,这在某些情况下会影响一些实时任务的截止期限;
  • 虽然Linux进程调度也支持实时优先级,但缺乏有效的实时任务的调度机制和调度算法;
  • 它的网络子系统的协议处理和其它设备的中断处理都没有与它对应的进程的调度关联起来,并且它们自身也没有明确的调度机制。

在解决Linux系统实时性问题的思想方法方面,有如下的四个思路:

  • 提高时钟精度,解决中断和调度延时问题;
  • 解决在Linux内核中不允许调度的问题;
  • 提供对于实时多媒体应用的支持,包括引入新颖的调度算法(网络包调度、进度调度和磁盘调度)
  • 引入新颖的调度框架以及资源管理思想,以更好地支持网络系统中的QoS要求。

UCLinux

UCLinux是一种由Linux内核发展而来的嵌入式Linux版本,是专门没有MMU的微处理器设计的嵌入式Linux操作系统。

UCLinux系统采用romfs文件系统,它是一种相对简单、占用空间较少的文件系统。空间的节约来自两方面:

  • 首先内核支持romfs文件系统比支持Ext2文件系统需要更少的代码;
  • 其次romfs文件系统相对简单,在建立文件系统超级块时需要更少的存储空间。

romfs是只读的文件系统,禁止写操作,因此系统同时需要虚拟盘支持临时文件和数据文件的存储。但是UCLinux对实时性的支持方面并不好。

RT-Linux

为了提高Linux的实时性能,比较引人注意的就是RT-Linux。

RT-Linux的设计思想极为简单有效:单独设计一个剥夺性实时微内核,并由这个内核来管理处理器;所有的实时进程,包括普通Linux都运行在这个微内核之上。也就是说,在RT-Linux中把Linux也看成是与其他实时进程一样的一个进程,但它是一个优先级最低的进程。这样,就可以把实时进程交给微内核管理,而非实时进程交给普通Linux内核处理。

RT-Linux的设计思想及系统结构图,如下图所示:

从图中可以看到,实时进程是由实时微内核RT-Linux来管理的,普通进程是由Linux来管理的,而Linux又是由微内核RT-Linux管理的一个优先级最低的进程。也就是说,Linux也被看成了一个实时进程,只不过其优先级最低,因此其处理器使用权可被所有的实时进程剥夺。

在实现上,RT-Linux的关键技术是通过软件来模拟硬件的中断控制器。这个中断控制器主要有两个作用:

  • 当Linux系统要封锁CPU的中断时时,RT-Linux中的实时子系统会截取到这个请求,把它记录下来,而实际上并不真正封锁硬件中断,这样就避免了由于封中断所造成的系统在一段时间没有响应的情况,此时处理器却可以响应实时中断的,从而提高了实时性;
  • 当有硬件中断到来时,RT-Linux截取该中断,并判断是否有实时子系统中的中断例程来处理、还是传递给普通的Linux内核进行处理。

另外,普通Linux系统中的最小定时精度由系统中的实时时钟的频率决定,一般Linux系统将该时钟设置为每秒来100个时钟中断,所以Linux系统中一般的定时精度为 10ms,即时钟周期是10ms,而RT-Linux采用的是终端计时中断方式。可以根据最近的进程的时间需要,不断地调整定时器的定时间隔,可以提供十几个微秒级的调度粒度。

Kurt-Linux

不同于RT-Linux单独实现一个实时内核的做法,Kurt -Linux是在通用Linux系统的基础上实现的,它也是第一个可以使用普通Linux系统调用的基于Linux的实时系统。

Kurt-Linux将系统分为三种状态:正常态、实时态和混合态,在正常态时它采用普通的Linux的调度策略,在实时态只运行实时任务,在混合态实时和非实时任务都可以执行;实时态可以用于对于实时性要求比较严格的情况。

为了提高Linux系统的实时特性,必须提高系统所支持的时钟精度。但如果仅仅简单地提高时钟频率,会引起调度负载的增加,从而严重降低系统的性能。为了解决这个矛盾,Kurt-Linux采用的提高Linux系统中的时钟精度的方法:它将时钟芯片设置为单次触发状态(One shot mode),即每次给时钟芯片设置一个超时时间,然后到该超时事件发生时在时钟中断处理程序中再次根据需要给时钟芯片设置一个超时时间。它的基本思想是一个精确的定时意味着我们需要时钟中断在我们需要的一个比较精确的时间发生,但并非一定需要系统时钟频率达到此精度。

缺点就是:Kurt-Linux所采用的这种方法需要频繁地对时钟芯片进行编程设置。

RED-Linux

RED-Linux将对实时调度的支持和Linux很好地实现在同一个操作系统内核中。它同时支持三种类型的调度算法,即:Time-Driven、Priority-Dirven、Share-Driven。

为了提高系统的调度粒度,RED-Linux从RT-Linux那儿借鉴了软件模拟中断管理器的机制,并且提高了时钟中断频率。当有硬件中断到来时,RED-Linux的中断模拟程序仅仅是简单地将到来的中断放到一个队列中进行排队,并不执行真正的中断处理程序。

另外为了解决Linux进程在内核态不能被抢占的问题, RED-Linux在Linux内核的很多函数中插入了抢占点原语,使得进程在内核态时,也可以在一定程度上被抢占。通过这种方法提高了内核的实时特性。

RED-Linux的设计目标就是提供一个可以支持各种调度算法的通用的调度框架,该系统给每个任务增加了如下几项属性,并将它们作为进程调度的依据:

  • Priority:作业的优先级;
  • Start-Time:作业的开始时间;
  • Finish-Time:作业的结束时间;
  • Budget:作业在运行期间所要使用的资源的多少;

通过调整这些属性的取值及调度程序按照什么样的优先顺序来使用这些属性值,几乎可以实现所有的调度算法。这样的话,可以将三种不同的调度算法无缝、统一地结合到了一起。

 

Linux中的C语言和汇编语言

Linux中的C语言

在Linux内核中使用的C语言与通常的有所不同,它的编译器为gcc。例如:再定义一个结构体类型的对象时,不像普通C语言那样只使用结构名,而是在结构名前面还要有关键字struct。例如下面的定义:

struct student {
    ...
}

在普通C语言中定义变量的形式为:

student S;

而在gcc的C语言中,上述的定义则为:

struct student S;

Linux中的汇编语言

通常见到或使用的是Intel格式的汇编语言,而gcc采用的是AT&T的汇编格式语言。

基本语法

这两种汇编语言在基本语法的主要有以下几个不同:

  • 寄存器命名原则。在AT&T汇编指令中,在寄存器的名称前面要带有前缀%,例如“%eax”;
  • 源/目的操作数顺序。在AT&T汇编语言数据传输指令中,数据的传递方向与Intel指令的方向相反。例如:Intel指令“mov ebx,eax”在ST&T中为“movl %eax,%ebx”;
  • 常数的格式。在AT&T指令中的常数要带前缀$,例如“movl $_value,%ebx”,在Intel中为“mov eax,_value”;
  • 寄存器间接寻址。在使用寄存器间接寻址方式时,在AT&T指令中使用“()”,而不像Intel汇编那样使用“[]”,例如“(%eax)”。

嵌入C代码中的行内汇编

在行内汇编方面比较简单,一般的格式为asm("statements")。asm与__asm__是完全一样的。如果有多行汇编,则每一行都要加上“\n\t”。例如:

asm("pushl %eax\n\t"
    "movl $0,%eax\n\t"
    "popl %eax");

 

Linux中的链表

Linux链表的设计思想

由于双链表有一个共同的特点,即它们都有两个指针域,分别指向链表的前一个节点和后一个节点。Linux设计者就将这两个指针定义成一个标准的结构,于是,在linux/list.h中定义了一个具有两个指针并叫做list_head的结构:

struct list_head
{
    struct list_head *head, *prev;
}

这样,我们就有了一个空链表,因为Linux用头指针的next是否指向自己来判断链表是否为空:

static inline int list_empty(const struct list_head *head)
{
        return head->next == head;
}

链表头的创建及链表节点的插入

为了使用户可在系统初始化时创建一个链表头,Linux在文件linux/list.h中提供了宏LIST_HEAD()。其定义如下:

#define LIST_HEAD_INIT(name) {&(name),&(name)}
#define LIST_HEAD(name)\
    struct list_head name=LIST_HEAD_INIT(name);

这里理解一下结构体的初始化,例如:

struct student stu = {"张三","男",18} ;

当用LIST_HEAD(student_list)声明一个名为student_list的链表头时,其next和prev指针都将被初始化为指向自身。创建的链表头如下图所示:

除可用LIST_HEAD()宏在初始化时创建一个链表头以外,Linux还提供了另一个可在运行时创建链表头的宏INIT_LIST_HEAD()。在文件linux/list.h中这个宏的定义如下:

#define INIT_LIST_HEAD(ptr) do{\
    (ptr)->next=(ptr); (ptr)->prev=(ptr); \
}while(0)

插入节点

创建了链表头之后,就可在需要时向链表中插入节点了。在链表的头部插入一个节点的函数如下:

static inline void list_add(
    struct list_head *new,            //待插入结点
    struct list_head *head            //链表头
    )
{
    __list_add(new,head,head->next);
}

其中:__list_add()的定义如下:

static inline void __list_add(
    struct list_head *new,                //待插入节点
    struct list_head *prev,                //链表头
    struct list_head *next                //链表头的next
    )
{
    next->prev=new;
    new->next=next;
    new->prev=prev;
    prev->next=new;
}

这个函数的作用是将一个新节点new插入链表的头部。

需要注意的是:

  • 我们看到整个list_add()函数的所以参数都是list_head的类型,不是用户结构(比如:student)类型!我们以前都习惯使用用户结构类型变量作为函数的参数,通过该变量来引用其成员!
  • 在定义的这个链表结构中,head指针实际上是链表尾,head->next才是链表头!或者理解成添加一个节点,是往head的后面添加。

也就是说,双向链表的结构如下:

也可在链表的尾部插入一个节点,该函数的原型如下:

static inline void list_add_tail(struct list_head *new, struct list_head *head);

链表节点宿主结构的访问

之前说到,链表中的节点操作都是按照list_head类型算的,但list_head又是用户结构的成员,所以根据list_head在结构体中的位置可以经过适当的运算,可通过list_head来访问以list_head为成员的用户结构,即其宿主结构。Linux为此提供了一个list_entry()宏:

#define list_entry(ptr,type,member) \
    container_of(ptr,type,member)

在文件linux/kernel.h中定义的container_of()如下:

#define container_of(ptr,type,member) ({\
    const typeof(((type *)0)->member) *_mptr=(ptr);\
    (type *)((char *)_mptr-offsetof(type,member));})

其中,ptr是指向用户结构中list_head成员的指针,也就是它在链表中的地址值;type为用户结构;member为用户结构中list_head成员的变量名。

例如:访问student_list链表中首个student_struct变量,则如此调用:

list_entry(student_list->next,struct student_struct,list);

这里的list正是struct student_struct结构中定义的list_head类型的成员变量名。

这里list_entry的结构:使用了编译器的一个小技巧,即先求得结构体成员在结构体中的偏移量,然后根据成员变量的地址反过来得出宿主结构变量的地址。

container_of()和offsetof()并不仅用于链表操作,这里最有趣的地方是:

((type *)0)->member

将0地址强制转换为type结构的指针,再访问type结构中的member成员。在container_of宏中,它用来给typeof()提供参数,已获得member成员的数据类型;在offsetof()中,这个member成员的地址实际上就是type结构中member成员相对于结构变量的偏移量。其示意图如下所示:

链表的遍历

可使用宏list_of_each()来遍历一个链表。该宏有两个参数:第一个参数用来指向当前项,第二个参数为需要遍历的链表指针。在每次遍历时,第一个参数随着遍历在链表中不断移动,直到每个节点都被访问。

在文件include/linux/list.h中,宏list_for_each()的定义为:

#include list_for_each(pos,head)\
    for(pos=(head)->next;prefetch(pos->next),pos!=(head);\
        pos=pos->next)

实际上它是一个for循环,利用传入的pos作为循环变量,从表头head开始,逐渐往后移动pos,直到又回到head。(prefetch()可不考虑,用于预取,以提供遍历速度)

可以看到list_foe_each()函数的参数有pos变量,是一个list_head类型的变量。所以在使用该宏进行遍历时,首先需要定义一个(struct list_head*)指针变量,然后才能遍历。

绝大多数情况下,遍历链表时都需要获得链表节点数据项,也就是说:list_for_each()和list_entry()总是同时使用。为此,Linux给出了一个list_for_each_entry()宏:

#include list_for_each_entry(pos,head,member)

与list_for_each()不同的是,这里的pos是数据项结构指针类型,不是(struct list_head*)指针变量。

哈希链表

Linux链表设计者认为双头(next、prev)的双链表对于HASH表来说“过于浪费”,因此设计了一套用于HASH表应用的hlist数据结构,它属于单指针表头双循环链表。它的结构如下图所示:

可以看出,哈希链表的表头仅有之个指向首节点的指针,而没有指向尾节点的指针,这样在可能是海量的HASH表中存储的表头就能减少一半的空间消耗。

在文件include/linux/list.h中定义了hlist链表结构如下:

struct  hlist_head{
    struct hlist_node *first;
}
struct  hlist_node {
        struct hlist_node *next,**pprev;
} 

因为表头和节点的数据结构不同,所以插入操作如果发生在表头和首节点之间,以往的方式就行不通了:表头的first指针必须修改指向新插入的节点,切不能使用类似于list_add()这样统一的描述。

为此,hlist节点的prev不再是指向前一个节点的指针,而是指向前一个节点(可能是表头)中的next(对于表头,则是first)指针(struct list_head **pprev),从而在表头插入的操作可以通过一致的“*(node->pprev)”访问和修改前驱节点的next(或first)指针。

这里回答关于hlist的两个问题:

1、Linux 中的hlist和list是不相同的,在list中每个结点都是一样的,不管头结点还是其它结点,使用同一个结构体表示,但是在hlist中,头结点使用的是struct hlist_head来表示的,而对于其它结点使用的是strcuct hlist_node这个数据结果来表示的。还有list是双向循环链表,而hlist不是双向循环链表。因为hlist头结点中没有prev变量。为什么要这样设计呢?

解答:散列表的目的是为了方便快速的查找,所以散列表通常是一个比较大的数组,否则“冲突”的概率会非常大,这样就失去了散列表的意义。如何来做到既能维护一张大表,又能不占用过多的内存呢?此时只能对于哈希表的每个entry(表头结点)它的结构体中只能存放一个指针。这样做的话可以节省一半的指针空间,尤其是在hash bucket很大的情况下。(如果有两个指针域将占用8个字节空间)

2、hlist的结点有两个指针,但是pprev是指针的指针,它指向的是前一个结点的next指针,为什么要采用pprev,二不采用一级指针?

由于hlist不是一个完整的循环链表,在list中,表头和结点是同一个数据结构,直接用prev是ok的。在hlist中,表头中没有prev,只有一个first。

为了能统一地修改表头的first指针,即表头的first指针必须修改指向新插入的结点,hlist就设计了pprev。list结点的pprev不再是指向前一个结点的指针,而是指向前一个节点(可能是表头)中的next(对于表头则是first)指针(这是因为next是一个指针,指向指针的指针,二级指针),从而在表头插入的操作中可以通过一致的node->pprev访问和修改前结点的next(或first)指针;

还解决了数据结构不一致,hlist_node巧妙的将pprev指向上一个节点的next指针的地址,由于hlist_head和hlist_node指向的下一个节点的指针类型相同,就解决了通用性。

关于hlist如果有不太了解的,可以参考文章:Linux内核哈希表分析与应用

 

2011-10-15 14:39:58 bmbm546 阅读数 155722
  • Linux根目录和常见目录

    区块链游戏开发的入门深入了解 学到linux命令行;EOS环境安装;C++;HTML;CSS;JavaScript;React;Redux等知识。

    13人学习 张云波
    免费试看
 

文件夹权限问题

Linux、Fedora、Ubuntu修改文件、文件夹权限的方法差不多。很多人开始接触Linux时都很头痛Linux的文件权限问题。这里告诉大家如何修改Linux文件-文件夹权限。以主文件夹下的一个名为cc的文件夹为例。 下面一步一步介绍如何修改权限: 1.打开终端。输入su(没

 

Linux、Fedora、Ubuntu修改文件、文件夹权限的方法差不多。很多人开始接触Linux时都很头痛Linux的文件权限问题。这里告诉大家如何修改Linux文件-文件夹权限。以主文件夹下的一个名为“cc”的文件夹为例。

下面一步一步介绍如何修改权限:
1.打开终端。输入”su”(没有引号)

2.接下来会要你输入密码,输入你的root密码。

3.假设我的文件夹在主目录里,地址为  /var/home/dengchao/cc  。假设我要修改文件权限为777,则在终端输入  chmod  777 /var/home/userid/cc

文件夹的权限就变为了777。

如果是修改文件夹及子文件夹权限可以用  chmod -R 777 /var/home/userid/cc

具体的权限(例如777的含意等)在下面解释下:
1.777有3位,最高位7是设置文件所有者访问权限,第二位是设置群组访问权限,最低位是设置其他人访问权限。

其中每一位的权限用数字来表示。具体有这些权限:

r(Read,读取,权限值为4):对文件而言,具有读取文件内容的权限;对目录来说,具有浏览目 录的权限。

w(Write,写入,权限值为2):对文件而言,具有新增、修改文件内容的权限;对目录来说,具有删除、移动目录内文件的权限。

x(eXecute,执行,权限值为1):对文件而言,具有执行文件的权限;对目录了来说该用户具有进入目录的权限。

2.首先我们来看如何确定单独一位上的权限数值,例如最高位表示文件所有者权限数值,当数字为7时,7用“rwx”表示–{4(r)+2(w)+1(x)=7}–

又如果数值为6,则用“rw-”表示–{4(r)+2(w)+0(x)=6}–,”-”表示不具备权限,这里表示不具备“执行”权限。

假如我们设定其他用户的访问权限为 “r–”,则数值为4+0+0=4

一开始许多初学者会被搞糊涂,其实很简单,我们将rwx看成二进制数,如果有则用1表示,没有则有0表示,那么rwx则可以表示成为:111

而二进制的111就是7。

3.我们再来看下怎么确定3个数位上的权限。假如我们要给一个文件设置权限,具体权限如下:

文件所有者有“读”、“写”、“执行”权限,群组用户有“读”权限,其他用户有“读”权限,则对应的字母表示为”rwx r– r–“,对应的数字为744

一般都是最高位表示文件所有者权限值,第二位表示群组用户权限,最低位表示其他用户权限。

下面来举些例子熟悉下。

权限

数值

rwx rw- r–

764

rw- r– r–

644

rw- rw- r–

664

具体linux修改文件夹-文件目录权限就是这样设置的了.

chmod用于改变文件或目录的访问权限。用户用它控制文件或目录的访问权限。该命令有两种用法。一种是包含字母和操作符表达式的文字设定法;另一种是包含数字的数字设定法。

1. 文字设定法

语法:chmod [who] [+ | - | =] [mode] 文件名

命令中各选项的含义为:

操作对象who可是下述字母中的任一个或者它们的组合:
  u 表示“用户(user)”,即文件或目录的所有者。
  g 表示“同组(group)用户”,即与文件属主有相同组ID的所有用户。
  o 表示“其他(others)用户”。
  a 表示“所有(all)用户”。它是系统默认值。
操作符号可以是:
  + 添加某个权限。
  - 取消某个权限。
  = 赋予给定权限并取消其他所有权限(如果有的话)。
设置 mode 所表示的权限可用下述字母的任意组合:
  r 可读。
  w 可写。
   x 可执行。
  X 只有目标文件对某些用户是可执行的或该目标文件是目录时才追加x 属性。
  s 在文件执行时把进程的属主或组ID置为该文件的文件属主。
      方式“u+s”设置文件的用户ID位,“g+s”设置组ID位。
  t 保存程序的文本到交换设备上。
  u 与文件属主拥有一样的权限。
  g 与和文件属主同组的用户拥有一样的权限。
  o 与其他用户拥有一样的权限。
文件名:以空格分开的要改变权限的文件列表,支持通配符。

  

在一个命令行中可给出多个权限方式,其间用逗号隔开。例如:

chmod g+r,o+r example  % 使同组和其他用户对文件example 有读权限。

2. 数字设定法

我们必须首先了解用数字表示的属性的含义:0表示没有权限,1表示可执行权限, 2表示可写权限,4表示可读权限,然后将其相加。所以数字属性的格式应为3个从0到7的八进制数,其顺序是(u)(g)(o)。

例如,如果想让某个文件的属主有“读/写”二种权限,需要把4(可读)+2(可写)=6(读/写)。

数字设定法的一般形式为:

语法:chmod [mode] 文件名

指令实例:

chmod a+x sort   
% 即设定文件sort的属性为:
 文件属主(u) 增加执行权限
 与文件属主同组用户(g) 增加执行权限
 其他用户(o) 增加执行权限
 
chmod ug+w,o-x text
% 即设定文件text的属性为:
 文件属主(u) 增加写权限
 与文件属主同组用户(g) 增加写权限
 其他用户(o) 删除执行权限
 
chmod u+s a.out
% 假设执行chmod后a.out的权限为(可以用ls – l a.out命令来看):
 –rws--x--x 1 inin users 7192 Nov 4 14:22 a.out
 并且这个执行文件要用到一个文本文件shiyan1.c,其文件存取权限为“–rw-------”,
  即该文件只有其属主具有读写权限。
   当其他用户执行a.out这个程序时,他的身份因这个程序暂时变成inin(由于chmod
  命令中使用了s选项),所以他就能够读取shiyan1.c这个文件(虽然这个文件被设定为
  其他人不具备任何权限),这就是s的功能。
  因此,在整个系统中特别是root本身,最好不要过多的设置这种类型的文件(除非
  必要)这样可以保障系统的安全,避免因为某些程序的bug而使系统遭到入侵。
 
chmod a–x mm.txt
chmod –x mm.txt
chmod ugo–x mm.txt
% 以上这三个命令都是将文件mm.txt的执行权限删除,它设定的对象为所有使用者。
 
$ chmod 644 mm.txt
% 即设定文件mm.txt的属性为:-rw-r--r--
 文件属主(u)inin 拥有读、写权限
 与文件属主同组人用户(g) 拥有读权限
 其他人(o) 拥有读权限
 
chmod 750 wch.txt
% 即设定wchtxt这个文件的属性为:-rwxr-x---
 文件主本人(u)inin 可读/可写/可执行权
 与文件主同组人(g) 可读/可执行权
 其他人(o) 没有任何权限

 

 

 

 

 

linux下搭建FTP服务器

*************FTP文件说明*********************
本FTP服务器软件包为vsftpd-2.3.4-1.fc14.i686.rpm
FTP客户端软件包为ftp-0.17-51.fc12.i686.rpm
1、vsftpd不再由xinetd控制;
2、FTP使用port 21发起连接,使用port 20进行数据传输;
3、vsftpd配置文件:    /etc/vsftpd/vsftpd.conf         #主配置文件
            /etc/vsftpd/vsftpd/ftpusers     #拒绝该文件中列出的用户登录FTP
            /etc/vsftpd/vsftpd/user_list    #默认同ftpusers相同
4、查看/etc/passwd文件,可以看到FTP默认的共享目录路径为/var/ftp;
5、FTP日志文件:/var/log/xferlog
6、相关软件包:tcp_wrappers、ip_conntrack_ftp、ip_nat_ftp
    (这3个软件包是教材上列出的,我没有测试过其用途,有兴趣的朋友可以研究一下)
7、启动和停止vsftp指令:
#service vsftpd start       //启动vsftpd服务
#service vsftpd stop        //停止vsftpd服务
#service vsftpd restart     //重启vsftpd服务,每次更改FTP相关配置后,一定要用该命令重启vsftpd服务
#chkconfig vsftpd on        //使vsftpd服务开机启动。(可选操作)
8、注意SElinux的安全性质:
一般SElinux是被强行启用的,对许多服务都默认有权限控制,如果在我们对FTP服务器测试时碰到一些莫名奇妙的错误时,可以关闭SElinux,
也可以仅关闭SElinux对FTP服务的保护设置;
#sestatus         //查看当前系统SElinux是否开启
如果开启了,则打开/etc/selinux/config文件,编辑:将SELINUX=enforcing改成SELINUX=disabled,并把SELINUXTYPE=targeted注释掉!

或者#setsebool -P ftpd_disable_trans 1     //仅关闭SELinux对FTP的保护
*************FTP权限需求**********************
a.允许匿名用户登录;
b.允许匿名用户上传和下载资料(拒绝覆盖已有资料);
c.允许本地用户登录;(注意SElinux的影响)
d.FTP共享目录/var/ftp/
e.拒绝匿名用户创建新文件或者文件夹;
f.使登录用户可以下载共享资料
============================================================================

1、查询本机是否已经安装ftp-server和ftp-client;
#rpm -qa vsftpd
#rpm -qa ftp

2、如果没有安装,则下载相应软件包,或者yum在线安装;
#yum install vsftpd     //ftp服务器软件包
#yum install ftp        //ftp客户端软件包

3、编辑/etc/vsftpd/vsftpd.conf
anonymous_enable=YES      //允许匿名用户登录

local_enable=YES          //允许本地用户登录

write_enable=YES          //允许登录到FTP的用户执行写操作

local_umask=022
anon_umask=077            //匿名用户上传的文件权限都会进行umask的计算,变成-rw- --- ---

anon_upload_enable=YES    //允许匿名用户上传文件

xferlog_file=/var/log/vsftpd.log     //FTP服务器日志文件默认路径

ftpd_banner=***********Welcome to My FTP Server***********

4、开启vsftpd服务
#service vsftpd start

5、在FTP共享目录下建立文件夹
#mkdir /var/ftp/pub              //用于存放共享文件资料
#mkdir /var/ftp/incoming         //用于存放匿名用户上传的资料

#ls -l /var/ftp/
drwxr-xr-x. 2 root root 4096  5月  8 14:13 incoming
drwxr-xr-x. 2 root root 4096  5月  8 14:15 pub
//新创建的文件夹默认归属于root用户和用户组,需要更正!

#chown ftp.ftp /var/ftp/incoming       //改为所属用户为ftp,用户组为ftp组
#chown ftp.ftp /var/ftp/pub
#ls -l /var/ftp
drwxr-xr-x. 2 ftp ftp 4096  5月  8 14:13 incoming
drwxr-xr-x. 2 ftp ftp 4096  5月  8 14:15 pub

6、登录到FTP服务器
#ftp 127.0.0.1
Connected to 127.0.0.1 (127.0.0.1).
220 ************Welcome to My FTP Server*************.
Name (127.0.0.1:root): ftp                //这里的登录用户名输入ftp或者anonymous或者本地有效账户名
331 Please specify the password.
Password:                                 //匿名登录时,直接回车
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp>

还有一种方法也可以登录到FTP服务器:打开火狐浏览器,输入ftp://127.0.0.1,即可匿名登录;
7、允许登录用户下载/var/ftp/pub中的文件资料
使用管理员帐号:
#chmod +r /var/ftp/pub/*          //修改pub目录下文件的读权限

Linux 就该这么学

阅读数 18058

Linux系统结构详解

阅读数 90017