精华内容
下载资源
问答
  • ROS命名空间 和 参数加载ROS命名空间参数设置 ROS命名空间 ROS命名空间,在我的理解就是我们在一个范围下(这个范围就是指的是命名空间)建立变量,节点等。这些变量,节点的有效范围就是他所在的命名空间。一般默认...
  • java 命名空间 命名规则
  • 命名空间 列出所有命名空间 hbase> list_namespace 新建命名空间 hbase> create_namespace 'ns1' 删除命名空间 hbase> drop_namespace 'ns1' 该命名空间必须为空,否则系统不让删除。 修改命名空间 hbase> alter...
  • C++命名空间实例解析

    2020-12-31 13:57:40
    每个命名空间是一个作用域,在所有命名空间之外,还存在一个全局命名空间(global namespace),全局命名空间以隐式的方式声明,它并没有名字。在命名空间机制中,原来的全局变量,就是位于全局命名空间中(可以用::...
  • PHP命名空间的使用,PHP命名空间实例 PHP命名空间简单案例,主要在于理解命名空间的使用方法
  • C#类与命名空间

    千次阅读 2021-08-18 23:15:26
    当你对类和命名空间有了初步的认识,你可能就对类和命名空间放置在那有疑问,不必疑惑,它们是放在类库里,类库、顾名思义就是类的仓库了,本篇文章也会介绍如何对项目添加类库的引用,类与类之间一旦互相引用了,...

    前言

    本文章包括这样几个类容,首先是剖析Hello World程序,上篇文章分别用十种技术编写了Hello World程序,其中有简单的也有复杂的,本片文章将剖析其中最简单的,也就是ConsoleApplication,通过剖析这个程序,来让大家对类和命名空间有一个初步的认识,当你对类和命名空间有了初步的认识,你可能就对类和命名空间放置在那有疑问,不必疑惑,它们是放在类库里,类库、顾名思义就是类的仓库了,本篇文章也会介绍如何对项目添加类库的引用,类与类之间一旦互相引用了,它们之间就产生了依赖关系,这个依赖关系在软件质量当中,起着至关重要的作用,因为质量好的软件和质量不好的软件他们之间非常明显的区别就在于依赖关系处理的怎么样,质量好的软件,它的依赖关系一定是非常清晰、好维护的,质量不好的软件,往往都是因为依赖关系不清楚照成的。
    那么,请看正篇吧

    剖析Hello World程序

    类(class)构成程序的主体

    类 (class) 是最基础的 C#
    类型。类是一个数据结构,将状态(字段)和操作(方法和其他函数成员)组合在一个单元中。类为动态创建的类实例 (instance)
    提供了定义,实例也称为对象 (object)。类支持继承 (inheritance) 和多态性 (polymorphism),这是派生类
    (derived class) 可用来扩展和专用化基类 (base class) 的机制。

    上面的文章摘抄自C#语言定义文档,从上面可以看出,C#语言定义文档为了让我们理解类这样一个名词,它后面用了二十个更加摸不着头脑的名词,所以如果我们直接看官方的文档,可能大家会什么都学不到,而且很可能觉得难,就干脆放弃了,前面说过学习应该是由浅入深,由表及里,所以我们不用上面的解释来理解类,当然上面的描述其实很精辟,但是不适合初学者,它更适合的是已经入门了C#的人来看

    至于我们该怎么理解类?初学者只需要记住,类是构成程序的主体,其它的,入门后再说

    名称空间(namespace)以树形结构组织类(和其它类型)

    什么是命名空间呢?比如说我们有一千个类,当你想使用其中一个类的时候,你会发现找起来很麻烦,就好比我们有一千本书,当我们需要看其中一本的时候,你要找就必须一本一本的去找,直到找到这本书为止,非常麻烦。
    名称空间呢就是用来把类当然还有其它的一些类型,用良好的结构组织在一起,这样的一个作用,就好比下面的这个图书馆,图书馆里边的书不是随便放的,他是按照一定逻辑分门别类放置,如果你想找一本书的话,你就看看这本书属于哪一类第几本,就能很轻易的在一堆书山中找到你想找到的书,而且我们在非常多的书的情况下,有些书是同名的,但这些书名字虽然一样,却属于不同的学科,所以说命名空间也能有效的避免同名的类之间命名的冲突
    图书馆的书

    通过一个简单的程序来理解类和命名空间

    光说不练假把式,我们还是通过一个控制台应用程序来理解命名空间和类吧
    在这里插入图片描述
    类在C#程序中,高亮的颜色是水蓝色,比如上面图片上显示的Program,和Console这些都是类的名字,

    这两个类Program这个类是我们自己编写的,这个类就代表着我们写的程序,C#语言是完全面向对象的语言,所以这个程序本身也是一个类,如果你学习过C语言的话你就会知道C语言是没有类的,他的Main方法是不需要包含在类里面的,而C#是完全面向对象的,所以说即便是程序的入口点Main方法也一定得包含在类里面。

    在这下面我们还可以看到Console这个类,Console这个类是微软给我们准备好的,我们可以直接使用其中的方法
    在这里插入图片描述
    简略的认识了一下类之后,咱们再来看一下命名空间,在上图中我们能在引用后面看到一行namespace理解类与命名空间,这句代码的意思是,我们编写的这个Prigram这个类,放在了一个名为“理解类与命名空间“的命名空间里,这个命名空间的名称默认会和我们创建Project的时候的名称是一样的,
      为什么会这样呢?意思是我自己写的类用自己定义的名称空间组织起来,当别人想调用我写的类的时候,他也能很方便的从我写的这个名称空间将类找出来,这是次要的,我们主要要知道的是是代码上面的那一片using
    在这里插入图片描述
    上面那一堆using(引用)的意思是我把名称空间引用到我的程序当中来,这样描述的话可能很不容易理解,那我们上实例

    还记得下面这行代码吗?像控制台打印一行Hello World!
    在这里插入图片描述
    为什么我们能直接使用这个系统为我们写好的类呢?就是因为上面的using,他将包含console这个类的名称空间引入至了我们的程序,
    现在我们将包含Console这个类的名称空间(System)引用注释掉
    在这里插入图片描述

    从图中我们可以看到,当我们将包含Console这个类的命名空间引用注释掉之后,Console这段代码立马就报错了,也不再是水蓝色,而是普通的白色
    我们再看一下他报的什么错
    在这里插入图片描述
    编译器提示你当前上下文不纯在Console,因为我把包含这个类的名称空间给注释掉了,当我再把这个名称空间给解注释了之后,编译器才能从新正确的识别这句代码
    在这里插入图片描述
    那是不是没有using引用名称空间就不能使用哪个名称空间里的类了呢?
    也不是,我们可以直接将名称空间写出来,再点出我们想要使用的它包含的类
    在这里插入图片描述
    但是我们一般不这么写,因为当你需要多次使用这个方法的时候,你就需要每次都打出他的命名空间再点出方法,
    在这里插入图片描述
    这样很繁琐,所以,为了方便,就都是使用using来引入命名空间

    但是还是有一些例外,比如说Path这个方法
    在这里插入图片描述
    我们由上图的代码提示可以知道,Path这个方法来自于System(系统)命名空间下的Windows命名空间下的Shapes(形状)命名空间下的一个类
    光看名字也能大概知道,这是一个系统下的widows里一个画图有关的类,现在不需要知道他能干嘛,只要知道有这么一个类,
    因为在System命名空间下的IO命名空间下也有一个Path类,


    平时如果你只需要单独是使用一个Path类的话没问题,但是当你需要这两个命名空间同时使用,那就会出麻烦了
    因为这个时候你使用的Path编译器不知道你想使用的到底是哪个命名空间下的Path,就会冲突了,
    所以当这种情况下,就需要使用命名空间一个一个点出来你需要使用的类了

    小结

    经过上面的文章,我们已经对类和命名空间有了初步的了解了,那么我们就应该思考一个问题,类和命名空间到底存放在上面地方呢?
    换句话说就是比如说我想看一本书,我知道它在第几排货架上第几列、第几本、书名是什么,但是如果我没有这个图书馆,那我还能找到我要的书吗?那肯定是拿不到的,
    所以这个问题的答案就是,类和命名空间它是放在一个叫做类库的东西里,类库就是类和命名空间的物理基础,如果你没有这个类库的话,你即使是知道这个名称空间和类的话,你也没法用它们,

    类库的引用

    上面我们知道了类库是什么,这里我将展示类库的引用

    我们先来看一个wpf程序,
    在这里插入图片描述
    当我想使用Button这个类的时候可以看到这个类是来自于System这个命名空间的,那我们能在哪里找到这个命名空间的物理呢类库?
    在这里插入图片描述
    我们打开解决方案管理器就可以看到System这个类库,每一个不同类型的项目就是引用了不同的类库,所以说,我们不同的项目模板,实际上就是给我们引用了不同的技术所需要的类库,所以以后当我们在新建其他类型的项目的时候,就应该明白,这些并没有什么神奇的地方,它就是给我们引用了不同的类库,再加载了不同的编辑器而已,下面我将展示一下类库的引用

    DLL引用(黑盒引用)

    NuGet简介

    NuGet 介绍. Nuget是 ASP .NET Gallery 的一员。. NuGet 是免费、开源的包管理开发工具,专注于在 .NET 应用开发过程中,简单地合并第三方的组件库。. 当需要分享开发的工具或是库,需要建立一个Nuget package,然后把这个package放到Nuget的站点。. 如果想要使用别人已经开发好的工具或是库,只需要从站点获得这个package,并且安装到自己的Visual Studio项目或是解决方案里。. NuGet能更方便地把一些dll和文件 (如jquery)添加到项目中,而不需要从文件中复制拷贝。.

    1. 特点:无源代码,需要有使用文档;使用.dll后缀的动态链接库。如果库有错误无法修改
    2. 添加类库依赖:项目——依赖项——添加项目引用
      在这里插入图片描述
    • 浏览——选择类库文件地址(后缀为.dll的文件)
      在这里插入图片描述
    • 添加NuGet类库(网上其他人共享的类库文件)
      在这里插入图片描述

    项目引用(白盒引用)

    特点:有源代码
    创建类项目:
    在这里插入图片描述

    • 编写类库
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace Tools //命名空间可以修改
    {
        public class Calculator //要使用到的类名
        {
            public static double Add(double a,double b)//类下的静态方法
            {
                return (a + b);
            }
            public static double Sub(double a, double b)
            {
                return (a - b);
            }
        }
    }
    
    • 添加依赖关系

    项目——依赖项——添加项目引用——解决方案——选择刚刚创建好的类项目

    在这里插入图片描述
    -引用依赖类
    5.1 在头部添加名称空间
    using Tools;
    5.2 在需要使用的地方
    类名.静态方法名(参数)

    using System;
    using Tools;
    namespace study
    {
        class Program
        {
            static void Main(string[] args)
            {
                Console.WriteLine("Hello World!");
                double result = Calculator.Add(2.3, 4.5);
                Console.WriteLine(result);
            }
        }
    }
    
    
    

    依赖关系

    类或对象之间的耦合关系
    优秀的程序追求“高内聚,低耦合”

    展开全文
  • Django应用命名空间与实例命名空间

    千次阅读 2019-02-13 00:49:23
    一、为什么需要url命名? 因为url是经常变化的。如果在代码中写死可能会经常改代码。给url取个名字,以后使用url的时候就使用他的名字进行反转就可以了,就不需要写死url了。 需求:访问app主页,如果没登录则自动...

    一、为什么需要url命名?

    因为url是经常变化的。如果在代码中写死可能会经常改代码。给url取个名字,以后使用url的时候就使用他的名字进行反转就可以了,就不需要写死url了。

    需求:访问app主页,如果没登录则自动跳转至登录页面,已经登录则留在app主页。

    项目下创建两个app:

    django-admin startapp app01
    django-admin startapp app02
    

    项目的settings.py中添加这两个应用:

    INSTALLED_APPS = [
    	...
        'apps.app01',
        'apps.app02'
    ]
    

    项目的urls.py中添加URL映射:

    from django.urls import path, include
    
    urlpatterns = [
        ...
        path('app01/', include('apps.app01.urls')),
        path('app02/', include('apps.app02.urls')),
    ]
    

    app01和app02分别新建urls.py并配置:

    from django.urls import path
    from . import views
    
    urlpatterns = [
        path('', views.index),
        path('signin/', views.login),
    ]
    

    app01和app02的views.py中:

    # 以下是app01/views.py
    from django.http import HttpResponse
    from django.shortcuts import redirect
    
    
    def index(request):
        username = request.GET.get('username')
        if username:
            return HttpResponse('app01首页')
        else:
            return redirect('./login/')
        
    
    def login(request):
        return HttpResponse('app01登录页面')
    
    # 以下是app02/views.py
    from django.http import HttpResponse
    from django.shortcuts import redirect
    
    
    def index(request):
        username = request.GET.get('username')
        if username:
            return HttpResponse('app02首页')
        else:
            return redirect('./login/')
        
    
    def login(request):
        return HttpResponse('app02登录页面')
    

    启动服务:

    python manage.py runserver
    

    访问 http://127.0.0.1:8000/app01?username='onefine'
    在这里插入图片描述

    访问 http://127.0.0.1:8000/app02?username='onefine'
    在这里插入图片描述

    访问 http://127.0.0.1:8000/app01/
    在这里插入图片描述

    访问 http://127.0.0.1:8000/app02/
    在这里插入图片描述

    一切正常!

    现在有了新的需求:登录时的url由login变为signin。在目前的项目中,更改需要涉及四个文件…额…


    现在采用url命名来防止这种需求。

    二、如何给一个url指定名称?

    path函数中,传递一个name参数就可以指定。

    path('', views.index, name='index')
    

    app01和app02下的urls.py配置:

    urlpatterns = [
        path('', views.index, name="index"),
        path('signin/', views.login, name="login"),
    ]
    

    app01和app02的views.py中:

    # 以下是app01/views.py
    from django.http import HttpResponse
    from django.shortcuts import redirect, reverse
    
    
    def index(request):
        username = request.GET.get('username')
        if username:
            return HttpResponse('app01首页')
        else:
        	# url反转,url重定向
            return redirect(reverse('login'))
    
    
    def login(request):
        return HttpResponse('app01登录页面')
    
    
    # 以下是app02/views.py
    from django.http import HttpResponse
    from django.shortcuts import redirect, reverse
    
    
    def index(request):
        username = request.GET.get('username')
        if username:
            return HttpResponse('app02首页')
        else:
            return redirect(reverse('login'))
    
    
    def login(request):
        return HttpResponse('app02登录页面')
    

    重新启动服务器,输入 http://127.0.0.1:8000/app02
    在这里插入图片描述

    输入 http://127.0.0.1:8000/app01
    在这里插入图片描述

    你没看错,它确实跳转的是app2下面的signin,这是怎么回事呢?


    三、应用(app)命名空间:

    在多个app之间,有可能产生同名的url。这时候为了避免反转url的时候产生混淆,可以使用应用命名空间,来做区分。定义应用命名空间非常简单,只要在appurls.py中定义一个叫做app_name的变量,来指定这个应用的命名空间即可。

    app01下的urls.py配置,app02类似:

    from django.urls import path
    from . import views
    
    # 应用命名空间
    app_name = 'app01'
    
    urlpatterns = [
        path('', views.index, name="index"),
        path('signin/', views.login, name="login"),
    ]
    

    以后在做反转的时候就可以使用应用命名空间:url名称的方式进行反转。

    app01的views.py中,app02类似:

    from django.http import HttpResponse
    from django.shortcuts import redirect, reverse
    
    
    def index(request):
        username = request.GET.get('username')
        if username:
            return HttpResponse('app01首页')
        else:
            return redirect(reverse('app01:login'))
    
    
    def login(request):
        return HttpResponse('app01登录页面')
    

    好了,完美贴合需求。


    四、实例命名空间:

    一个app可以创建多个实例。可以使用多个url映射到同一个app。这就会产生一个问题:以后在做反转的时候,如果使用应用命名空间,那么就会发生混淆。

    项目下urls.py文件:

    urlpatterns = [
        path('app01/', include('apps.app01.urls')),
        path('app02/', include('apps.app02.urls')),
    	
    	# 新添加的
        path('app03/', include('apps.app01.urls')),
    ]
    

    重启服务访问 http://127.0.0.1:8000/app03
    在这里插入图片描述

    还真是脆弱。。。


    为了避免这个问题。我们可以使用实例命名空间。实例命名空间只要在include函数中传递一个namespace变量即可。

    项目下urls.py文件:

    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        # re_path(r'^$', views.index),
    	path('app01/', include('apps.app01.urls', namespace='app01')),
        path('app02/', include('apps.app02.urls', namespace='app02')),
    	
    	# 同一个app下的第二个实例,实例命名空间
        path('app03/', include('apps.app01.urls'), namespace='app03'),
    ]
    

    以后在做反转的时候,就可以根据实例命名空间来指定具体的url。

    app01下的views.py,app02类似:

    from django.http import HttpResponse
    from django.shortcuts import redirect, reverse
    
    
    def index(request):
        username = request.GET.get('username')
        if username:
            return HttpResponse('app01首页')
        else:
        	# 获取当前实例的命名空间
            current_namespace = request.resolver_match.namespace
            return redirect(reverse('%s:login' % current_namespace))
    
    
    def login(request):
        return HttpResponse('app01登录页面')
    
    

    输入http://127.0.0.1:8000/app03/
    在这里插入图片描述

    输入 http://127.0.0.1:8000/app03?username='onefine'

    在这里插入图片描述

    欣慰!

    注意:在使用实例命名空间之前,必须先指定一个应用命名空间——在子url.py中添加app_name变量。

    'Specifying a namespace in include() without providing an app_name ’
    django.core.exceptions.ImproperlyConfigured: Specifying a namespace in include() without providing an app_name is not supported. Set the app_name attribute in the included module, or pass a 2-tuple containing the list of patterns and app_name instead.


    展开全文
  • XML命名空间详解

    千次阅读 2019-08-09 10:26:06
    一、命名空间的意义 XML是一种非常好用的标记语言,它具有极好的可扩展性,因此当我们需要同时访问多份XML文档时,有可能会出现这样一种情况:在同一份XML文档中可能出现多个同名的标签和属性,而这些标签和属性意义...

    一、命名空间的意义
    XML是一种非常好用的标记语言,它具有极好的可扩展性,因此当我们需要同时访问多份XML文档时,有可能会出现这样一种情况:在同一份XML文档中可能出现多个同名的标签和属性,而这些标签和属性意义又是完全不同的,这样如果我们如果不从语法上提供区别,则XML处理器将无法区分它们。

    为了解决这个问题XML提供了命名空间的支持。我们想象这样一个场景,在学校的操场上你喊一句“小明”可能一下子会有好几个小明回应你。那你如果喊3年级2班的小明,那可能只会有你找的那个小明回应你。这里我们指定了一个范围(3年级2班),在这个范围内小明是唯一的。说简单一些,要确定一个人仅有名字是不够的,还必须要有一个确定的范围,这个范围就可以理解为命名空间。

    回到xml中,加入有这样一个文档,文档中需要保存图书的信息,同时有包含作者的详细信息,可以能会是如下一个文档:

    <book>
    <title>西游记</title>
    <author>
    <name>吴承恩</name>
    <title>先生</title>
    </author>
    </book>

    这个文档中book有两个子标签title和author,title表示书名,author表示作者的信息。而author中也有一个title属性,这里title只的是头衔称呼,也就是表示的是称吴承恩为先生,但是这里book中的title和author中的title确是两个完全不同的意思,仅仅靠程序是不能区分开这两个title的区别的。

    二、使用前缀

    解决这个问题最好的方法就是为不同的元素起不同的名字。比如:这里我们可以定一个规则,每一个book下的元素使用一个前缀,而author下的使用另一个前缀,这样我们可以通过不同的前缀来区分不同的标签,如此一来我们的文档会变成这个样子:

    <b:book>
    <b:title>西游记</b:title>
    <a:author>
    <a:name>吴承恩</a:name>
    <a:title>先生</a:title>
    </a:author>
    </b:book>

    这种方式看起来比较难看,但是确实可以达到区分的目的,现在b:title和a:title就是两个不同的标签。

    通过前缀名我们可以很方便的将文档中的标签分成两类a和b,带有前缀a的属于a类型,带有前缀b的属于b类型,这个类就是命名空间,这里你看起来是不是和Java中的包名有着异曲同工的效果呢?

    但是这里还存在一个小问题,这里的命名空间还只是通过名字来区分不同的标签,也就是说命名空间只是为名字进行了一个分类但是名字具体代表了什么意义,它们应该在哪里出现,它并没有一个说明和约束。

    三、为什么XML没有直接使用前缀

    我们上边这个方法可以解决我们所面临的问题,但是XML为什么没有直接采用这种方式呢?因为这种方式存在一个漏洞,我们通过前缀来约束标签名,那么前缀是否有可能重复呢?加入一份有atguigu定义的xml文档,前缀我们设置为a。这里又一份alibaba定义的文档前缀同样为a,那这两份文档是不是就会出现重复的标签呢?所以我们的问题并没有根本解决。

    解决这个问题现在变成了我们需要使用一个唯一的前缀来确保文档中标签的唯一性,那么现实中有哪些东西是唯一的呢?想一下,java中包名采用的是哪种方式?没错!就是uri地址,java中通过将uri地址倒着写来到达区分包的目的,之所以可行就是因为每个公司的uri地址都是唯一的,所以不会出现重复。

    这里我们就可以为我们的标签名使用uri地址作为前缀比如 (http://www.atguigu.com/a)title,采用这种方式很显然出现重复的几率就小多了,但是注意这里的http://www.atguigu.com/a并不是一个真实的地址,它的目的就是一个确保唯一。

    这种方式虽然看着可行但是实际上是不现实的,不讨论xml中可不可以直接在标签中编写uri地址,仅从编写的角度上看我们也不会这个干,这玩意太麻烦了!!!

    四、XML中如何使用命名空间

    XML命名空间为我们提供了一个标准的语法,声明XML名称空间,并为XML文档里的某个元素或熟悉确定命名空间。

    要在文档里使用XML命名空间,元素名就变成了限定名(qualified names 缩写为qName),限定名分成了两部分,一部分就是我们之前使用的元素名;另一部分是命名空间的前缀,它确定了这个名称所在的命名空间。

    <b:book xmlns:b="http://www.atguigu.com/xml/b">

    我们在根标签中添加了一个xmlns:b属性,xmlns代表的是xml namespace,b是我们声明的命名空间,但是b本身并没有意义,可以将它理解为是<u>http://www.atguigu.com/xml/b</u>的一个别名,我们在标签中使用b,就相当于使用这个uri地址。一旦使用了b这个前缀,就代表这个标签是属于<u>http://www.atguigu.com/xml/b</u>这个命名空间下的元素。

    我们还可以在一个文档中定义多个命名空间,如下的语法也是没有问题的:

    <b:book xmlns:b="http://www.atguigu.com/xml/b" 
            xmlns:a="http://www.atguigu.com/xml/a">

    五、默认的命名空间

    这样我们在文档中就可以使用a和b两个前缀来区分不同的命名空间中的标签了。但是实际上咱们所使用的前缀并不友好,为了方便识别在开发中尽量使用便于识别的前缀,比如book,author等。

    采用以上的方式声明命名空间已经可以很好的解决了咱们的问题,但是这种方式显得有一些麻烦,因为每一个标签都需要加上一个前缀,不如直接写标签名来的爽快。所以xml还给我们提供了一种方式可以声明一个默认的命名空间,具体如下:

    <book xmlns="http://www.atguigu.com/xml/b" 
          xmlns:a="http://www.atguigu.com/xml/a">

    上边的xmlns="http://www.atguigu.com/xml/b"并没有指定前缀,那么这种没有指定前缀的命名空间就会作为页面中元素的默认命名空间,除非在标签中使用其他命名空间的前缀,否则解析器都会认为元素是在默认命名空间下存在。

    但是要注意的是一个文档中只能有一个默认的命名空间,如下的语法是错误的:

    <book xmlns="http://www.atguigu.com/xml/b"
          xmlns="http://www.atguigu.com/xml/a">

    这里我们指定了两个命名空间而都没有使用前缀,解析器在解析文档时会不知道使用哪个命名空间,所以在一个文档中只能有一个默认的命名空间,其他命名空间必须使用前缀。

     

    另附一文进一步理解XML/XSD命名空间解析:

    https://www.jianshu.com/p/49d44ffc9f47

    展开全文
  • linux命名空间(namespace)学习(三)

    千次阅读 2018-12-08 11:09:40
    LinuxPID命名空间学习 通过对于前两节的学习我们知道Linux内核使用task_struct结构来表示和管理进程,这个数据结构里面存放了很多有关于PID如何管理的数据,可以这么说,Linux内核所有有关进程管理的数据结构都和此...

    LinuxPID命名空间学习

    通过对于前两节的学习我们知道Linux内核使用task_struct结构来表示和管理进程,这个数据结构里面存放了很多有关于PID如何管理的数据,可以这么说,Linux内核所有有关进程管理的数据结构都和此数据结构有关。该数据结构存放在include/linux/sched.h头文件里,并且这个数据结构比较大,就不一一列举了。实际上一一列举也没有什么意思,因这个数据结构过于庞大导致列举出来连笔者都感到头大----可以举出这么一个例子:这个数据结构占用内核1.7K的空间,可想有多么庞大。但是不需要担心,可以把此数据结构分块划分的话,就简单很多了。话不多说我会根据如下来结构体系来介绍:

     1. 进程类型
     2. PID的命名空间;
     3.管理 PID有关的数据结构
    

    进程类型

    进程如何划分呢?我们可以把进程划分为如下四种类型:

     1.普通PID:
     	这是Linux对于每一个进程都使用的划分,每一个进程都分配给一个PID,每一个PID都对应一个task_struct,每一个task_struct对应着相应的命名空间,和PID类型(先做了解)。
     2.TGID:
     	线程组ID,这个是线程的定义,这个定义在clone时候使用CLONE_THREAD函数调用的时候进行:在一个进程中,如果以CLONE_THREAD标志来调用clone建立的进程就是该进程的一个线程,它们处于一个线程组,该线程组的ID叫做TGID。处于相同的线程组中的所有进程都有相同的TGID;线程组组长的TGID与其PID相同;一个进程没有使用线程,则其TGID与PID也相同。
     3.PGID:
     	另外,独立的进程可以组成进程组(使用setpgrp系统调用),进程组可以简化向所有组内进程发送信号的操作,例如用管道连接的进程处在同一进程组内。进程组ID叫做PGID,进程组内的所有进程都有相同的PGID,等于该组组长的PID。
     4.SID:
     	几个进程组可以合并成一个会话组(使用setsid系统调用),可以用于终端程序设计。会话组中所有进程都有相同的SID。
    

    PID命名空间

    命名空间是为操作系统层面的虚拟化机制提供支撑,目前实现的有六种不同的命名空间,分别为mount命名空间、UTS命名空间、IPC命名空间、用户命名空间、PID命名空间、网络命名空间。命名空间简单来说提供的是对全局资源的一种抽象,将资源放到不同的容器中(不同的命名空间),各容器彼此隔离。命名空间有的还有层次关系,如PID命名空间,图1 为命名空间的层次关系图。

    图1 命名空间的层次关系
    在上图有四个命名空间,一个父命名空间衍生了两个子命名空间,其中的一个子命名空间又衍生了一个子命名空间。以PID命名空间为例,由于各个命名空间彼此隔离,所以每个命名空间都可以有 PID 号为 1 的进程;但又由于命名空间的层次性,父命名空间是知道子命名空间的存在,因此子命名空间要映射到父命名空间中去,因此上图中 level 1 中两个子命名空间的六个进程分别映射到其父命名空间的PID 号5~10。

    命名空间增大了 PID 管理的复杂性,对于某些进程可能有多个PID——在其自身命名空间的PID以及其父命名空间的PID,凡能看到该进程的命名空间都会为其分配一个PID。因此就有:

    全局ID:

    在内核本身和初始命名空间中具有唯一的ID表示唯一的进程。内核中的init进程就是初始命名空间。系统为每一个进程分配了ID号来标示不同的进程,无论是在一级命名空间还是在二级命名空间中的进程,都在初始命名空间进程中都申请了一个ID号用于管理。这样在父命名空间中就可以看到子命名空间中的进程了。
    

    局部ID

    也可以说是子命名空间中看到的ID号,这个ID只能在子命名空间中有用,在父命名空间中没有作用。
    

    进程ID管理数据结构

    Linux 内核在设计管理ID的数据结构时,要充分考虑以下因素:

    1.如何快速地根据进程的 task_struct、ID类型、命名空间找到局部ID
    2.如何快速地根据局部ID、命名空间、ID类型找到对应进程的 task_struct
    3.如何快速地给新进程在可见的命名空间内分配一个唯一的 PID
    如果将所有因素考虑到一起,将会很复杂,下面将会由简到繁设计该结构。
    介绍的结构如下:

     1. 一个PID只对应一个task_struct结构;
     2. 加入TGID/PGID/SID管理的PID管理;
     3. 加入命名空间的PID管理
    

    一个PID对应一个task_struct结构

    如果不考虑一个进程对应的TGID/PGID/SID,也不考虑一个进程对应的命名空间设计,我们可以对于进程的数据结构进行如下设计:
    一个进程对应了一个task_struct结构,其中每一个PID 中的nr表示PID号即为进程号,PID 结构中的pid_chain代表PID散列表的节点。
    进程的设计一

    上述设计核心思想如下:
    1.一个task_struct 中存放着pid_link结构体,指向struct pid结构。
    2.PID结构里面存放着PID 号(即为nr),也存放着指向pid_link的指针和PID散列表的节点的节点。
    3.每一个PID的申请和释放都是通过pid_hash(PID散列表)和pid_map来进行管理的。
    4.对于每一个PID的查找也是通过pid_hash来管理的;
    数据结构如下:

    struct task_struct {
        //...
        struct pid_link pids;
        //...
    };
    
    struct pid_link {
        struct hlist_node node;  
        struct pid *pid;          
    };
    
    struct pid {
        struct hlist_head tasks;        //指回 pid_link 的 node
        int nr;                       //PID
        struct hlist_node pid_chain;    //pid hash 散列表结点
    };
    

    上述两个主要的数据结构还有两个没有介绍:
    pid_hash[]:是PID的hash散列表,用于管理和查找pid结构,主要通过pid号来进行关键索引找到PID结构。然后找到task_struct结构,主要查找有一下四步:

     1. 通过PID号,索引pid_hash[],找到struct pid的pid_chain结构;
     2. 通过pid_chain找到struct pid结构;
     3. struct pid结构中有tasks指向,task_struct->plink.node;
     4. 通过container_of查找到struct task_struct结构;
    

    pid_map:PID位图表示,主要用于申请和释放未使用的PID号,这样不用遍历pid_hash结构也能够找到未使用的PID号。

    加入TGID/PGID/SID管理的PID管理

    加入TGID/PGID/SID管理的PID管理稍微比较复杂一点,在上述基础上我们知道struct pid结构可以索引到task_struct结构,但是如何加入TGID/PGID/SID的管理呢?可以从如下角度考虑下问题:

     1. 如何通过进程本身的task_struct 索引到自身的所属TGID/PGID/SID的struct PID 结构?
     2. 一个线程组或者一个进程组或者一个组里面的线程主ID或者进程组ID或者组ID怎么索引到其下所有的线程,进程,组中所有的进程?
    

    以上两点的解决方案如下图:

    加入TGID/PGID/SID管理的PID管理ruc
    对于上述的两点疑问可以做如下解答:

     1. 在task_struct结构里面增加struct pid_link数组到至少四个,第一个索引自身进程的struct pid结构,第二个索引线程组ID,第三个索引PGID,第四个索引SID。可以通过一次索引查询到自身task_struct的PID,TGID,PGID,SID结构的task_struct结构。
     2. 每一个自身的进程的PID结构把tasks数组增加至至少四个,第一个索引自身的task_struct ,第二个索引以自己为主进程的下面挂载多少个线程的task_struct,第三个索引以自己为主进程下面挂载多少个gid..... 其中hlist_head tasks[index]以struct task_struct->pid_link[index].hlist_node为节点.
    

    数据结构设计如下:

    enum pid_type
    {
        PIDTYPE_PID,
        PIDTYPE_PGID,
        PIDTYPE_SID,
        PIDTYPE_MAX
    };
    
    struct task_struct {
        //...
        pid_t pid;     //PID
        pid_t tgid;    //thread group id
    
        struct task_struct *group_leader;   // threadgroup leader
    
        struct pid_link pids[PIDTYPE_MAX];
    
        //...
    };
    
    struct pid_link {
        struct hlist_node node;  
        struct pid *pid;          
    };
    
    struct pid {
        struct hlist_head tasks[PIDTYPE_MAX];
        int nr;                         //PID
        struct hlist_node pid_chain;    // pid hash 散列表结点
    };
    

    **

    增加PID命名空间的PID表示结构

    **
    再回到PID命名空间的讨论范畴,通过本文中对于PID命名空间的介绍我们知道每一个命名空间中其PID分配是相对独立的,在父命名空间中可以看到子命名空间中的进程,父命名空间中看到的进程号是父命名空间分配的,子命名空间中看到的进程号是子命名空间分配的。
    可能会有一下疑问:

     1. 子命名空间中的进程怎么会索引到父命名空间中?
     2. 子命名空间中怎么会感知父命名空间的存在呢?
     3. 父命名空间如何会知道子命名空间中的进程呢?
     4. 父命名空间中的进程如何给子命名空间中的进程分配PID呢?
    

    为了回答以上问题,我们先从第四个问题开始讨论:
    为了使父命名空间给子命名空间中的进程分配进程号,Linux内核在命名空间设计中把pid_map结构放入到命名空间中结构,这样每一个父命名空间中的结构就能够给子命名空间中的进程分配ID了,如下所示:

    struct pid_namespace {
            struct kref kref;
            struct pidmap pidmap[PIDMAP_ENTRIES];
            int last_pid;
            struct task_struct *child_reaper;
            struct kmem_cache *pid_cachep;
            unsigned int level;
            struct pid_namespace *parent;
    #ifdef CONFIG_PROC_FS
            struct vfsmount *proc_mnt;
    #endif
    #ifdef CONFIG_BSD_PROCESS_ACCT
            struct bsd_acct_struct *bacct;
    #endif
    };
    以上数据结构还回答了我们第二个问题:子命名空间怎么感知父命名空间的存在
    

    父命名空间如何会知道子命名空间中的进程呢?

    我们知道同一个父命名空间中的进程ID和子命名空间中的ID互相不影响,而且敷命名空间的和子命名空间是不相同的,这样我们就可以在设计数据结构的时候把两者设计在一起,只要找到设计的数据结构就可以通过pid_hash得到struct upid结构。
    上面提到的pid_hash索引的功能有所变化,之前提交通过pid_hash表通过PID值可以索引到struct pid结构,但是现在我们通过hash表先索引到struct upid结构,再通过upid结构和namespace的level值所引到pid结构。进一步所引到task_struct结构
    如下所示:

    struct upid {
            /* Try to keep pid_chain in the same cacheline as nr for find_vpid */
            int nr;
            struct pid_namespace *ns;
            struct hlist_node pid_chain;
    };
    

    以下图片会帮助我们回答以上所有问题,举例来说,在level 2 的某个命名空间上新建了一个进程,分配给它的 pid 为45,映射到 level 1 的命名空间,分配给它的 pid 为 134;再映射到 level 0 的命名空间,分配给它的 pid 为289,对于这样的例子,如图4所示为其表示:在这里插入图片描述
    图中关于如果分配唯一的 PID 没有画出,但也是比较简单,与前面两种情形不同的是,这里分配唯一的 PID 是有命名空间的容器的,在PID命名空间内必须唯一,但各个命名空间之间不需要唯一。
    数据结构设计如下:

    struct pid
    {
        unsigned int level;  
        /* lists of tasks that use this pid */
        struct hlist_head tasks[PIDTYPE_MAX];
        struct upid numbers[1];
    };
    
    struct upid {
        int nr;
        struct pid_namespace *ns;
        struct hlist_node pid_chain;
    };
    
    

    以上摘自:https://www.cnblogs.com/hazir/p/linux_kernel_pid.html

    展开全文
  • Namespace 命名空间

    2011-10-25 15:04:28
    Namespace 命名空间Namespace 命名空间Namespace 命名空间Namespace 命名空间Namespace 命名空间
  • PHP命名空间详解

    千次阅读 2019-02-03 11:52:31
    命名空间的定义 PHP 命名空间(namespace)是在PHP 5.3中加入的,对于学过C++的宝宝们,那命名空间就不算什么新事物了。 不过命名空间在PHP当中还是相当重要的。 PHP 命名空间可以解决以下两类问题: 1.用户编写...
  • K8S命名空间

    千次阅读 2020-05-25 22:16:53
    1、简介Kubernetes 支持多个虚拟集群,它们底层依赖于同一个物理集群。这些虚拟集群被称为命名空间。2、如何使用命名空间命名空间适用于存在很多跨多个团队或项目的用户的场景。对于只有...
  • 4 p命名空间和c命名空间在通过构造方法或set方法给bean注入关联项时通常是通过constructor-arg元素和property元素来定义的。在有了p命名空间和c命名空间时我们可以简单的把它们当做bean的一个属性来进行定义。4.1 p...
  • std命名空间

    千次阅读 2019-05-15 19:05:00
    C++ std命名空间 1. 什么是命名空间 在编程语言中,命名空间是一种特殊的作用域,它包含了处于该作用域中的所有标示符,而且其本身也是由标示符表示的。命名空间的使用目的是为了将逻辑相关的标示符限定在一起,...
  • c# 命名空间命名规范 C#命名空间 (C# Namespace ) In C# namespaces are used to group similar type of classes. Two classes with same name in different namespaces never conflict to each other. 在C#中,...
  • Vuex 命名空间 namespaced 介绍

    万次阅读 多人点赞 2019-04-18 21:04:40
    在带命名空间的模块中,如何将action注册为全局actions 两个条件: ①添加 root: true ②并将这个 action 的定义放在函数 handler 中 //storeAction在命名空间moduleA中,但是它是一个全局actions const moduleA = {...
  • linux命名空间(namespace)学习(一)

    千次阅读 2018-12-05 20:42:53
    关于linux命名空间网络上有很多是关于docker 的,也有关于linux的专门的linux的namespace介绍的,没有专门介绍Linux命名空间的应用的。所以我想先介绍一下linux命名空间的应用,然后再介绍linux内核对于命名空间的...
  • 什么是命名空间? 字面意思来理解,命名空间主要有两个点——“名字”和“空间”。通过这两个关键词,我给大家简单描述一下什么是命名空间(看下面↓) 举个例子:有一个学校,世界之大无奇不有,恰恰这个学校就...
  • 超长干货 | Kubernetes命名空间详解

    千次阅读 2019-02-19 02:05:54
    K8s使用命名空间的概念帮助解决集群中在管理对象时的复杂性问题。在本文中,会讨论命名空间的工作原理,介绍常用实例,并分享如何使用命名空间来管理K8s对象。最后,介绍名为projects的Rancher特性是如何构建并扩展...
  • C++中的命名空间及其作用

    千次阅读 多人点赞 2019-04-04 20:38:56
    一、 命名空间是什么? 命名空间是ANSIC++引入的可以由用户命名的作用域,用来处理程序中 常见的同名冲突。 在 C语言中定义了3个层次的作用域,即文件(编译单元)、函数和复合语句。C++又引入了类作用域,类是出现在...
  • 类加载器的命名空间

    万次阅读 2019-08-21 12:21:11
    命名空间是类加载器中一个很重要的概念,对于只要学过java的人都知道java万物皆对象,在java中即使是一个“.class”文件,通过类加载器加载到虚拟机内存,那么在内存中会生成一个对应的Class对象 那么问题又来了,...
  • cxf 命名空间修改

    千次阅读 2019-11-08 15:50:33
     xmlInterceptor 为报文输出过滤器,在过滤器里打印了响应的报文 开发环境和测试环境生成的报文命名空间还是不一致,查资料分析后应该是在测试服务器上配置中jaxws:properties 标签中的配置没有生效(entry 标签...
  • Kubernetes — 基于层级命名空间的多租户隔离

    千次阅读 热门讨论 2020-11-23 00:25:32
    文章目录目录基于命名空间的多用户模型基于层级命名空间的多租户隔离示例 基于命名空间的多用户模型 在单个 Kubernetes Cluster 上安全托管多用户一直是个难题。其中最大的麻烦就是不同的组织会以不同的方式使用 ...
  • C++17之嵌套的命名空间

    千次阅读 2019-09-01 11:39:41
    c++标准委员会于2003年首次提出,最终接受嵌套名称空间的定义如下: ...注意,嵌套不支持内联命名空间。这仅仅是因为内联应用于最后一个名称空间还是应用于所有名称空间并不明显(两者都同样有用)。 这里简单介绍下...
  • 报错:命名空间中不存在类型或命名空间名“ComponentModel“ 原因:目录名中使用了系统关键字System,导致命名空间混乱 解决方案:把目录名由System改名为Sys。同时,如有需要,把相关的文件的命名空间改为Sys,...
  • linux中的网络命名空间的使用

    千次阅读 2018-09-03 22:29:24
    命名空间的使用,类似虚拟化技术,在同一台物理机上,创建的多个命名空间相互独立,各个空间的进程独立运行,互不干扰。 在此作一总结,学习加深理解。 linux命名空间 命名空间(Linux namespace)是linux内核...
  • php的命名空间和自动加载实现

    千次阅读 2018-04-18 20:52:31
    引子 我们先前讲过类的自动加载,然后我就在思索。 我们写代码的时候,每在另一个文件中调用其他类时 我们并没有写spl_autoload_register这个方法啊?那我们时怎么实现的呢?...命名空间简而言之就是一种标...
  • spring各种命名空间实例。以及命名空间下的各元素简介
  • 1. 声明了命名空间之后,下面的const, function, class都会划归到该命名空间。 2. 只有声明过命名空间的PHP 文件才能加载有命名空间的PHP文件。 3. PHP 5.3 及以上才能使用命名空间 名词: 关键字:namespace 用来...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 785,846
精华内容 314,338
关键字:

命名空间