精华内容
下载资源
问答
  • 在二地址指令中_____是正确的
    千次阅读
    2020-01-06 09:56:22

    一、背景说明
    准备在项目中基于nginx搭建一个简易网关,实现同一域名根据不同cookie代理不同docker功能,降低前端、移动端多业务线并行测试联调成本。简单来说就是服务端有多个测试环境docker分别部署不同业务需求代码,通过在前端、移动端种植cookie(存放服务端测试环境docker IP地址)方式让其具有可选择服务端测试环境能力,大大降低联调环境配置成本。具体cookie的解析逻辑在nginx中使用lua实现。

    二、问题说明
    根据相应nginx+lua资料配置后,一切顺利,可正常访问。但是在配合前端、移动端研发人员进行联调时,间接频繁出现请求404情况,同一接口请求参数相同,请求时间段不同,会间接出现404报错情况,在出现404时,nginx中报错信息如下所示:

    2020/01/02 17:16:51 [error] 506478#0: *2183 open() "/export/Instances/Logs/runtime/api/timer/info" failed (2: No such file or directory), client: xx.xx.xx.xx, server: www.timer.com, request: "GET" .......

    从错误信息来看出现404报错时,请求是直接在nginx中找静态文件的反向代理了。我有在lua脚本中打印了执行日志信息,在出现404错误时,lua脚本正常执行成功。由于该问题间接性出现,大大增加了问题排查的难度。

    三、解决方案
    先说解决方案,修改nginx 中lua脚本导入方式,详细如下所示:
    错误方式(会出现404):

    location / {
    	 default_type 'application/json';  
    	 charset utf-8;  
    	 lua_code_cache on;  
    	 access_by_lua_file /export/Instances/timer/runtime/lua/timer.lua;
    }

    正确方式:

    location / {
    	 default_type 'application/json';  
    	 charset utf-8;  
    	 lua_code_cache on;  
    	 content_by_lua_file /export/Instances/timer/runtime/lua/timer.lua;
    }

    access_by_lua:在请求访问阶段处理,用于访问控制,适用于http、server、location、location if
    content_by_lua:是内容处理器,接受请求并输出响应,适用于location、location if
    注:我的解决方案是试出来的,由于access_by_lua 和 content_by_lua 资料相对较少,至于最根本的原因,我还没弄明白

    四、排查与总结笔记
    1、前期考虑是由于配置了 lua_code_cache on ,导致lua脚本被缓存导致的,深入学习了一下,非问题根本原因。
    lua_code_cache :启用或禁用指令中Lua代码的Lua代码缓存。关闭时,ngx_lua提供的每个请求都将在一个单独的Lua VM实例中运行,引用的Lua文件将不被缓存,所有使用的Lua模块都将从头开始加载;开启时,lua脚本会被缓存,需要reload nginx才能让更新后的lua脚本生效

    2、考虑是lua脚本错误导致的,在lua脚本本中打印了诸多日志,最后发现出现404错误时,lua脚本可正常执行,输出日志信息
    记录常用命令:

    ---请求header
    local reqHeaders = ngx.req.get_headers();
    ----请求类型
    local reqType= ngx.var.request_method;
    ---请求cookie
    local reqCookie = reqHeaders["cookie"];
    local pcIp = ngx.var.cookie_pcip;
    local appIp = ngx.var.cookie_appip;
    --请求URL
    local requestUri = ngx.var.request_uri;
    --请求域名地址
    local requestHost = ngx.var.host;

    五、未完待续
    继续查找 access_by_lua  和 content_by_lua 配置的相关资料
    以上问题中lua 返回代码如下所示:

    local timerHttp = require "resty.http"
    ---Post 请求
    local function http_post(url,headerParm,body,timeout)
        local httpc = timerHttp.new();
        timeout = timeout or 30000;
        httpc:set_timeout(timeout);
        local res, err_ = httpc:request_uri(url, {
            method = "POST",
            body = body,
            keepalive=false,
            headers = headerParm;
        })
        httpc:set_keepalive(5000, 100)
        return res,err_;
    end
    
    local reqResult,reqErr = http_post(nowUrl,reqHeaders,reqBody,30000);
    if(reqResult.status==200) then
    	ngx.say(reqResult.body);
    	return ;
    else
    	ngx.say(reqErr);
    	return ;
    end

     

    更多相关内容
  • JSP第版课后习题下载:https://download.csdn.net/download/weixin_42859280/11265785 JSP第版课后习题答案下载:https://download.csdn.net/download/weixin_42859280/11265728 剪切之前的:...

    JSP第二版课后习题下载:https://download.csdn.net/download/weixin_42859280/11265785

    JSP第二版课后习题答案下载:https://download.csdn.net/download/weixin_42859280/11265728

    剪切之前的:https://blog.csdn.net/weixin_42859280/article/details/94355366

     

    习题四【第三版3章】

    一、选择题

    1、在JSP中,要定义一个方法,需要用到以下(   )元素。D

    A.<%=  %>                            B.<%   %>

    C.<%@  %>                           D.<%!  %>

    2、在J2EE中,在一个JSP文件中,有表达式<%=2+3 %>,它将输出( )。 B

    A.2+3                                   B.5                 

    C.2                                 D.不会输出,因为表达式是错误的

    3、在JSP中,(    )动作用于将请求转发给其他JSP页面。  A

    A.forward                           B.include

    C.useBean                           D.setProperty

    4、要设置某个JSP页面为错误处理页面,以下page指令正确的是(  )。  B

    A.<%@ page errorPage="true"%>                     

    B.<%@ page isErrorPage="true"%>

    C.<%@ page extends="javax.servlet.jsp.JspErrorPage"%>

    D.<%@ page info="error"%>

    5、当浏览器第二次访问以下JSP网页时的输出结果是什么?( )C

    <%! int a=0;     %>

    <%

         int b=0;

         a++;

         b++;

    %>

    a:<%= a %> <br>

    b:<%= b %>

    选项:

    A.a=0  b=0                         B. a=1  b=1

    C. a=2  b=1                         D. a=2  b=2

    6、关于<jsp:include>, 下列说法不正确的是(  )。D【百度说是C】

    A. 它可以包含静态文件。

    B. 它可以包含动态文件。

    C. 当它的flush属性为true时,表示缓冲区满时,将会被清空。

    D. 它的flush属性的默认值为true。

    Include指令(编译时包括)又叫静态引用,约等于同一个界面,可以共享数据。
    Include动作(运行时包括)又叫动态引用,完全是两个界面,不能共享数据。
    autoFlush 定义缓冲满时,缓冲输出是否自动完成(flush)或抛出异常。
    缺省值为true。 

    7、在JSP中,对<jsp:setProperty>标记描述正确的是(  )。C

    A. <jsp:setProperty>和<jsp:getProPerty>必须在一个JSP文件中搭配出现。

    B. 就如同session.setAttribute()一样,来设计属性/值。

    C. 和<jsp:useBean>动作一起便用,来设置bean的属性值。

    D. 就如同request.setAttribute()一样,来设置属性/值。

    使用<jsp:getproperty>之前,必须<jsp:usebean>来创建它。
    
    不能使用<jsp:getproperty>来检索一个已经被索引了的属性。

    8、在 myjsp.jsp 中,关于下面的代码说法错误的是( )。A

    <%@ page language="java" import="java.util.*" errorPage="error.jsp" isErrorPage="false" %>     

    A.该页面可以使用 exception 对象  。

    B.该页面发生异常会转向 error.jsp  。

    C. 存在 errorPage 属性时,isErrorPage 是必须的属性值且一定为 false 。

    D.error.jsp 页面一定要有isErrorPage 属性且值为 true。

    9、下列哪一种不是JSP 中的注释符( )。   A

    A. <!--注释内容-->                         B.  /*注释内容*/     

    C. //注释内容                              D.   /**注释内容**/

    A是HTML里面的。

    https://blog.csdn.net/weixin_42859280/article/details/94357167

    10、J2EE中在JSP中要使用user包中的User类,则以下写法正确的是(   )。A

    A. <jsp:useBean id="user"class="user.User"scope="page"/>

    B. <jsp:useBean class="user.Use.class"/>

    C. <jsp:useBean name="user"class="user.User"/>

    D. <jsp:useBeam id="user"class="user"import="user.*"/>

    二、判断[1:表示对;0:表示错;]

    1、在page指令中,import参数允许重复使用多次。( )1

    2、<!--  -->中可以使用<% %>动态输出注释内容,同时<%--  --%>中也可以使用<% %>,因为预览JSP页面时没有报错。( )1

    [P54]

    3、当page标识的isThreadSafe属性设为true时,JSP只可以接受一个用户访问。( )0

    【P61,默认是true,能同时处理多个用户请求。false,一个jsp一次只能处理一个请求】

    4、<jsp:include page="body.jsp?name=tom&password=123" />可用于在JSP页面中包含body.jsp文件,并传递两个参数name和password。( )0

    【它没有这个功能】

    5、<%@ include file=”URL” %>允许包含动态文件和静态文件,但是这两种包含文件的结果是不同的,如果文件仅仅是静态文件,那么这种包含仅仅是把包含文件的内容加到JSP文件中去,这个被包含的文件不会被JSP编译执行。相反地,如果被包含文件是动态文件,那么这个被包含文件会被JSP编译器执行。( )0

    这个命令只有静态的。

    三、填空

    1、JSP有三个指令元素:

     <%@page%><%@include %><%@taglib %>

    2、JSP的脚本元素包含以下4个部分:

    隐藏注释(Hidden Comment)、声明(Declarations)、脚本段(ScriptLets)、表达式(Expression)

                      、                                                       

    3、动作元素<jsp:setProperty>的作用为           设置javabean对象的属性值                   

    4、<jsp:forward>的作用是    页面跳转     

    5、在JSP页面中可以声明方法,但是仅在   当前页面    内有效。

    四、简答

    1. 如何在HTML网页中嵌入JSP程序代码?怎样来定义JSP中的声明区与程序区?

    答:在JSP网页中必须于<%与%>符号间嵌入程序代码。
    JSP声明的语法格式为:
    <%! declaration; [ declaration; ] ... %> 或
    <%! 声明; [声明; ] ... %>
    脚本代码的语法格式如下:
    <% code fragment %> 或
    <% 代码 %>
    

    2. 请说明JSP中有哪3个指令元素,以及这3个指令的主要用途。

    答:page指令:可用来设置JSP网页的特性,如编码方式、引用类、缓冲区等。
    include指令:可用来将HTML、文本文件或者JSP程序加载当前的JSP网页。
    taglib指令:可用来引用一个自定义的标签库。
    

    3. JSP中include指令与include动作的区别是什么?

    答:include指令是指把其它页面的Java代码(源码)加进来,跟本页面的代码合并在一起,
    相当于把源码从那个页面复制到本页面中来,然后再编译。
    并且由于本页面编译时已经包含了别的文件的源码,所以以后其它页面更改时,
    本页面并不理会,因为已经编译过了。
    <jsp:include>动作是指两个页面的代码运行完以后,
    再把包含的那个页面运行后的HTML结果页面加到本页面运行后的HTML结果页面中来。
    所以是运行时包含,并且还可以传递参数给被包含的页面。
    

    4. JSP网页可以使用的特殊操作元素有哪些?其中<jsp:forward>与<jsp:param>操作元素各有什么功能?

    答:可使用的操作元素有<jsp:param>、<jsp:include>、<jsp:forward>、<jsp:plugin>。
    <jsp:forward>:可将当前浏览器显示网页的网址,重新导向新的网址。
    <jsp:param>:主要用来传递参数给JSP程序,而由程序取得参数值。
    

    五、编程

    1. 编写一个JSP程序,计算10!,并显示出结果。要求先声明计算阶乘的方法,再调用该方法,最后在页面上输出结果。

    (进阶要求,通过表单提交一个正整数,然后计算它的阶乘。)

    2. 在JSP页面中静态包含文件。要求程序包含两个文件,主文件静态包含一个能够计算数据的算数平方根的页面。

    3. 动态包含页面并传递数据。要求程序包含两个文件,主文件加载次文件,并将随机产生的0~1之间的数据传递给它,并且在页面上显示出来。

    (进阶要求,把动态包含改为动态重定向,比较两者之间的区别。)

    4. 计算三角形的面积。要求由用户输入三角形的三条边,判断这三条边是否能构成一个三角形,若能构成三角形,则输出三角形的面积。

     

    习题五【对应第三版4章】

     

    一、选择题

    1、在J2EE中,下列(  )语句可以获取页面请求中的一个单选框的选项值(单选框的名字为name)。C

    A.  response.getParameter("name");      

    B.  request.getAttribute("name");

    C.  request.getParameter("name");         

    D.  request.getParameters("name");

    P89

    2、在J2EE中,request对象的(     )方法可以获取页面请求中一个表单控件对应多个值时的用户的请求数据。D

    A.String getParameter(String name)

    B.String[] getParameter(String name)

    C.String getParameterValuses(String name)

    D.String[] getParameterValues(String name)

    P91下面

    3、以下对象中作用域最大的是(  )。C

    A.request                    B.session     

    C.application                 D.page

    P116

    4、在JSP页面中,能够完成输出操作的内置对象是 (  )。A

    A.   out                       B.  response

    C.   request                    D. config

    P103

    5、要在session对象中保存属性,可以使用以下哪个语句?(  )B

    A.   session.getAttribute("key","value");

    B.    session.setAttribute("key","value");

    C.   session.setAtrribute("key");

    D.   session.getAttribute("key");

    P109

    6、需要删除session中的某个属性key,可以调用下面的(   )方法。B

    A.   remove(“key”)

    B.    removeAttribute("key")

    C.   invalidate()

    D.   logout()

    P110

    7、在J2EE中,假如HttpSession的getLasAccessTime()方法返回值为x,getCreationTime()方法返回值为y,则为x - y()。C

    A.两个连续请求之间间隔的最长时间

    B.最近的两个连续请求之间的时间间隔

    C.最后使用session发送请求的时间和session创建时间的间隔

    D.最后使用session发送请求的时间

    P110

    8、以下代码能否编译通过,假如能编译通过,运行时得到什么输出结果( )。A

    <%

    request.setAttribute("count",new Integer(0));

    Integer count = request.getAttribute("count") ;

    %>

    <%=count %>

    A.   编译不通过

    B.    可以编译运行,输出0

    C.   编译通过,但运行时抛出ClassCastException

    D.   可以编译通过,但运行无输出

    貌似request.getAttribute("count") 必须强制转化 Integer

    9、现在session中没有任何属性,阅读下面2个JSP中的代码,将分别输出( )。A

    <%

              out.println(session.getAttribute("svse "));

    %>

    <%

              session.invalidate();

              out.println(session.getAttribute("svse "));

    %>

    A.   null, 异常信息

    B.    null, null,

    C.   异常信息,异常信息

    D.   异常信息,null

    1,返回一个什么都没有的。所以是null

    2,已经被结束。所以是null。参考P114

    10、Form表单提交的信息中含有“name= svse”,阅读下面的JSP,a.jsp将输出()。A

           接受该请求的JSP:

    <%

              response.sendRedirect(“a.jsp");  

    %>

           a.jsp包含如下代码

    <%=request.getParameter(“name") %>

    A.   null

    B.    什么都不输出

    C.   异常信息

    D.   svse

    P89.没有实际参数与之对应的时候。就会输出null。89页有例子。

    二、判断[1:表示对;0:表示错;]

    1、<jsp:forward ... >标记的page属性值是相对的URL地址,只能静态的URL。( )P70 3.4.2

    2、利用response对象的sendRedirect方法只能实现本网站内的页面跳转,但不能传递参数。(  )P98

    3、contentType属性用来设置JSP页面的MIME类型和字符编码集,取值格式为"MIME类型"或"MIME类型;charset=字符编码集",response对象调用addHeader方法修改该属性的值。(  )0  P96

    4、在J2EE中,重定向到另一个页面,可以用request.sendRedirect("http://www.jb-aptech.com.cn");(  )1P98

    【有争议】

    https://blog.csdn.net/qq_27668813/article/details/51394736

    5、应用application对象能在不同用户之间共享数据(    )。1 P116

    三、填空

    1、当客户端请求一个JSP页面时,JSP容器会将请求信息包装在             对象中。request

    2、已知文件look.jsp的路径为c:/myjsp/inc,文件login.jsp的路径为c:/myjsp。若使用response的重定向方法由look.jsp跳转到login.jsp中,则正确的写法为________________ 。response.sendRedirect(“../login.jsp”);

    3、当getParameter()方法的参数部分指定的输入控件不存在时,该方法的返回值为  ____________。null

    4、列表框的name属性值为“city”,并且允许多选,若要一次读取所有的选中项并存放于数组str中,则对应的java语句为____________________ 。String[] str=request.getParameterValues(“city”);

    5、给定一个JSP程序源码如下:

    <jsp:include page = “test.jsp”flush = “true”>

    <jsp:param name = “location”value = “beijing”/>

    </jsp:include>

    在test.jsp中加入____________________代码片断可以输出参数location的值。<%=request.getParameter(“location”)%>

    P89

    四、简答

    1. JSP中的内建对象包含哪些?试简述这些对象在JSP中的主要功能。

    答:request:取得客户端数据与系统的信息。
    response:响应客户端信息。
    application:记录与处理上线者共享的数据。
    session:记录与处理上线者的个别数据。
    out:控制数据输出的操作。
    config:取得JSP编译后Servlet的信息。
    pageContext:存取与处理系统运行时期的各项信息。
    page:表示当前的JSP网页。
    

    2. response重定向方法sendRedirect()和动作元素<jsp:forward>的区别是什么?

    (1)response.sendredirect()会在客户端呈现跳转后的URL地址;
    这种跳转称为客户端跳转。使用response.sendredirect()将重定向的URL发送到客户端,
    浏览器再根据这个URL重新发起请求。所以用这个方法时,
    你在浏览器地址栏上会看到新的请求资源的地址。
    并且这个时候的request,response都和第一次的不一样了。
    这时是重新产生了新的request,response。
    (2)使用<jsp:forward>完全是在服务器上进行,浏览器地址栏中的地址保持不变;
    这种跳转称为服务器端跳转。所以使用这个方法时没有产生新的用request,response。
    因为request没有变,在同一个请求内,可以用request来转递参数。
    (3)response.sendRedirect()想带参数的话,
    自己在地址中写成 xxx.jsp?param1=aaa&... 这种形式传递参数。
    <jsp:forward>能够使用<jsp:param/>标签向目标文件传送参数和值 ,
    目标文件必须是一个动态的文件,能够处理参数。
    (4)<jsp:forward>后面的语句不会被执行也不会继续发送到客户端,
    response.sendRedirect()后面的语句会继续执行,除非语句前面有return。
    (5)<jsp:forward>是在服务器的内部进行转换,只发送给客户端最后转到的页面,
    速度会比较快;response.sendRedirect()需要服务器与客户端之间的往返,
    可以转到任何页面,包括网络有效域名。但速度比较慢。
    

    3. application与session对象存储数据变量的方式有何区别?

    答:application:记录联机用户共享的数据。session:记录联机用户的个别数据。

    4. 请说明session对象的生命周期在哪些状况下会结束。

    答:当以下四种情形之一发生时,session与其中的数据便会消失:
    (1)用户关闭当前正在使用的浏览器程序。
    (2)关闭网页服务器。
    (3)用户未向服务器提出请求超过预设的时间,Tomcat服务器预设为30分钟。
    (4)运行程序结束session。
    

    五、编程

    1. 编写一个简单的网上测试系统。要求由两个页面组成,第一个页面显示试题,例如单选题,如图5-37所示。第二个页面获取考生提交的选择,统计考生得分并显示。

    2. 信息的保存和获取。

    例如简单的网上购物,将购买者的姓名、商品名保存在session对象中,实现一个Web目录下的页面对session对象中信息的共享。要求创建3个页面,第1个页面输入用户的姓名,第2个页面输入购买商品名的名称,第3个页面实现结账处理。

    3. 简单的用户登录。

    用户通过输入用户名和密码(假设用户名和密码都是admin)进入用户或管理员页面,拒绝绕过登录页面直接进入用户或管理员页面。

    要求创建4个文件,第1个是用户登录页面,此页面输入用户名和密码以及登录类型,如图5-38所示。

    图5-37  网上测试单选题                    图5-38  用户登录页面

    第2个文件对提交信息进行检查,如果输入正确则根据登录类型分别进入到管理员或普通用户页面,用重定向的方法实现跳转到这两个页面。如果输入有误,则弹出警示对话框,如图5-39所示,让用户重新输入信息。

    第3个文件是管理员页面,显示管理员成功登录的信息。

    第4个文件是普通用户页面,显示普通用户成功登录的信息。

    4. 用application对象实现一个简单的聊天室。

    要求采用application对象记录所有用户的留言信息并在页面上显示出来,如图5-40所示。

    图5-39  警示对话框                    图5-40  显示聊天内容

    习题六【第三版5章】

    一、选择题

    1、在web程序中,cookie和session的信息保存位置分别在哪里?( )  A

    A. cookie保存在客户端,session保存在服务器端

    B. cookie和session都保存在客户端

    C. cookie和session都保存在服务器端

    D. cookie保存在服务器端,session保存在客户端

    cookie:P133 session:P147

    2、有关会话跟踪技术描述不正确的是( )。D

    A. Cookie是Web服务器发送给客户端的一小段信息,客户端请求时,可以读取该信息发送到服务器端 P133

    B.关闭浏览器意味着会话ID丢失,但所有与原会话关联的会话数据仍保留在服务器上,直至会话过期。实话

    C.在禁用Cookie时可以使用URL重写技术跟踪会话。P147

    D.隐藏表单域将字段添加到HTML表单并在客户端浏览器中显示。P148

    3、J2EE中,Servlet API 为使用Cookie,提供了( )类。     A

    A. Javax.servlet.http.Cookie

    B. Javax.servlet.http.HttpCookie

    C. Javax.servlet. Cookie

    D. Javax.servlet.http. HttpCookie

    4、带有名为myCookie 的cookie存在于客户计算机上,服务器发送有同名的一个cookie。 这会发生什么?( )A

    A.新cookie 重写到老的cookie          B.新 cookie 被拒绝

    C.作为拷贝存贮新cookie               D.抛出一个异常

    5、不能在不同用户之间共享数据的方法是( )。A

    A.通过cookie

    B.利用文件系统

    C.利用数据库

    D.通过ServletContext对象

    6、如何获取一个 Cookie[] ?(  )。   A

    A.request.getCookies()     

    B.request.getCookie()

    C.response.getCookies()   

    D.response.getCookie()

    7、如何发送Cookie? ( )B

    A. 使用new Cookie语句

    B. 调用response.addCookie方法

    C. 使用Cookie的setMaxAge方法

    D. setCookie方法

    8、将Cookie保存到客户端,就是为了以后得到其中保存的数据。以下说法错误的是( )。C

    A.调用HttpServletRequest的getCookies得到一个Cookie对象的数组

    B.在客户端传来的Cookie数据类型都是数组类型,因此要得到其中某一项指定的Cookie对象,需要遍历数组来找。

    C.在客户端传来的Cookie数据类型都是枚举类型,因此要得到其中某一项指定的Cookie对象,需要指定元素位置来找。

    D.JSP将调用request.getCookies()从客户端读入Cookie,getCookies()方法返回一个HTTP请求头中的内容对应的Cookie对象。

    9、Cookie调用getValue( )方法取得( )。A

    A.与指定名字关联的值

    B.从客户端读入Cookie    

    C.检查各个Cookie的名字

    D.检查各个Cookie的值  

    10、下面的代码使用setMaxAge()方法设置Cookie对象login在一天之内都是有效的是(  )B

    A.login.setMaxAge(3600);

    B.login.setMaxAge(86400);

    C.login.setMaxAge(1);

    D.login.setMaxAge(7200);

    二、判断[1:表示对;0:表示错;]

    1、当用户关闭浏览器的时候,Cookie的数据便会消失。(  )0

    2、Cookie实质是服务器端与客户端之间传送的普通HTTP头,可以保存也可以不保存在客户的硬盘上。(  )1

    3、Cookie在生成时就会被指定一个Expire值,这就是Cookie的生存周期,在这个周期内Cookie有效,超出周期Cookie就会被清除。(  )1

    4、使用Cookie的目的就是为用户带来方便,为网站带来增值,但是事实上Cookie会造成严重的安全威胁。(  )0

     5、Cookie中的内容大多数经过了加密处理,因此在我们看来只是一些毫无意义的字母数字组合,只有服务器的CGI处理程序才知道它们真正的含义。(  )1

    三、填空

    1、Cookie数据存储的功能由      浏览器       所提供,因此,Cookie功能都必须要有浏览器的支持才行。

    2、Response对象的addCookie(Cookie cookie)方法添加一个       Cookie       对象,用来保存客户端的用户信息。

    3、用Request的      getCookies()       方法可以获得这个Cookie。

    4、用response对象的   addCookie    方法可以将cookie对象写入客户端。

    5、要删除某一个客户端的Cookie,必须使用前面的sexMaxAge()方法,并将Cookie的存在期限设为__0__。    

    四、简答

    1. 简述Cookie的概念与使用方式。

    答:Cookie为浏览器提供的功能,是一种可将联机用户的数据存储在客户端计算机上的技术,
    要运用Cookie必须先建立一个Cookie对象来存储字符串数据,再将此Cookie对象传送到客户端。

    2. 查看自己计算机上Cookie文件的保存位置。浏览网页,运行本书的例子,看是否会把信息记录在此位置?文件是如何命名的?文件的内容是什么?

    答:在默认情况下,Cookie是随着用户关闭浏览器而自动消失的。
    所以书上例子不会保存Cookie。如果在例2中我们在usingCookie.
    jsp中使用setMaxAge()方法,设置Cookie对象的存在期限。
    这样Cookie对象就会保存在硬盘中的Cookies文件夹中
    如“C:\Documents and Settings\Administrator\Cookies”如文件“administrator@ch06[1].txt”。
    内容是如下代码  
    “name
    d
    localhost/ch06/
    1024
    1524104704
    30118001
    4117789296
    30117999
    *”
    

    3. Cookie的常见用途有哪些?

    (1)网站浏览人数管理 
    由于代理服务器、缓存等的使用,
    唯一能帮助网站精确统计来访人数的方法就是为每个访问者建立一个唯一的ID。
    使用Cookie,网站可以完成以下工作:测定多少人访问过;
    测定访问者中有多少是新用户(即第一次来访),多少是老用户;
    测定一个用户多久访问一次网站。 
    通常情况下,网站设计者是借助后台数据库来实现以上目的的。
    当用户第一次访问该网站时,网站在数据库中建立一个新的ID,
    并把ID通过Cookie传送给用户。用户再次来访时,网站把该用户ID对应的计数器加1,
    得到用户的来访次数或判断用户是新用户还是老用户。 
    (2)按照用户的喜好定制网页外观 
    有的网站设计者,为用户提供了改变网页内容、布局和颜色的权力,
    允许用户输入自己的信息,然后通过这些信息对网站的一些参数进行修改,以定制网页的外观。
    (3)在电子商务站点中实现诸如“购物篮”等功能 
    可以使用Cookie记录用户的ID,这样当你往“购物篮”中放了新东西时,
    网站就能记录下来,并在网站的数据库里对应着你的ID记录当你“买单”时,
    网站通过ID检索数据库中你的所有选择就能知道你的“购物篮”里有些什么。
    

    4. Cookie与session有何不同?

    session与Cookie同样是用来记录上线用户的个别数据的,两者的差异在于session是存在于服务器端,
    而Cookie则是存在于客户端。

    五、编程

    1. 理解并掌握Cookie的作用及利用Cookie实现用户的自动登录功能,如图6-10所示。

    图6-10  应用Cookie保存用户信息

    当服务器判断该用户是首次登录时,会自动跳转到登录页面等待用户登录,并填入相关信息。通过设置Cookie的有效期限来保存用户的信息。关闭浏览器后,验证是否能够自动登录,若能登录打印欢迎信息,否则跳转到登录页面。

     

    习题七【第三版6章】

    • 选择题

    1、<jsp:useBean>声明对象的默认有效范围为(  )。A

    A. page                       B.   session        C. application                      D. request

    page对象就是指jsp页面本身,是java.lang.Object实例。

    2、编写JavaBean就是编写一个Java类,所以只要会写类就能编写一个Bean,一个完整JavaBean在类的命名上需要遵守以下规则,其中错误的是(  )。D

    A. 类中方法的访问属性必须是public的。类中方法的访问属性必须是public的

    B. 对于boolean类型的成员变量,允许使用is代替get。对于boolean类型的成员变量,允许使用is代替get和set

    C. 类中如果有构造方法,那么这个构造方法也是public的,并且是无参数的。

    类中如果有构造方法,那么这个构造方法也是public的,并且是无参数的

    D. 在JavaBean中定义属性时,应该定义成public。javaBean属性定义为pirvate

    https://blog.csdn.net/yihuliunian/article/details/90900212[遵守一下4项规定。]

    3、关于JavaBean的说法,哪个是正确的?(  )D

    A.   JavaBean的具体类可以不是public的。[P167]

    B.    JavaBean可以只提供一个带参数的构造器。[P167]

    C.   jsp:userBean可以向HTML标记一样不关闭。[]

    D.   JavaBean可以保存状态。

    4、下边哪个不是MVC中的组成部分?(  )B

    A.   JavaBean  B. FrameWork  C.   JSP  D. Servlet

    5、下面哪一个是正确使用JavaBean的方式?(  )A

    A.   <jsp:useBean id="address" class="AddressBean" />P172

    B.    <jsp:useBean name="address" class="AddressBean"/>

    C.   <jsp:useBean bean="address" class="AddressBean" />

    D.   <jsp:useBean beanName="address" class="AddressBean" />

    6、在JSP中使用<jsp:getProperty>标记时,不会出现的属性是:(  )C

    A.  name     B.  property     C. value        D.以上皆不会出现

    7.、在JSP中调用JavaBean时不会用到的标记是:(  )A

    A.<javabean>     B. <jsp:useBean>    C.<jsp:setProperty>   D. <jsp:getProperty>P170首行

    8.、关于JavaBean正确的说法是:( )A

    A. Java文件与Bean所定义的类名可以不同,但一定要注意区分字母的大小写

    B. 在JSP文件中引用Bean,其实就是用<jsp:useBean>语句

    他的这种说法没错,但是太绝对了,还有其他的方法可以引用bean啊,因为它是选择题,所以语句要要求很严谨

    C. 被引用的Bean文件的文件名后缀为.java

    jsp中还可以通过Java脚本来newJavabean对象

    D. Bean文件放在任何目录下都可以被引用

    所有编译好的JavaBean都需要放在某个应用目录下的_____WEB-INF/classes_______目录之下。

    9、 test.jsp文件中有如下一行代码:

    <jsp:useBean id=”user” scope=”__” type=”com.UserBean”>

    要使user对象可以作用于整个应用程序,下划线中应添入(  )。D

    A.   page    B.    request  C.   session   D.  application

    作用于整个应用程序

    10、下面哪项是错误的设置Bean属性值的方法(   )。 B

    A. <jsp:setProperty name="beanInstanceName" property= "*" />

    B.<jsp:setProperty name="beanInstanceName" property="propertyName"/>

    C.<jsp:setProperty name="beanInstanceName" property="propertyName"

    param="parameterName" />

    D. <jsp:setProperty name="beanInstanceName" property="*" value="{string | <%= expression

    %>}"/>

    选项D重复啦

    二、判断题[1:表示对;0:表示错;]

    1、在MVC模式中,因为Servlet负责创建JavaBean,所以JavaBean的构造函数可以带有参数,除了保留get和set规则外,还可以有其他功能的函数。(   )1

    2、Bean文件放在任何目录下都可以被引用。(  )0

    3、get请求处理的数据量大小不受到限制。(   )0

    4、<jsp:getProperty>必须出现在其对应的<jsp:usebean>标签之后。(  )1【事实】

    5、相同的Javabean只会实例化一次。(   )0【https://zhidao.baidu.com/question/1642382354215987180.html

    三、填空题

    1、Javabean是一种     Java        类,通过封装     属性               方法          成为具有某种功能或者处理某个业务的对象,简称bean。

    2、在Tomcat中,所有编译好的JavaBean都需要放在某个应用目录下的_____WEB-INF/classes_______目录之下。

    3、JSP开发网站的两种模式分为______jsp+javabean__________和_____jsp+javabean+servlet___________ 。

    4、如果你想使用Javabean设计一个网站计数器,那么该bean的scope应当设为    application            

    5、按功能JavaBean可以分为____可视化JavaBean_________和_______非可视化JavaBean_____。

    四、问答题

    1. 试说明什么是JavaBean。

    答:JavaBean是一种特殊的Java程序,是用于包装特定功能的程序代码,
    可以被JSP网页重复使用,其本身无法独立运行,是JSP网页程序组件化的核心。

    2. 试说明如何在JSP网页中载入JavaBean。

    A:<jsp:useBean id=id-name scope=scope-name class=class-name />

    3. JavaBean对象可声明哪些不同的生命周期?

    答:request、session、page及applaction。

    4. JavaBean程序除了必须要有一个无传入值的建构式之外,还有哪些特色?

    答:除了必须要有一个无传入值的建构式之外,还必须是一个公开的类,并以set及get开头的方法来设置与取得属性。

    5. 试说明Get和Post方法之间的差异?

    答:Post和Get这两种设置方式主要的差异在于数据的传送方式,
    前者将所要传送的数据包含在HTTP文件头中,
    后者则是将数据直接串接在网址栏的后端,
    两者都可使用GetParameter取得传送的数据内容。

    五、编程

    1、要求编写两个JSP页面:input.jsp和show.jsp。编写一个名字为car的JavaBean,其中car由Car.class类负责创建。

    input.jsp页面提供一个表单。其中表单允许用户输入汽车的牌号、名称和生产日期,该表单将用户输入的信息提交给当前页面,当前页面调用名字为car的bean,并使用表单提交的数据设置car的有关属性的值。要求在input.jsp提供一个超链接,以便用户单击这个超链接访问show.jsp页面。

    show.jsp调用名字为car的bean,并显示该bean的各个属性的值。

    编写的Car.java应当有汽车号码、名称和生产日期的属性,并提供相应的getXxx和setXxx方法,来获取和修改这些属性的值。

     

    习题八[对应第三版本7章]

     

    一、选择题

    1.在WEB应用程序的目录结构中,在WEB-INF文件夹中的lib目录是放(   )文件的。C

    A. .jsp文件  B. .class文件  C. .jar文件  D. web.xml文件

    2、java.io.File对象的(   )方法可以新建一个文件。D
    A. delete()          B. createFile()       C. mkdir()      D. createNewFile()
    3、在JSP应用程序中要求删除所有photo目录中的的文件,但是保留文件夹,下列代码中空缺位置最适合的选项为(   )。A

    String path=request.getRealPath("photo");
    File fp1=new File(path);
    File[] files=fp1.listFiles();
    for(int i=0;i<files.length;i++)
    {
       if(__________________________)
         {
                files[i].delete();  
    }
    }
    A. files[i].isFile()       B. files[i].isDirectory()  C. !files[i].isFile()      D. ! files[i].isDirectory()

    4、下列File对象的哪个方法能够判断给定路径下的文件是否存在。(   )C

    A. canRead()     B .canWrite()    C. exists()       D. isDirectory()

    5、BufferedReader处理Reader类中的方法外,还提供了public String readLine()方法,该方

    法读入一行文本,这里的“一行”指字符串以“\n”或什么做结尾。(   )C

    A. \t      B. \f     C. \r      D. \p

    二、判断题[1:表示对;0:表示错;]

    1、File类直接处理文件和文件系统,它并不涉及文件的读写操作。(  )1

    2、创建一个File对象,就会在某个物理路径下创建一个文件或目录。(  )0

    3、使用Java的输出流写入数据的时候,就会开启一个通向目的地的通道,这个目的地可以是文件,但不能是内存或网络连接等。(  )0

    4、“纯文本”类的信息,一般使用字符流来进行处理。(  )1

    5、InputStream抽象类的read方法出错后一定会抛出一个IOException异常。(  )1

    三、填空题

    1、Java中有四个“输入/输出”的抽象类,                                                

    InputStream 、OutputStream、Writer、Reader

    2、从网站上下载jspsmartupload.jar这个文件,将此文件放到网站的    WEB-INF\lib   文件夹底下。

    3、字节流类为处理字节式输入/输出提供了丰富的环境,其处理单元为   1         个字

    节;字符流提供了处理任何类型输入/输出操作的足够功能,字符流处理的单元为         2              

    个字节的Unicode字符。

    四、问答题

    1. JSP网页使用File类之前,将哪个命名空间载入?

    import="java.io.*"

    2. 试说明如何利用File类进行文件目录的操作?

    答:利用File类进行文件目录的操作首先必需建立一个File对象,
    将所要操作文件或是目录完整路径当作参数传入,当File对象建立之后,
    JSP网页便可以利用这个对象调用File类的所有方法,以进行各种文件目录的操作。

    3. 简述文件存取操作的操作过程。

    答:首先利用File类建立一个参照指定文件的目录的File实体对象,
    接下来利用FileWriter和FileReader这两个类,进行指定文件的读写,
    其中的FileWriter的write方法,负责将数据写入文件,而FileReader的read则用来读取文件中的数据。

    五、编程

    1、 创建两个文件selectContent.jsp和writeContent.jsp,首先使用selectContent.jsp中的表单输入存放路径、保存的文件名和将要写入文件的文件内容信息,提交后,由writeContent.jsp文件负责将内容写到指定的文件中,同时放到指定的路径下。运行结果如图8-12和图8-13所示。

     

    图8-12  selectContent.jsp页面

     

    图8-13  提交成功后的结果

    2、. 创建两个文件selectFile.jsp和readContent.jsp。首先使用selectFile.jsp中的表单输入存放路径和将要读取的文件名,提交后,由readContent.jsp文件负责将文件读出并显示在页面上。运行结果如图8-14和图8-15所示。

                 

    图8-14  selectFile.jsp页面                          图8-15  提交成功后的结果

     

     

    习题十【对应三版本8章】

     

    一、选择题

    1、创建JSP应用程序时,配置文件web.xml应该在程序下的(   )目录中。C
           A. admin       B. servlet       C. WEB-INF        D. WebRoot  P234

    2、 Oracle数据库的JDBC驱动程序类名及完整包路径为:(   )D

    A.   jdbc.driver.oracle.OracleDriver

    B.    jdbc.oracle.driver.OracleDriver

    C.   driver.oracle.jdbc.OracleDriver

    D.   oracle.jdbc.driver.OracleDriver   P231

    3、请选出微软公司提供的连接SQL Server 2000的JDBC驱动程序。(   )C

    A. oracle.jdbc.driver.OracleDriver                   B. sun.jdbc.odbc.JdbcOdbcDriver

    C. com.microsoft.jdbc.sqlserver.SQLServerDriver  P231     D. com.mysql.jdbc.Driver

    4、下述选项中不属于JDBC基本功能的是:( )D

    A. 与数据库建立连接 B.  提交SQL语句   C.  处理查询结果 D.  数据库维护管理【常识吗?】

    5.在 JSP中,便用 Resultset对象的 next()方法移动光标时,如果超过界限,会抛出异常,该异常通常是(   )。C

    A.InterruptedExceptlon   B.AlreadyBoundExceptlon  C.SQLException  D.NetExcePtlon

    6、cn是Connection对象,创建Statement 对象的方法是:(   )B

    A. Statement st=new Statement ();       B. Statement st=cn.createStatement()

    7、查询数据库得到的结果集中,游标最初定位在(    )。B

    A. 第一行  B. 第一行的前面  C. 最后一行  D. 最后一行的后面

    8、在JDBC中,下列哪个接口不能被Connection创建(  )。D

    A.Statement   B.PreparedStatement      C.CallableStatement      D.RowsetStatement【在课本上面没找到】

    9、该程序加载的是哪个驱动?(   )A【缺失啦】

    A. JDBC-ODBC桥连接驱动      B.部分Java编写本地驱动

    C. 本地协议纯Java驱动         D.网络纯Java驱动

    10、下列代码生成了一个结果集

    conn=DriverManager.getConnection(uri,user,password);

    stmt=conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,

    ResultSet.CONCUR_READ_ONLY);

    rs=stmt.executeQuery("select * from book");

    rs.first();rs. previous();

    下面哪项对该rs描述正确( )D

    A.rs.isFirst()为真  B.rs.ifLast()为真  C.rs.isAfterLast()为真  D.rs.isBeforeFirst()为真

    二、判断题[1:表示对;0:表示错;]

    1、使用JDBC-ODBC桥效率会有所降低。(  )1

    2、Statement对象提供了int executeUpdate(String sqlStatement)方法,用于实现对数据库中数据的添加、删除和更新操作。(  )1

    3、数据库服务与Web服务器需要在同一台计算机上。(  )0【事实】

    4、使用数据库连接池需要烦琐的配置,一般不宜使用。(  )0【管理功能】

    5、JDBC构建在ODBC基础上,为数据库应用开发人员、数据库前台工具开发人员提供了一种标准,使开发人员可以用任何语言编写完整的数据库应用程序。(  )0【任何就过分了吧】

    三、填空题

    1、JSP应用程序配置文件的根元素为 _______<web-app>___________。

    2、JDBC的主要任务是:__________________、__________________、__________________。

    与数据库建立连接    、    发送SQL语句  、   处理结果   。

    3、如果想创建一个不敏感可滚动并且不可更新的结果集,参数选择__________________和__________________。

    ResultSet.TYPE_SCROLL_INSENSITIVE   ResultSet.CONCUR_READ_ONLY

    4、在可更新的结果集中插入一条新纪录,需要移动首先到可更新行,调用_______moveToInsertRow();___________函数。

    5、Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); 是__________Access________数据库的加载驱动语句。

    四、问答题

    1. 试说明Statement与ResultSet接口的意义,以及它们生成的对象在JSP程序处理数据库时,分别扮演着什么样的角色?

    答:Statement:Statement接口中主要是提供了一些SQL运行的方法,
    以及设置运行SQL后所返回ResultSet类型对象的属性。
    由此接口所生成的对象在JSP中同样是用来运行各种SQL指令与设置Resultset对象的属性。
    ResultSet:ResultSet接口下所定义的方法大都是用来控制ResultSet对象中指针的移动的,
    以取得其中的数据元素。
    

    2. 试列举说明Statement运行SQL指令的3种方法成员。

    答:execute():运行一般SQL指令,例如建立数据库、修改数据表等等。
    executeQuery():运行以SELECT语句开头的描述,
    这个方法同时返回一个包含查看结果的ResultSet对象。
    

    3. 说明如何一次运行多段SQL语句。

    答:首先建立一个Statement对象,将多个想要运行的SQL指令以addBatch()方法加到批处理文档中,
    最后引用executeBacth()方法运行。

    五、编程

    1. 使用本章的数据库ch10中student表的结构,创建3个页面selectStudent.jsp、byNumber.jsp和byName.jsp,通过JSP页面对student表进行名字和学号的查询。运行效果如图10-28、图10-29和图10-30所示。

     

    图10-28  selectStudent.jsp页面

     

    图10-29  byNumber.jsp页面

    2. 使用本章数据库ch10中student表的结构通过JSP页面对student表进行添加、删除和修改。添加JSP页面处理功能:添加新学生、修改和删除选中的学生信息,如图10-31所示(或者自行设计界面)。

       

    图10-30  byName.jsp页面                            图10-31  演示页面

     

    习题十二【对应三版本10章】

    一. 选择题

    1. 下面Servlet的哪个方法用来为请求服务,在Servlet生命周期中,Servlet每被请求一次它就会被调用一次。( )A

    A.service()     B.init()    C. doPost()      D.destroy()

    P286

    2. Servlet 可以在以下(  )三个不同的作用域存储数据。B

    A.HttpServletRequest、HttpServletResponse、HttpSession

    B.HttpServletRequest、HttpSession、ServletContext

    C.HttpServletResponse、HttpSession、ServletContext

    D.HttpServletRequest、HttpServletResponse、ServletContext

    P298 P307 P311

    3. 在J2EE中,Servlet从实例化到消亡是一个生命周期。下列描述正确的是( )。ABD

    A.在典型的Servlet生命周期模型中,每次Web请求就会创建一个Servlet实例,请求结束Servlet就消亡了P286

    B.init()方法是容器调用的Servlet实例此方法仅一次    P293

    C.在容器把请求传送给Servlet之后,和在调用Servlet实例的doGet或者doPost方法之前,容器不会调用Servlet实例的其他方法

    D.在Servlet实例在service()方法处理客户请求时,容器调用Servlet实例的init()方法一定成功运行了P293

     

    4. 在J2EE中,给定某Servlet的代码如下,编译运行该文件,以下陈述正确的是( )。B

    Public class Servlet1 extends HttpServlet{

       Public void init() throws ServletException{

       }

       Public void service(HttpServletRequest request,HttpServletResponse response)

               Throws ServletException,IOException{

           PrintWriter out = response.getWriter();

           Out.println(“hello!”);

       }

    }

    A. 编译该文件时会提示缺少doGet()或者dopost()方法,编译不能够成功通过

    B.编译后,把Servlet1.class放在正确位置,运行该Servlet,在浏览器中会看到输出文字:hello!

    C.编译后,把Servlet1.class放在正确位置,运行该Servlet,在浏览器中看不到任何输出的文字

     D.编译后,把Servlet1.class放在正确位置,运行该Servlet,在浏览器中会看到运行期错误信息

    5. 下面是IP地址为222.22.49.189Web服务器上,ch应用下的一个Servlet部署文件的片段:

       <servlet>

           <servlet-name>Hello</servlet-name>

           <servlet-class>myservlet.example.FirstServlet</servlet-class>     

       </servlet>

       <servlet-mapping>

           <servlet-name>Hello</servlet-name>

           <url-pattern>/helpHello</url-pattern>

       </servlet-mapping>

       访问此Servlet的URL地址是。(  )A

    A.http://222.22.49.189:8080/ch/helpHello【默认】

    B.http://222.22.49.189:8080/ch/helpHello.java

    C.http://222.22.49.189:8080/helpHello

    D./helpHello

    6. 在Web应用的部署描述文件中下面哪个选项能够将com.example.LoginServlet servlet 映射为 /utils/LoginServlet?(  )D

    A. <servlet>

    <servlet-class>com.example.LoginServlet</servlet-class>

    <url-pattern>/utils/LoginServlet</url-pattern>

    </servlet>

    B. <servlet-mapping>

    <servlet-class>com.example.LoginServlet</servlet-class>

     <url-pattern>/utils/LoginServlet</url-pattern>

    </servlet-mapping>

    C. <servlet>

    <servlet-mapping>

    <servlet-class>com.example.LoginServlet</servlet-class>

    <servlet-name>Login Servlet</servlet-name>

    <url-pattern>/utils/LoginServlet</url-pattern>

    </servlet-mapping>

    </servlet>

    D. <servlet>

    <servlet-name>Login.Servlet</servlet-name>

    <servlet-class>com.example.LoginServlet</servlet-class>

    </servlet>

    <servlet-mapping>

    <servlet-name>Login.Servlet</servlet-name>

    <url-pattern>/utils/LoginServlet</url-pattern>

    </servlet-mapping>

    7. 在Web容器中,以下哪两个类别的实例分别代表HTTP请求与响应对象?(  )BC

    A. HttpRequest                  B. HttpServletRequest

    C. HttpServletResponse            D. HttpPrintWriter

    二. 判断[1:表示对;0:表示错;]

    1. 不能给一个Servlet映射多个访问路径。(  0)P292

    2. JSP技术是在Servlet之后产生的,它以Servlet为核心技术,是Servlet技术的一个成功应用。( 1)P事实

    3. 实现转发需要两个步骤,首先在Servlet中要得到RequestDispatcher对象,然后在调用该对象的forward方法实现转发。

    ( 1 )P313-314

    三. 填空

    1. 在Servlet中有两种异常处理机制:______和_______。

    程序式异常处理机制和声明式异常处理机制。P316.以及标题。

    2. 如果某个类要成为Servlet,则它应该继承_________、________或_________接口或类。

    HttpServlet、GenericServlet、Servlet

    3. Servlet 的生命周期又一系列事件组成,把这些事件按照先后顺序排序_________、________、_________、________、_________。

    加载类,实例化,初始化,请求处理,销毁

    四. 简答

    1. 简述Servlet和JSP的关系。

    答:Servlet是服务器端运行的一种Java应用程序。当浏览器端有请求则将其结果传递给浏览器。
    在JSP中使用到的所有对象都将被转换为Servlet或者非Servlet的Java对象,
    然后被执行,所以执行JSP实际上与执行Servlet是一样的。
    

    2. 简述Servlet的生命周期。

    答:
    Servlet的生命周期可分为下面几个阶段:
    (1)装载Servlet。
    (2)实例化一个Servlet实例对象。
    (3)调用Servlet的init( )方法进行初始化。
    (4)服务。
    (5)卸载。
    

    3. 简述HttpSession接口的功能和使用方法。

    答:
    .HttpSession接口是Servlet提供会话追踪解决方案。 HttpSession对象存放在服务器端,只是对cookie和url重写技术的封装应用。
    使用HttpSession进行会话控制的过程:
    (1)获得一个HttpSession实例对象;
    (2)访问和设置与会话相关联信息,维护会话的状态;
    (3)废弃会话数据。
    

    4. 简述开发一个Servlet所需要的步骤。

    答:
    第一步:编写Servlet实例
    第二步:在web.xml文件中配置该Servlet
    第三步:编写其它文件
    

    五、编程

    1. 编写一个HTML页面和一个Servelt,实现利用Servelt()的doPost()方法读取HTML文件中Form表单内容。

    2. 编写一个利用HttpSession接口的用户登录的Servlet,当用户已经登录时,返回欢迎信息,否则转向登录页面。

     

     

    习题十三【对应三版本11章】

     

    一、选择题

    1. 在web.xml文件中,有下列代码:

    <filter-mapping>

       <filter-name>LogFilter</filter-name>

       <url-pattern>/*.jsp</url-pattern>

       < dispatcher > REQUEST </ dispatcher >

       < dispatcher > INCLUDE < /dispatcher >

    </filter-mapping>

     

    Hello.jsp文件的代码如下:

    <%@ page contentType="text/html;charset=GB2312" %>

    <%@ page import="java.sql.*" %>

    <html>

    <body bgcolor=cyan>

     <jsp:include file="date.jsp"/>

     <jsp:forward page="helpHello.jsp"/>

     <a href="login.jsp">登录</a>

    </body>

    </html>

    访问Hello.jsp文件,过滤器LogFilter过滤的文件有( )D

    A.Hello.jsp            B.helpHello.jsp

    C.login.jsp            D.date.jsp

       < dispatcher > REQUEST </ dispatcher >
    不要request
    
       < dispatcher > INCLUDE < /dispatcher >
    不要include

    2. 下列哪个不属于监听器接口ServletContextAttributeListener提供的方法()D

    A.public void attributeAdded(ServletContextAttributeEvent event)

    B.public void attributeRemoved(ServletContextAttributeEvent event)   

    C. public void attributeReplaced(ServletContextAttributeEvent event)     

    D.public void valueBound(HttpSessionBindingEvent event)

    P355

    3. 下列哪个不属于Servlet2.3提供的监听器。( )D

    A.ServletContext对象状态变化(事件)的监听器P351

    B.HttpSession对象状态变化(事件)的监听器P351

    C.HttpServletRequest对象状态变化(事件)的监听器[没找到]

    D.HttpServletResponse对象状态变化(事件)的监听器

    【或者,可以按照P351的。没有response】

    4. 为了实现对下列jsp代码动作的监听,需要定义的监听器必须实现下列哪些接口。( )BD

    test.jsp文件代码如下:

    <%

    getServletContext().setAttribute("userName","hellking");

    getServletContext().removeAttribute("userName");

    request.getSession.setAttribute("user","hellking");

    %>

    A. ServletContextListener           B. ServletContextAttributeListener

    C. HttpSessionAttributeListener      D. HttpSessionBindingListener

    E. ServletRequestAttributeListener

    5.给定某Servlet程序的片段如下,用户在浏览器地址栏中键盘键入正确的请求URL并回车后,在控制台上显示的结果是。()C

       public void doGet(HttpServletRequest request,HttpServletResponse response) throws ServletException ,IOException

       {

       System.out.println("get");

           doPost(request,response);

       }

       public void doPost(HttpServletRequest request,HttpServletResponse response)  throws ServletException ,IOException

       {

       System.out.println("post");

       }

    A.get      B.post     C.getpost     D.postget

    【嗯哼?】

    二、判断[1:表示对;0:表示错;]

    1. 部署过滤器的工作内容,实际就是在Web应用的Web.xml文件中配置过滤器。(  1)

    2. 在Web.xml文件中部署监听器,用<listener>注册监听器,用<listener-mapping>映射监听器。( 0)P353

    filter-mapping的配置:我们将uimfilter过滤器映射给所有的jsp文件【P342】

    3. 如果使指定的IP访问JSP时报错,并告知用户不能访问,可以使用监听器。( 1 )

    监听器的理解:监听器好比一个卫兵,卫兵一直站在那里等待长官的命令,当卫兵收到长官的命令以后,立即执行

        之前已经协定好的事件。

    三、填空

    1. 对Web应用来说,_______就是驻留在服务器端,在源数据和目的数据间,对Web请求和Web响应的头属性(Header)和内容体(Body)进行操作的一种特殊Web组件。过滤器&filter&Filter

    2. 过滤器对象使用_______对象调用过滤器链中的下一个过滤器或者是目标资源。

    FilterChain & filterchain & Filterchain & filterChainP339

    3. 在J2EE中,使用Servlet过滤器时,需要在web.xml通过_____元素将过滤器映射到Web资源。<filter-mapping>[P342]

    4. 在一个Filter中,处理filter业务的是____方法。 [P339-]

    doFilter (ServletRequest request,ServletResponse response, FilterChain chain)

    四、简答

    1. 什么是过滤器?什么是监听器?分别应用在哪些方面?

    2. Filter接口、FilterConfig接口和FilterChain接口的功能分别是什么?提供的方法有哪些?

    3. ServletContextListener接口、ServletContextAttributeListener接口和HttpSessionBindingListener接口的功能分别是什么?提供的方法有哪些?

    4. JSP乱码如何解决,列举几种解决方案?

    5. 如何编写、配置过滤器,举例说明?

    6. 如何编写、配置监听器,举例说明?

     

    五、编程

    1. 编写一个过滤器LogFilter.java,对Request请求进行过滤,记录请求的访问时间戳、从请求获取远程地址、从请求获取远程主机名、客户请求的资源URI、客户用的浏览器,并记录到日志文件中。

    2. 编写一个监听器ContextListener .java,监听Web应用的启动和停止,并记录到日志文件中。

     

    习题十四【对应三版本12章】

    一. 选择题

    1.  给定程序片段:

      <% String value = "beanvalue"; %>

      <% request.setAttribute ("com.example.bean", value); %>

      <%--插入代码处--%>

    在第3行插入哪个EL表达式,能够计算并输出"beanValue"。( )E

    A. ${bean}       B. ${value}      C. ${beanValue}

    D. ${com.example.bean}

    E. ${requestScope["com.example.bean"]}

    F. ${request.get("com.example.bean").toString()}

    2. 假定在web应用中,请求参数productID包含产品的标识符,下面哪两个EL表达式能够计算productID的值。(  )B

    A. ${product ID}

    B. ${param.productID}

    C. ${params.productID}

    D. ${params.productID[1]}

    3. 用户的会话对象中存在属性cart,以下哪两条语句能够将该属性从session中删除( )  DE

    A. ${cart = null}

    B. <c:remove var="cart" />

    C. <c:remove var="${cart}" />

    D. <c:remove var="cart" scope="session" />

    E. <c:remove scope="session">cart</c:remove>

    F. <c:remove var="${cart}" scope="session" />

    G. <c:remove scope="session">${cart}</c:remove>

    4. 在JSP页面中,开发人员需要构建如下的动态代码:

    if ( test1 ) {

      // action1

     } else if ( test2 ) {

      // action2

    } else {

      // action3

    }

    下面个JSTL的结构能够实现相同的功能?B

    A. <c:choose>

    <c:when test="test1" >action1</c:when>

    <c:when test="test2">action2</c:when>

    <c:when>action3</c:when>

    </c:choose>

    B. <c:choose>

    <c:when test="test1">action1</c:when>

    <c:when test="test2">action2</c:when>

    <c:otherwise>action3</:otherwise>

    </c:choose>

    C. <c:if test="test1">

    <c:then>action1</c:then>

    <c:else-if test=""test2">

    <c:then>action2</c:then>

    <c:else>action3</c:else>

    </c:else-if>

    </c:if>

    D. <c:if test="test1">

    <c:then>action1</c:then>

    <c:else>

    <c:if test="test2">

    <c:then>action2</c:then>

    <c:else>action3</c:else>

    </c:if>

    <c:else>

    <c:if>

    二. 判断[1:表示对;0:表示错;]

    1. JSTL代码片段<c:import url="foo.jsp"/>能够实现导入其他web资源的功能。(1 )

    2. <fmt:setLocale>是用于设置本地属性的JSTL标记。( 1)

    3. SQL标记库中的标记<sql:query>是用来修改数据库中的记录。(0  )

    三. 填空

    1. 假定在web应用中,请求参数productID包含产品的标识符,能够计算productID值的EL表达式____。

    2. JSTL的全称是____。

    3. JSTL提供的标签分为5大类,分别是_____、______、______、______和______。

    4. 在JSTL核心标签当中,网页数据的存取操作行为是由标签_______、_____与______等3个标签所设置的。

    5. 在与url有关的标签中,______用来设置一个超级链接。

    6. 流程控制标签用来控制程序运行的流程, __________搭配__________与__________,来进行多重判断。

    7. <c:forEach>标签通过属性值_____、_____与_____控制循环的间隔数及起始与结束值。

    8. <c:out>标签中使用____属性表示要输出的内容。

    9. <c:set>标签的作用是____。

    10. 标识EL语法元素的符号为______。

    11.  EL中的三元运算符为________。

    12. 与存活期范围有关的4个隐含对象分别是______、_______、_______以及_______。

    13. 隐含对象_______与_______,可直接用来存取表单传递的参数。

    14 系统初始化数据存放于WEB-INF文件夹的_____,隐含对象____可用来对其进行访问。

    1. ${param.productID}
    2. JSP Standard Tag Library  
    3. JSTL提供的标签分为5大类,分别是[核心标签]、[i18n国际化格式标签]、[SQL标签]、[XML标签]和[函数标签]。
    4. 在JSTL核心标签当中,网页数据的存取操作行为是由标签[out]、[set]与[remove]等3个标签所设置的
    5. 在与url有关的标签中,[<c:url>]用来设置一个超级链接。
    6. 流程控制标签用来控制程序运行的流程,[<c:choose>]搭配[<when>]与[<otherwise>],来进行多重判断。
    7. <c:forEach>标签通过属性值[begin]、[end]及[step]控制循环的间隔数及起始与结束值。
    8. value
    9. 将EL表达式的值存储在一个变量中 
    10. 标识EL语法元素的符号为[&{}]。
    11. EL中的三元运算符为[A?B:C]。
    12. 与存活期范围有关的4个隐含对象分别是[pageScope]、[requestScope]、[sessionScope]及[applicationScope]。
    13. 隐含对象[param]及[paramValues],可直接用来存取表单传递的参数。
    14. 系统初始化数据存放于WEB-INF文件夹的[web.xml]中,隐含对象[initParam]可用来对其进行存取。
    

    四. 简答

    1. 请简述JSTL与一般的JSP技术有何差异。

    2. JSTL标签的分类主要有哪几种,请简单说明。

    3. 使用JSTL有何优点?

    4. 在Tomcat中安装使用JSTL的步骤有哪些?

    5. <c:if>和<c:choose>这两种标签都可以用来进行流程判断,请说明它们的差异及用法。

    6. 说明如何使用JSTL所提供的<sql:setDataSource>标签设置联机信息。

    7. 在EL中访问变量的值可以使用如下的EL元素:${变量名},如果没有指定变量的有效范围,JSP容器会依次到哪几个范围内查找该变量?

    8. 说明如何运用隐含对象取得表单参数

    1. 
    请简述JSTL与一般的JSP技术有何差异。
       答:使用JSTL实现动态JSP页面的最大特点在于简单,避免了使用脚本片段带来的许多问题,Web应用开发人员利用JSTL可以取代直接嵌入页面的代码片段,提高程序可读性和可维护性。
    2. 
    JSTL标签的分类主要有哪几种,请简单说明。
    答:核心标签库、I18N 格式标签库、SQL 标签库、XML 标签库、函数标签库 
    
    4. 
    在Tomcat中安装使用JSTL的步骤有哪些?
    Sun的JSTL页面(http://java.sun.com/products/jsp/jstl)提供JSTL规范文档和相关实现的下载。Apache Jakarta项目是JSTL标准的一种实现,具体下载网址为:http://www.apache.org/dist/jakarta/taglibs/standard/。Windows系统下软件包的对应下载的文件名为:jakarta-taglibs-application-current.zip。
    Jakarta JSTL的实现是一些JAR文件,如果在Web应用中使用JSTL,就需要在Web应用的WEB-INF\lib目录下包含JSTL的JAR文件。将jstl.jar和standard.jar复制到Tomcat网站根目录下的文件夹WEB-INF\lib当中,并将tld目录复制到Tomcat的WEB-INF目录下,重新启动Tomcat之后,就可以开始使用JSTL了。
    
    5. 
    <c:if>和<c:choose>这两种标签都可以用来进行流程判断,请说明它们的差异及用法。
    答:<c:if>标签用于进行条件判断,只有当其test属性指定的Boolean表达式值为true时才会处理其本体的内容,否则不执行。
    <c:choose>标记用来处理多个可选条件下的选择。<c:choose>标记需要和<c:when>、<c:otherwise>标记配套使用,并且<c:when>和<c:otherwise >必须依附在<c:choose>标签下。
    6.
    1.	说明如何使用JSTL所提供的<sql:setDataSource>标签设置联机信息。
    答:
    使用<sql:setDataSource>标记来指定数据源,其语法为:
    <sql:setDataSource  
    { dataSource=“dataSource”  |  url=“jdbcUrl” 
    [driver=“driverClassName”] 
    [user=“userName”] 
    [password=“password”] }
    [var=“varName”] 
    [scope=“{page|request|session|application}”] />
    url属性用于指定连接的url。driver属性用于指定驱动程序。
    dataSource属性为数据源。
    
    7.
    答:pageScope]、[requestScope]、[sessionScope]及[applicationScope]。
    
    8.
    答:隐含对象param与paramValues被设计用来提供使用request之外的一个选择,这两个对象最大的好处便是简化了request参数数据的存取,其功能相对于request对象如下表所示:
    EL对象	Request对象
    ${param.paraName}	request.getParameter(paraName)
    ${paramValues.paraName }	request.getParameterValues(paraName)
    
    以下为取值的范例程序:
    ${param.yearValue }
    param内容包含当前网页所有的request参数,这段程序代码取得其中名为yearValue的参数值。
    

    五. 编程

    1. 使用JSTL标准标记库中的标记输出1~100的数字之和。

    提示:本程序所使用的JSTL核心标记库的uri为http://java.sun.com/jsp/jstl/core。

    2. 使用标准标签库中的<c:foreach>标签、<c:if>标签和<c:out>标签列出1~100中能被2整除不能被3整除的数字。

    图15-11 带body的标签

     

     

     

    展开全文
  • 栈帧和函数调用()一,函数调用惯例,_cdecl三,_stdcall四,总结      通过上文的介绍,我们大致知道了函数调用时实际发生了什么,以及为什么我们使用编译器调试代码时,可以通过栈...

    (栈帧和函数调用二)_stdcall和_cdecl的区别

         通过上文的介绍,我们大致知道了函数调用时实际发生了什么,以及为什么我们使用编译器调试代码时,可以通过栈回溯看到整个调用的流程。从这样的信息里能够发现一个现象,那就是函数的调用方和被调用方对函数如何调用有这统一的理解,例如,它们双方都一致认同函数参数是按照某个固定的方式压入栈内的,如果不这样,那么函数无法取得正确的参数,这样的约定称为函数调用惯例。

    一,函数调用惯例

    1, 函数参数的传递顺序和方式
         函数参数的传递方式有很多种,最常见的也就是栈传递。函数的调用方将参数按照一定顺序压入栈中,函数自身再按照该顺序从栈中取出参数,参数压栈的顺序分为从左至右和从右至左。有些调用惯例还允许使用寄存器传递函数参数以提升性能(本章不讨论该情况)

    2, 栈的维护方式
         调用方将参数压入栈中,函数从栈中取出参数,并执行完函数体后,需要将压入栈中的参数进行弹出,以使得栈在函数调用前后保持一致,而这个操作既可以由函数调用方来完成,也可以由函数自身来完成。

    3, 函数名字修饰方式
         使用不同调用修饰符修饰的函数,会对函数名字进行不同策略的修饰,比如_cdecl修饰的函数名字直接在名称前加1个下划线(int fun(int a,int b) =>_fun),_stdcall修饰的函数名字是由下划线+函数名+@+参数的字节数(int fun(int a,int b) =>_fun@8)

    二,_cdecl

         在c/c++语言中,默认的函数调用规则是cdecl,任何一个没有显示指定调用规则的函数默认都是使用cedecl修饰的,它将参数以 从右至左的顺序压入栈中,出栈操作也是由函数调用方来执行的。
    以以下函数为例:

    int _cdecl fun(int a, int b)
    {
    	return 1;
    }
    
    

         Fun(1,2),调用处的反汇编代码为:
    在这里插入图片描述
         先将参数2入栈,再将参数1入栈,再执行函数体,函数体内反汇编为:
    在这里插入图片描述
         我们只用看最后一条指令ret,是直接返回到函数调用处的,也就是push 1下面的那个栈地址,参数a和b的栈空间并没有被fun函数自己清理掉,而是被调用方清理了,再回过去看上上图的最后一行汇编代码:

    add esp,8
    

         将栈顶指针正向偏移8个字节,刚好将a参数和b参数所占用的8个字节给回收了(32位环境)

    三,_stdcall

         Stdcall是从pascall发展来的一种函数调用方式,它不是c/c++默认的调用方式,我们使用的时候需要显示加上_stdcall修饰符。它将参数以从右至左的顺序压入栈中,出栈操作也是由函数内部来执行的。
    以以下函数为例:

    int _stdcall fun(int a, int b)
    {
    	return 1;
    }
    
    

         Fun(1,2),调用处的反汇编代码为:
    在这里插入图片描述
         先将参数2入栈,再将参数1入栈,再执行函数体,函数体内反汇编为:
    在这里插入图片描述
         直接看最后一个ret指令,可以看到参数为8,也就是说函数体内自动将传入的int a,int b两个参数的栈空间给回收了,跳转了函数返回地址的正向偏移8字节的位置。

    四,总结

    1, 微软使用__stdcall来定义Win32 API,因为理论上__stdcall比较节省空间,两者比较计算如下:
    __stdcall消耗的空间是:
    ret X(X是一个地址,在32位系统为4字节),这样就是1字节(ret)+4字节(地址)=5字节
    __cdecl消耗的空间是
    (被呼叫者)ret
    (呼叫者)add esp,x 这样就是(ret)1字节+add esp(1字节)+X(4字节)=6字节

    2, 可变参数的函数只能用_cdecl而不能用_stdcall,是因为_stdcall修饰的函数参数所占用的栈空间是由函数自身来清理的,对于可变参数的情况,函数是不确定有多少入参的,不能准确清理栈空间。

    3, 使用_stdcall还是_cdecl是由函数调用方和函数方两者结合使用场景共同决定的,只要双方统一了调用规定,那么使用就是没问题的(不要认为dll中只能用_stdcall)

    参考文献:
    1,《程序员的自我修养:链接、装载与库》第十章第二节

    展开全文
  • io_uring技术的分析与思考

    千次阅读 多人点赞 2020-12-03 00:56:18
    io_uring是Linux 5.1引入的一套新的syscall接口,用于支持异步IO。近来这套机制颇受关注,很多人认为它代表了与内核...linux下,目前绝大部分程序的IO操作都是同步的,最后通过read/write系列的系统调用实现对

    io_uring是Linux 5.1中引入的一套新的syscall接口,用于支持异步IO。近来这套机制颇受关注,很多人认为它代表了与内核实现高性能交互的一种模式。本文将对io_uring的原理和实现进行分析,了解其相对于原有IO机制的优势,并尝试预测其应用场景和发展趋势。

    异步IO机制

    在介绍io_uring之前,需要先了解一下其实现的异步IO机制,以及io_uring之前的异步IO是如何实现的。

    在linux下,目前绝大部分程序中的IO操作都是同步的,最后通过read/write系列的系统调用实现对文件的读写。同步IO的性能受限于文件类型和底层的设备性能,还有可能造成线程阻塞,在要求实时性的场景下显然不能满足需求。为此,出现了多种异步IO的实现机制,来解决实时IO的问题。异步IO是一种IO接口类型,调用这种类型的接口进行IO操作,可以在IO操作实际完成之前就返回,而不会阻塞等待。常见的异步IO实现方式有3种:

    • POSIX AIO。这种方案的实现可在linux手册中看到:https://www.man7.org/linux/man-pages/man7/aio.7.html。这套方案在glibc中提供,通过使用pthread库创建用户态多线程的方式实现异步IO的接口,最后调用的IO syscall仍然是内核的同步接口。在手册中写道,“这套机制局限性很大,最显著的一点就是使用多线程实现异步IO的效率和可扩展性太差”。因此,手册中还提到了下一种异步IO方案。
    • LINUX AIO。这套方案是linux内核提供的接口,名字也叫AIO。这套方案是io_uring出现前Linux内核支持异步IO的唯一接口,由于glibc中已经提供了同样名为AIO的机制,因此没有为其提供封装,需要通过专门的libaio库进行调用。io_uring的开发者,也是Linux内核IO部分的主要maintainer,Jens Axboe在Efficient IO with io_uring这篇介绍io_uring的文章中分析了Linux AIO的缺陷:AIO最大的局限性是只支持direct IO,这不仅导致程序无法使用cache,更让程序无法使用普通的malloc/new等方式分配的内存用于IO,而必须使用mmap方式直接分配4K对齐的页。在绝大部分情况下,这显然是无法实现的,因为即使开发者在自己的代码中管理内存分配,却无法控制引用的各类库和包的内存管理方式,因此在大部分情况下AIO没有实用价值。此外AIO在某些场景下仍然会退化为阻塞调用,其接口传递的参数过大因此效率也不高。因此linux社区一直认为“这套AIO机制不够成熟,还不能将glibc中的POSIX AIO接口改用这套机制实现”。
    • 事实上,当前主流的异步IO模型,大多是程序直接根据程序逻辑实现的。例如异步日志,就是在主要的工作线程中将需要写的日志内容写入一个专门的buffer队列中,再由另一个专门的日志写入线程将队列内容写入文件。也有一些库能够实现这样的功能,例如log4j2。本质上这种实现与POSIX AIO的原理是一致的,但通过结合程序的实现功能需求和配置,就避免了通用的AIO机制带来的过多线程创建管理开销。

    IO_URING

    现有的内核AIO机制经过多年的开发,仍然存在大量的问题。内核维护者认为已有机制问题太多,使用场景太少,早期设计时没有考虑到异步IO的实际需求,在其基础上开发新特性已经没有意义。因此决定针对AIO机制开发中发现的一系列问题,从头开发一套新的异步IO机制,称作io_uring。根据笔者的理解,uring这个朴实的名字就是user和ring的意思,这两者也是io_uring机制的核心。io_uring的高效性就是建立在使用用户态(user-space)可访问的无锁环形队列(ring)的基础之上的。开发者Jens Axboe在Efficient IO with io_uring中详细介绍了io_uring的设计思想和使用方式,在Linux异步IO新时代:io_uring中对其内容做了概括,【译】高性能异步 IO — io_uring(Effecient IO with io_uring)是其中文翻译(建议参考原文阅读)。

    设计目标

    作者在文章中明确列出了io_uring的设计目标:

    • 易用。从笔者的角度来看,与现有的IO接口相比,io_uring相关syscall接口其实并不算易用,甚至理解起来也不算容易。作者自己也说,这些设计目标之间是有冲突的,特性丰富、高效还可伸缩的接口必然是很难用的。为了解决这个问题,作者为io_uring开发了一个配套的库liburing。既然支持全部需求的接口对于一般开发者来说使用难度过高,那就对其中最常用的部分再封装一层,提供一个更简单易用的接口。使用liburing无法使用io_uring全部的功能,特别是一些为高性能目标设计的功能,但能够使用一套风格与io_uring类似,但简单的多的接口来使用io_uring的基本功能,这对于大部分开发者来说也已经足够了。对于需要高级特性的开发者来说,也可以在使用liburing的基础上调用io_uring syscall接口来获取自己需要的特性,因为这类开发者一般也不会同时需要所有高级特性,而只是使用其中很小的一部分。这个设计方式值得我们学习,如何解决功能强大和接口易用之间的矛盾,“加一个中间层”永远是一个有效的思路。
    • 可扩展。这里的可扩展指的是io_uring操作的IO设备类型是可扩展的,io_uring实现的异步接口不止能够用于块设备,也能够支持socket网络IO等非块设备,后续还可能支持更多fd类型,从接口语义方面没有限制。
    • 特性丰富。这一项是针对linux aio机制的局限性而来的。aio机制由于支持的特性不多,使用限制却很多,因此使用场景非常有限。作者的目标是在所有需要异步IO的场景都能够使用io_uring接口,并且不需要程序本身做架构级别的调整。
    • 高效。这里的高效主要体现在两个方面:一是每次调用io_uring系统调用接口的开销要小,这里主要是和aio相比减少了每次调度传递的参数大小;二是减少io_uring系统调用的次数,这是io_uring最重要的设计之一,通过一次系统调用提交多个IO请求的方式,io_uring可以大幅减少系统调用次数,这在spectre/meltdown修复导致系统调用开销显著上涨的背景下更加重要。
    • 可伸缩。作者对这个目标的解释是允许使用者获得尽可能好的IO性能。一般对伸缩性的理解是能够使用更多的CPU核心或其他资源来提升性能,但从io_uring的接口来看,似乎是不能支持多核并发操作的,而且并发调用异步IO接口也没有什么意义。笔者理解这里的伸缩性可能是指可以通过不同的使用模式来获得更好的IO性能。io_uring在用户态和内核态都支持轮询(polling)模式,可以在不调用syscall的情况下直接处理IO请求和结果,代价是在IO请求不需要全部CPU资源时会浪费一些计算资源。这就相当于是使用更多的CPU资源来获取最佳的IO性能,也可以理解为是一种伸缩性了。

    原理与结构

    io_uring的原理是让用户态进程与内核通过一个共享内存的无锁环形队列进行高效交互。相关的技术原理其实与DPDK/SPDK中的rte_ring以及virtio的vring是差不多的,只是这些技术不涉及用户态和内核态的共享内存。高性能网络IO框架netmap与io_uring技术原理更加接近,都是通过共享内存和无锁队列技术实现用户态和内核态高效交互。但上述的这些技术都是在特定场景或设备上应用的,io_uring第一次将这类技术应用到了通用的系统调用上。

    共享内存

    为了最大程度的减少系统调用过程中的参数内存拷贝,io_uring采用了将内核态地址空间映射到用户态的方式。通过在用户态对io_uring fd进行mmap,可以获得io_uring相关的两个内核队列(IO请求和IO完成事件)的用户态地址。用户态程序可以直接操作这两个队列来向内核发送IO请求,接收内核完成IO的事件通知。IO请求和完成事件不需要通过系统调用传递,也就完全避免了copy_to_user/copy_from_user的开销。

    无锁环形队列

    io_uring使用了单生产者单消费者的无锁队列来实现用户态程序与内核对共享内存的高效并发访问,生产者只修改队尾指针,消费者只修改队头指针,不会互相阻塞。对于IO请求队列来说,用户态程序是生产者内核是消费者,完成事件队列则相反。需要注意的是由于队列是单生产者单消费者的,因此如果用户态程序需要并发访问队列,需要自己保证一致性(锁/CAS)。

    内存屏障与保序

    使用共享内存和无锁队列最需要注意的就是保证内存操作的顺序和一致性。这部分内容在Efficient IO with io_uring中做了简单的介绍。简单的说就是要保证两点:

    1. 修改队列状态时,必须保证对队列元素的写入已经完成。这时需要调用write barrier来保证之前的写入已经完成。在x86架构上这一点其实是针对编译器优化的,防止编译器将修改队列状态的指令放到队列元素写入完成之前。

    2. 读取队列状态时,需要获取到最新写入和修改的值。这时需要调用read barrier来保证之前的写入都能被读取到,这主要是对缓存一致性的刷新。

    内存屏障在不同架构的CPU上有不同的实现和效果,要正确使用需要对CPU和编译器有一定了解。在liburing中已经屏蔽了这些细节,因此建议一般情况下使用liburing来实现对队列的操作。

    轮询模式

    io_uring提供了io_uring_enter这个系统调用接口,用于通知内核IO请求的产生以及等待内核完成请求。但这种方式仍然需要反复调用系统调用,进行上下文切换,并在内核中唤醒异步处理逻辑去处理请求。显然这种方式会产生额外的开销,而且受限于系统调用速率,无法发挥IO设备的极限性能。为了在追求极致IO性能的场景下获得最高性能,io_uring还支持了轮询模式。轮询模式在DPDK/SPDK中有广泛应用,这种模式下会有一个线程循环访问队列,一旦发现新的请求和事件就立即处理。

    对于用户态程序来说,轮询只需要一个线程持续访问请求完成事件队列即可。但这个层次的轮询只是轮询了io_uring的队列,但内核从IO设备获取完成情况仍然是基于设备通知的。通过在初始化时设置IORING_SETUP_IOPOLL标志,可以将io_uring配置为IO设备轮询模式。在这种模式下,调用io_uring_enter获取完成事件时,内核会使用轮询方式不断检查IO设备是否已经完成请求,而非等待设备通知。通过这种方式,能够尽可能快的获取设备IO完成情况,开始后续的IO操作。

    同时,在内核中还支持了一个内核IO模式,通过IORING_SETUP_SQPOLL标志设置。在这个模式下,io_uring会启动一个内核线程,循环访问和处理请求队列。内核线程与用户态线程不同,不能在没有工作时无条件的无限循环等待,因此当内核线程持续运行一段时间没有发现IO请求时,就会进入睡眠。这段时间默认为1秒,可以通过参数sq_thread_idle设置。如果内核线程进入睡眠,会通过IO请求队列的flag字段IORING_SQ_NEED_WAKEUP通知用户态程序,用户态程序需要在有新的IO请求时通过带IORING_ENTER_SQ_WAKEUP标识的io_uring_enter调用来唤醒内核线程继续工作。

    需要注意的是,如果IORING_SETUP_IOPOLL和IORING_SETUP_SQPOLL同时设置,内核线程会同时对io_uring的队列和设备驱动队列做轮询。在这种情况下,用户态程序又不需要调用io_uring_enter来触发内核的设备轮询了,只需要在用户态轮询完成事件队列即可,这样就可以做到对请求队列、完成事件队列、设备驱动队列全部使用轮询模式,达到最优的IO性能。当然,这种模式会产生更多的CPU开销。

    调用接口

    上文提到,io_uring使用两个队列来传递IO请求和完成情况,这两个队列中的元素结构如下:

    // Submission Queue Entry
    struct io_uring_sqe {
       __u8 opcode;        //请求类型,例如IORING_OP_READV
       __u8 flags;         //
       __u16 ioprio;       //优先级,和ioprio_set系统调用的作用类似
       __s32 fd;           //需要操作的文件fd
       __u64 off;          //文件偏移位置
       __u64 addr;         //读写数据地址,如果是readv/writev请求则是iovec数组地址
       __u32 len;          //读写数据长度,如果是readv/writev请求则是iovec数组长度
       union {
         __kernel_rwf_t rw_flags;    //请求相关的选项,其含义与对应的blocking syscall相同,例如preadv2
         __u32 fsync_flags;
         __u16 poll_events;
         __u32 sync_range_flags;
         __u32 msg_flags;   
       };
       __u64 user_data;    //使用者任意指定的字段,在复制到对应的cqe中,一般用于标识cqe与sqe的对应关系。
       union {
         __u16 buf_index;
         __u64 __pad2[3];
       };
    };
    
    // Completion Queue Event
    struct io_uring_cqe {
       __u64 user_data;    //来自对应的sqe中的user_data字段
       __s32 res;          //请求处理结果,和普通IO操作的返回值差不多。一般成功时返回字节数,处理失败时返回-errno。
       __u32 flags;        //暂未使用
    };
    

    io_uring有3个系统调用接口,分别是:

    • io_uring_setup,创建io_uring。
    • io_uring_enter,通知内核有IO请求待处理,并根据参数等待请求完成。
    • io_uring_register,注册fd和buffer为常用对象,避免内核反复操作。

    io_uring_setup

    原型为:

    int io_uring_setup(unsigned entries, struct io_uring_params *params);

    这个函数返回一个io_uring的fd,后续通过这个fd来操作io_uring。entries是创建出的io_uring中包含的sqe(请求)数量,必须是1-4096间的2的幂级数。io_uring_params是一个与内核的交互参数,用户态调用者在其中指定需要的参数,内核也在其中反馈实际创建的情况,其定义和解释如下:

    struct io_uring_params {
        __u32 sq_entries;                    /* IO请求sqe数量,内核输出 */
        __u32 cq_entries;                    /* IO完成事件cqe数量,内核输出 */
        __u32 flags;                         /* io_uring运行模式和配置,调用者输入 */
        __u32 sq_thread_cpu;
        __u32 sq_thread_idle;
        __u32 resv[5];                       /* 预留空间,用于对其cacheline,同时为将来扩展留下空间 */
        struct io_sqring_offsets sq_off;     /* sqe队列的偏移地址 */
        struct io_cqring_offsets cq_off;     /* cqe队列的偏移地址 */
    };
    
    struct io_sqring_offsets {
       __u32 head;            /* offset of ring head */
       __u32 tail;            /* offset of ring tail */
       __u32 ring_mask;       /* ring mask value */
       __u32 ring_entries;    /* entries in ring */
       __u32 flags;           /* ring flags */
       __u32 dropped;         /* number of sqes not submitted */
       __u32 array;           /* sqe index array */
       __u32 resv1;
       __u64 resv2;
    };
    
    

    这里需要关注的是io_sqring_offsets和io_cqring_offsets。这是内核分配的ring结构中需要用户态操作部分的相对偏移,用户态程序需要使用mmap将ring结构的内存映射到用户态来供后续交互:

    struct app_sq_ring {
        unsigned *head;
        unsigned *tail;
        unsigned *ring_mask;
        unsigned *ring_entries;
        unsigned *flags;
        unsigned *dropped;
        unsigned *array;
    };
    
    struct app_sq_ring app_setup_sq_ring(int ring_fd, struct io_uring_params *p)
    {
        struct app_sq_ring sqring;
        void *ptr;
        ptr = mmap(NULL, p→sq_off.array + p→sq_entries * sizeof(__u32),
        PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE,
        ring_fd, IORING_OFF_SQ_RING);
        sring→head = ptr + p→sq_off.head;
        sring→tail = ptr + p→sq_off.tail;
        sring→ring_mask = ptr + p→sq_off.ring_mask;
        sring→ring_entries = ptr + p→sq_off.ring_entries;
        sring→flags = ptr + p→sq_off.flags;
        sring→dropped = ptr + p→sq_off.dropped;
        sring→array = ptr + p→sq_off.array;
        return sring;
    }
    

    这里的一个疑问是为什么要让用户态程序再调用一次mmap,而不是在内核中就将地址映射好直接返回,这显然让接口的使用复杂度上升了很多。笔者认为这么做唯一的意义在于尽量保留了用户态程序对地址空间的控制力,可能在一些特殊场景下程序会需要特定的地址空间用于特殊用途,内核直接映射可能引入难以发现的问题。为了解决接口易用性的问题,liburing中封装了io_uring_queue_init接口,对于没有上述特殊需求的程序,直接使用这个接口即可。

    io_uring_enter

    原型为:

    int io_uring_enter(unsigned int fd, unsigned int to_submit, unsigned int min_complete, unsigned int flags, sigset_t sig);

    在程序向sqring,即请求队列中插入了IO请求后,需要通知内核开始处理,这时就需要调用io_uring_enter。参数中的fd是io_uring的fd,to_submit是提交的IO请求数。

    min_complete可以用来阻塞等待内核完成特定数量的请求,前提是flags中设置IORING_ENTER_GETEVENTS。这个功能可以单独调用来等待内核处理完成。需要注意的是由于采用共享内存队列的方式来同步请求完成情况,因此程序也可以不使用这个接口而是直接判断cqring的状态来获取IO完成情况并处理cqring中的完成事件。

    io_uring_register

    原型为:

    int io_uring_register(unsigned int fd, unsigned int opcode, void *arg, unsigned int nr_args);

    这个syscall用于支持一些高级的优化用法,主要有两种模式,opcode分别为:

    • IORING_REGISTER_FILES。内核异步处理sqe请求时,需要保证fd不会在处理过程中被关闭,因此需要在开始处理前增加fd引用计数,结束后再减少。而调用这个接口后就可以避免这种反复的引用计数操作。在调用后指定的文件fd的引用计数会增加,后续提交请求时只要在sqe的flags中指定IOSQE_FIXED_FILE就不会再修改引用计数。如果不再需要操作这个fd,可以用IORING_UNREGISTER_FILES这个opcode解除注册。
    • IORING_REGISTER_BUFFERS。在使用O_DIRECT模式时,内核需要先映射用户态的页面,处理完后再解除映射,这也是一种重复开销。使用这个opcode后,就可以把指定的buffer页面固定映射到内核中,处理请求时就不需要反复映射、解除映射。

    liburing

    上文中提到,由于io_uring要实现强大的功能和最优的效率,因此其接口和使用方式会比较复杂。但对于大部分不需要极致IO性能的场景和开发者来说,只使用io_uring的基本功能就能获得大部分的性能收益。当只需要基本功能时,io_uring的复杂接口中很大一部分是不会使用的,同时一部分初始化操作也是基本不变的。因此,io_uring的作者又开发了liburing来简化一般场景下io_uring的使用。使用liburing后,io_uring初始化时的大部分参数都不再需要填写,也不需要自己再做内存映射,内存屏障和队列管理等复杂易错的逻辑也都封装在liburing提供的简单接口中,大幅降低了使用难度。

    io_uring的创建与销毁

    在liburing中封装了io_uring的创建与销毁操作接口,几乎不需要指定任何参数即可完成创建:

    struct io_uring ring;
    io_uring_queue_init(ENTRIES, &ring, 0);
    
    io_uring_queue_exit(&ring);

    提交请求与处理完成事件

    struct io_uring_sqe sqe;
    struct io_uring_cqe cqe;
    /* get an sqe and fill in a READV operation */
    sqe = io_uring_get_sqe(&ring);
    io_uring_prep_readv(sqe, fd, &iovec, 1, offset);
    /* tell the kernel we have an sqe ready for consumption */
    io_uring_submit(&ring);
    /* wait for the sqe to complete */
    io_uring_wait_cqe(&ring, &cqe);
    /* read and process cqe event */
    app_handle_cqe(cqe);
    io_uring_cqe_seen(&ring, cqe);

    上面这段代码是io_uring作者提供的样例,其中体现了几个关键操作接口:

    • io_uring_get_sqe(&ring),从请求队列中获取一个空闲的请求结构。
    • io_uring_prep_readv(sqe, fd, &iovec, 1, offset),构造一个readv读请求。
    • io_uring_submit(&ring),将请求提交给内核。
    • io_uring_wait_cqe(&ring, &cqe),等待请求完成。这是一个阻塞操作,还有一个非阻塞版本:io_uring_peek_cqe。
    • io_uring_cqe_seen(&ring, cqe),通知内核已经完成对完成事件的处理。

    通过这些接口,开发者已经能够很容易的写出异步IO的代码。

    具体实现

    上文已经介绍了io_uring的接口和基本使用方法,以及io_uring的技术原理。这里再讨论一下io_uring在内核中的实现。笔者认为,以前没有在内核中支持这类接口是有原因的,让用户态程序与内核共享内存、并发访问和修改同一数据结构,是一种危险行为。如果不能妥善的控制共享内存的操作权限,完整覆盖各种并发操作、特别是用户态异常操作的内核处理逻辑,就很可能让用户态程序能够通过这个机制破坏内核状态,造成严重错误和漏洞。因此,与技术原理相比,io_uring的具体实现更加重要,我们需要了解io_uring是如何保障其可靠性和安全性的。

    风险分析与解决思路

    在分析代码之前,我们先分析一下io_uring机制存在的风险以及可能的规避方式。

    使用共享内存的ring进行同步,逻辑上并不复杂,但共享内存的结构如果损坏,内核在处理这个结构时就可能出现错误,造成内核崩溃等问题。结构损坏可能有几种:

    1. ring的head/tail指针错误。这会导致内核处理没有设置过的请求sqe。由于sqe是内核预分配的内存,因此这个操作不会造成内核访问非法内存地址。如果sqe中的参数是非法的,内核会直接生成错误事件,如果参数合法,则会按参数执行IO。这种错误的影响和使用了错误的syscall参数是差不多的,对内核不会产生严重影响。

    2. ring的mask/entries/flags被错误修改。由于对ring内的entry数组访问以及一些特性实现和这些元素是强相关的,如果这些内存被错误修改,就可能造成内核严重异常。但这些元素在创建io_uring时就已经确定了,内核可以单独为每个io_uring单独保存一份用于实际处理逻辑,而不使用共享内存中的部分。这样就可以避免用户态修改对内核产生影响。

    3. sqe的内容在内核处理时被修改。这个情况比较复杂,理论上有可能做到对sqe的元素都只做单次访问,从而避免元素值变化造成的逻辑异常。但由于io_uring支持的操作类型和特性很丰富,可能很难实现这一点。因此更可行的方式是在处理sqe前直接复制一份,之后只访问复制的sqe参数。

    内核实现

    io_uring的实现在fs/io_uring.c中,这是一个长达9300行的c文件。。。

    SYSCALL_DEFINE2(io_uring_setup),即sys_io_uring_setup是io_uring_setup系统调用的实现函数。可以看到,在创建io_uring时,内核创建了两个数据结构io_ring_ctx和io_rings。其中io_rings就是和用户态共享内存的ring结构,包含了ring的head、tail指针,mask、entries以及sq_off、cq_off中的其他字段。而io_ring_ctx中则包含了那些不能被修改的参数。和我们在上一节分析的一样,内核将不应被修改的部分参数在内核专用的io_ring_ctx结构中保存了一份,内核实际访问的是io_ring_ctx中的元素,而不是和用户态共享的io_rings中的元素。这就避免了共享的关键参数被修改可能导致的问题。事实上,io_ring_ctx中还包含了sq_ring的head和cq_ring的tail这两个应该由内核控制的ring参数,内核只会根据io_ring_ctx中的这两个值来访问ring,并将修改后的值写回到io_rings中。因此用户态修改这些值不会对内核逻辑产生影响,而是会被内核不断修正。

    SYSCALL_DEFINE6(io_uring_enter),即sys_io_uring_enter是io_uring_enter系统调用的实现函数。在主要实现逻辑io_submit_sqes函数中,会为每一个待处理的sqe分配一个io_kiocb结构,并将sqe中的请求参数逐个复制到io_kiocb中,后续真正实现io请求时访问的是io_kiocb,因此sqe被修改也不会对io处理逻辑产生影响。

    值得注意的是,io_uring_enter中并不一定是完全异步化的处理sqe中的IO请求,只有当sqe中设置了REQ_F_FORCE_ASYNC时才会立即将对应的io_kiocb加入异步队列,否则会尝试启动文件的异步IO操作,只有当文件不支持异步模式时才会将其加入异步队列。这部分逻辑理解的不是很透彻,需要进一步阅读代码。

    小结

    本文分析了io_uring的原理、接口、用法和实现。io_uring提供了复杂而强大的异步IO接口,同时又实现了liburing来屏蔽高级特性带来的接口复杂性和使用难度。io_uring展示了一种新的可能性,即通过共享内存的方式与内核进行高性能的交互,而避免大量的syscall带来的性能开销和限制。未来,这种模式也可以被用于加速其他实时性要求不高的系统调用。

    展开全文
  • 调用约定__cdecl、__stdcall和__fastcall的区别

    万次阅读 多人点赞 2018-08-26 21:12:08
    什么是调用约定 函数的调用约定,顾名思义就是对函数调用的一个约束和规定(规范),描述了函数参数是怎么传递和由谁清除堆栈的。它决定以下内容:(1)函数参数的压栈顺序,(2)由调用者还是被调用者把参数... Apple...
  • MKS GEN_L V2.1 Klipper固件使用说明书

    万次阅读 多人点赞 2021-11-02 16:25:18
    文章目录一、产品简述1.1特点优势1.2主板参数1.3接线图1.4尺寸图、固件下载、更新2.1固件下载2.2 使用Xloader更新固件三、驱动跳线设置3.1 A4988驱动跳线设置3.2 TMC2208、TMC2209、TMC2226普通模式跳线设置3.3TMC...
  • Nginx性能提升 - open_file_cache指令

    千次阅读 2019-02-19 14:14:16
    今天我们使用 open_file_cache 指令来尝试提高我们的nginx服务性能 前置工具 strace常用来跟踪进程执行时的系统调用和所接收的信号, 是一个强大的工具。 因为这里本人使用的是mac系统, 对应的mac分析命令 dtruss ...
  • 选择题 PC存放的是下一条指令地址,故PC的位数与(主存地址寄存器MAR )的位数相同 用以指定待执行指令所在...多周期CPU,( 一条指令的功能通过执行一个微程序来实现 ) 相对于微程序控制器,硬布线控制器的特点
  • 开头的名称并不是指令的助记符,不会被翻译成机器指令,而是给汇编器一些特殊指示,称为汇编指示(Assembler Directive)或伪操作(Pseudo-operation),由于它不是真正的指令所以加个“伪”字。.section指示把代码...
  • 英飞凌XC2000系列CAN BootLoader(CAN_BSL)的实现

    千次阅读 热门讨论 2019-09-06 10:53:14
    英飞凌多个系列的单片机都提供了BootLoader机制,即能够不连接烧写器的情况下,通过CAN、UART等传输协议实现自身程序的更新,便于产品使用过程软件的更新迭代。我这次用的是XC2000系列单片机,基于CAN实现...
  • 作业_进制炸弹_手把手教学讲解

    万次阅读 多人点赞 2020-11-09 13:55:52
    作为实验目标的进制炸弹“binary bombs” Linux可执行程序包含了多个阶段(或关卡),每个阶段程序要求你输入一个特定字符串,如果输入满足程序代码所定义的要求,该阶段的炸弹就被拆除了,否则程序输出“炸弹...
  • #pragma data_seg用法总结

    千次阅读 2017-03-30 22:23:50
    Windows一个Win32程序的地址空间周围筑了一道墙。通常,一个程序的地址空间的数据是私有的,对别的程序而言是不可见的。但是执行STRPROG的多个执行实体表示了STRLIB程序的所有执行实体之间共享数据是毫无问题...
  • 支持云端升级的固件, flash 会分为 2 个区,一个用来运行程序,一个用来保存升级固件, 当运行 user1 时升级,程序会下载固件到 user2,下载完毕后,下次启动时从 user2 启动,依次替换,实现云端升级。...
  • cx_freeze的安装使用

    万次阅读 2018-07-20 16:49:47
    python程序几乎可以所有常见的平台进行使用,而且大部分无需修改任何代码!不过,python也有一点点小缺憾(这个是由于自身本质决定,不能叫缺憾,不过这就这么称呼吧),那就是python程序的执行必须要有解释器...
  • TEXT_OFFSET 内核RAM的起始位置相对于RAM起始地址偏移。值为0x00008000 ./arch/arm/Makefile 118 textofs-y := 0x00008000 222 TEXT_OFFSET := $(textofs-y) PAGE_OFFSE 内核镜像起始虚拟地址。值为0xC...
  • 取指周期:根据PC的内容取出指令代码并存放在IR 间址周期:根据IR中指令地址码取操作数有效地址 执行周期:根据指令字的操作码和操作数进行相应的操作 中断周期:保存断点,送中断向量,处理中断请求 四个工作...
  • gcc的__builtin_函数介绍

    万次阅读 多人点赞 2015-04-08 23:02:19
    第一个参数addr是要预取的数据的地址,第个参数可设置为0或1(1表示我对地址addr要进行写操作,0表示要进行读操作),第三个参数可取0-3(0表示不用关心时间局部性,取完addr的值之后便不用留cache,而1、2、3...
  • ),即编译生成的指令中val就已经被替换成100了,其实加const只是告诉编译器不能修改而不是真正地不可修改,如果程序员不注意而去修改了它会报错,现在我们利用const_cast去除了常量性,然后通过指针和引用对其...
  • nginx之proxy_pass指令完全拆解

    千次阅读 2018-07-09 17:53:46
    一、proxy_pass的nginx官方指南nginx有两个模块都有proxy_pass指令。ngx_http_proxy_module的proxy_pass:语法: proxy_pass URL; 场景: location, if in location, limit_except 说明: 设置后端代理服务器的协议...
  • u-boot relocate_code原理简单说明

    千次阅读 2016-12-18 18:12:38
    通俗地讲,uboot把内存的绝对物理地址固定进制文件里,所以uboot应该被拷贝到内存哪个地方,下一条指令应该跳转到哪个物理地址都是编译的时候就已经固定的。 2. 旧版本uboot的重定向 旧版本的...
  • 前面写了两篇关于杂耍把戏的手艺方面的文章: ...并不是很过瘾,因为当我将一个函数完整搬移到另一处的时候,我有意避开了采用相对地址寻址指令偏移校准 核心问题 ,还美其名曰为了简单。 失去...
  • 计算机组成原理,指令系统,练习题

    千次阅读 2021-07-16 00:14:08
    1、单项选择题1 CPU执行指令的过程指令地址由___B__给出。A 程序计数器PC B 指令地址码字段C 操作系统 D 程序员2 下列关于指令的功能及分类叙述正确的是__B___。A 算术与逻辑运算指令,通常完成算术运算或...
  • 冯诺依曼工作方式的基本特点是____

    万次阅读 2016-07-17 15:28:52
    冯诺依曼工作方式的基本特点是____ 正确答案: B 你的答案: B (正确) ...多指令流单数据流 ...按地址访问并顺序执行指令 ...(1)计算机处理的数据和指令一律用进制数表示 (2)顺序执行程序: 计算机
  • STM32_Programmer_CLI.exe基本命令介绍

    千次阅读 2020-09-13 00:41:38
    w32 写32位数据命令 说明: 将指定的32位数据从指定地址开始下载到闪存,注意不像下载指令-w会自动擦除扇区,-w32写指令要手动调用擦除扇区指令-e后才能写。 语法: -w32 <32_data_bits> :下载的起始地址。 <32_...
  • 应用程序具有3个基本段,可执行指令应该保存于__________。 代码段 如下符号_____________不是MASM支持的关键字。 done 汇编语言的优点不包括_____。 编程容易 编写汇编语言源程序文件,应使用______。 编辑程序 ...
  • nginx proxy_cache缓存详解

    千次阅读 2021-05-28 16:34:55
    1. 关于缓冲区指令 1.1 proxy_buffer_size 1.2 proxy_buffering 1.3 proxy_buffers 1.4 proxy_busy_buffers_size 1.5 proxy_max_temp_file_size 1.6 proxy_temp_file_write_size 1.7 缓冲区配置实例 ...
  • 1)实验平台:正点原子新起点V2开发板 2)平台购买地址:https://detail.tmall.com/item.htm?id=609758951113 ...FLASH存储器又称闪存,是一种长寿命的非易失性(断电情况下仍能保持所存储的数据
  • 个函数返回操作之前的值。 type __sync_lock_test_and_set(type *ptr, type value, ...) 将*ptr设为value并返回*ptr操作之前的值; void __sync_lock_release(type *ptr, ...) 将*ptr置为0 ...
  • open 函数定义: int open( const char * pathname, int flags); int open( const char * pathname,int flags, mode_t mode);...  mode: 用来规定对该文件的所有者,文件的用户组及系统其他用...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 192,698
精华内容 77,079
热门标签
关键字:

在二地址指令中_____是正确的