• request与response对象.


    request与response对象.

               1.

                     request代表请求对象

                     response代表的响应对象。                           

                    学习它们我们可以操作http请求与响应。

              2.request,response体系结构.

                                在我们Servlet中使用的request与response                        

                                         HttpServletRequest接口------>父接口  ServletRequest

                                         HttpServletResponse接口----->父接口  ServletResponse

                                在tomcat中它采用门面模式对requst,response进行操作.

                                对外提供使用的是 RequestFacade  ResponseFacade这两个类,

                                但是直正完成功能的是 Reqeust,Response类.

                       关于reqeust,response总结:

                                1.它的作用:

                                       request代表的是http请求对象,通过reqeust可以获取Http请求信息.

                                       response代表的是http响应对象,通过response可以设置响应信息。

                                2.在我们的servlet中使用的request,response是怎样来的?

                                     它是tomcat服务器帮助创建的,通过service方法传递到了我们的servle中。tomcat在创建request对象时,就将http请求中的信息封装到request中.

                                3.它们的体系结构

                                      ServletReqeust------>HttpServletReqeust-------->具体的实现类是由服务器创建的。tomcat中是 RequestFacade

                                      ServletResponse----->HttpServletResponse------->具体的实现类是由服务器创建的。tomcat中是 ResponseFacade

         


             HttpServletResponse对象.

                    它代表的是response响应对象,可以通过这个对象去操作http响应信息.

                           1.响应行

                                 响应行中重要的是状态码.

                                 response对象可以通过   setStatus(int num)方法去操作.

                           2.响应头

                                  setHeader()

                                  addHeader()

                                  setDateHeader();

                                  setIntHeader();

                         3.响应正文

                                 我们通过输出流,操作http响应中的响应正文:              

                                      1.获取到的字节流与字符流的类型。

                                                   字符流     PrintWriter out=response.getWriter();

                                                   字节流     ServletOutputStream sos=response.getOutputStream();

                                      2.字符流与字节流选择

                                               ~~字符流:操作文本:

                                               ~~ 字节流:如果信息没有改变,只是做copy操作,就选择字节流。操作二进制:图片,音频使用。

                                               我们需要手动在浏览器上显示信息时,一般会使用字符流。

    注意事项

                       1.在一个servlet中只能选择使用一种流,不能两个一起使用,因为它们是排斥的。

                       2.在servlet中使用完流后,流可以不关闭,tomcat服务器会自动检查,关闭流.

                       3.我们可以通过response获取输出流,向浏览器写一个页面。但是会出现乱码问题.

                          当用字节流输出时,我们为防止乱码,要设置两次编码格式:

                              response.setContentType("text/html;charset=UTF-8");

                              os.write(str.getBytes("UTF-8")); 

                          而用字符流输出时,一次就可以(这一句相当于两句)

                              response.setContentType("text/html;charset=UTF-8");

         响应头

               示例1:通过response去实现重定向.

                              设置状态码为302  设置location为指定的值.

                                    response.setStatus(302);

                                    response.setHeader("location",url);

                       注意:url是客户端路径。如果不写协议,那么要以/开头。这里是绝对路径基本格式是/工程名/资源路径.        

                       在开发中我们一般不使用上面的方式完成重定向,使用 response.sendRedirect(url);

                               原理            302+Lcoation

                                * 特点:   客户端发出2次请求

                                * 地址栏改变

                                * request 域中的数据不能共享

               示例2:通过response来控制响应头,完成指定时间跳转到指定页面.

                                         //带协议路径

                                         //response.setHeader("refresh", "3;url=http://localhost/day10/index.html");

                                         //不带协议路径

                                         //response.setHeader("refresh", "3;url=/day10/index.html");

                                         在开发中如果要完成跳转操作,一般很少在服务器端完成,在客户端通过html就可以完成跳转换操作.

                                                   <meta http-equiv="refresh" content="5;url=/day10/index.html">

                                         如果要想在页面上显示时间变化,那么可以通过js完成操作.

                                                   <script type="text/javascript">

                                                            var time = 5;

                                                            var span;

                                                            var interval;

                                                            window.onload = function() {

                                                                     span = document.getElementById("num");

                                                                     span.innerHTML = time;

                                                                     interval=window.setInterval("show()", 1000);

                                                            };

                                                            function show() {

                                                                     time--;

                                                                     if(time==0){

                                                                               window.clearInterval(interval);

                                                                               return;

                                                                     }

                                                                     span.innerHTML = time;

                                                            }

                                                   </script>

                     

             实例3:控制浏览器禁止缓存当前文档内容

                             禁止使用缓存:通过三个header设置.

                                     response.setHeader("Cache-Control ", "no-cache");

                                     response.setHeader("Pragma", "no-cache");

                                     response.setDateHeader("Expires", -1);

                      

             response示例----动态验证码(代码不要求,要求会使用)à防止恶意注册与刷机。

    package cn.zl.response;
    
    
    import java.awt.Color;
    import java.awt.Font;
    import java.awt.Graphics;
    import java.awt.image.BufferedImage;
    import java.io.IOException;
    import java.util.Random;
    
    import javax.imageio.ImageIO;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    /**
     * 验证码输出
     * @author wangli
     *
     */
    public class AuthCodeServletDemo extends HttpServlet {
    
        public void doGet(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            int height=25,width=120;
            //1.得到一个图像缓冲区  BufferedImage
            BufferedImage bimage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            //2.得到一只画笔   Graphics
            Graphics g = bimage.getGraphics();
            //3.画矩形,填背景色   画干扰线条   画字符串
            //3.1画矩形框时,可以先调画笔颜色
            g.setColor(Color.BLUE);//先调画笔颜色
            g.drawRect(0, 0 , width, height);
            
            //3.2填充背景
            g.setColor(Color.YELLOW);//调画笔颜色
            g.fillRect(1,1, width-2, height-2);
            
            //3.3画干扰线条
            g.setColor(Color.GRAY);//调画笔颜色为灰色
            Random random = new Random();//因为要画随机线条,引入随机数
            for (int i = 0; i < 20; i++) {
                //random.nextInt(width)因为要确定x坐标不能超范围
                g.drawLine(random.nextInt(width), random.nextInt(height), random.nextInt(width), random.nextInt(height));
            }
            
            //3.4画随机字符串  先要控制字符颜色,及字体大小
            g.setColor(Color.RED);
            // Font.BOLD|Font.ITALIC 两种类型做迭加
            g.setFont(new Font("黑体",Font.BOLD|Font.ITALIC,20));
            
            for (int i = 0; i < 4; i++) {
                g.drawString(random.nextInt(9)+"",20+(i*20), 20);
            }
            
            //4.将画好的缓冲区的图像写入到浏览器中
            //4.1服务器要通过响应消息头,告知客户端,给它写的内容是一个一幅图片
            response.setHeader("Content-Type", "image/jpeg");
            
            //为了更好的让验证码,在客户端不要缓存,设置响应头,告诉客户端不要缓存
            response.setHeader("Cache-Control", "no-cache");
            response.setHeader("Pragma", "no-cache");
            response.setHeader("Expires", "-1");
            
            //4.2 写数据到浏览器   ImageIO
            ImageIO.write(bimage, "jpg", response.getOutputStream());
            
        }
    
        public void doPost(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            this.doGet(request, response);
    
        }
    
    }
    验证码


     


         request对象

           request获取http请求信息.

                1.获取http请求行中信息.

                       -1.获取请求方式

                               request.getMethod() ///GET  POSt                                            

                        -2.获取请求路径

                              request.getRequestURI();  //day10/requestDemo1    统一资源标识符

                              request.getRequestURL(); //http://localhost/day10/requestDemo1  统一资源定位符,统一资源标识符包含了统一资源定位符.定位符是唯一的定位了一个位置。

                       -3.获取请求协议

                              request.getProtocol();

               2.关于reqeust获取客户机信息.

                                     -1.得到客户机ip地址.

                                                            request.getRemoteAddr();

                                     -2.获取get请求时,请求参数.(了解)

                                                            request.getQueryString();

                                     -3.获取请求资源路径

                                                            getContextPath();   这个方法得到的是工程名,其实是虚拟目录名称.

                                                            /day10/requestDemo1

                                                            /day10---->工程名或虚拟目录.

                                                            /requestDemo1---->它代表的是资源路径

                                                            通过request.getRequestURI()-就得到了资源路径。

                                                            我们做url级别权限控制时,需要得到访问的资源路径。

             3.获取http请求头

                                long getDateHeader(String name)--如果value值是Date类型

                                String getHeader(String name)--根据name获取value值

                                Enumeration getHeaderNames() --获取所有的name值,返回的是Enumeration

                                Enumeration getHeaders(String name) --在http请求头中可能出现,一个name 对应多个value,这时可以使用getHeaders()。

                               int getIntHeader(String name) --如果value是int类型              我们在开发中应用比较多的是  getHeader()方法

               4.request获取请求参数

                             -1.String getParameter(String name)

                                                   根据请求参数中的name值获取对应的value值.

                              -2.String[] getParameterValues(String name);

                                                   操作多个值的组件,例如  checkbox。

                              -3.Enumeration getParameterNames();

                                                   获取请求参数中的所有name的值.

                              -4.Map<String,String[]> getParameterMap()

                                                   得到请求参数的name与value的map映射

                                     获取请求参数,它可以针对于post/get请求。

              5.关于请求参数的校验. 客户端验证与服务端验证

                   数据提交到服务器,我们在开发中在客户端需要进行校验.使用的是js,我们在服务器端也需要进行校验使用java代码.

                            我们需要在服务器端对获取的请求参数进行校验.

                                      1.非空校验

                                      2.规则校验            

             6.关于获取请求参数编码问题

                             响应编码----response.setContentType("text/html;charset=utf-8");

                             请求编码----request.setCharacterEncoding("utf-8");  

                     请求参数出现乱码的原因?

                                1.在页面上我们的编码是utf-8,那么我们传递到服务器时,请求参数中如果存在中文,那么就会以utf-8进行编码.

                                2.tomcat服务器本身默认编码是iso-8859-1,它得到请求参数时,以iso8859-1进行了解码操作.

                                3.我们在servlet中获取请求参数时,得到的就是乱码.

                     解决乱码!!

                                我们通过request.getParameter()去获取请求参数时,得到的是乱码,这时可以将数据以iso8859-1进行编码,在以utf-8进行解码.

                                对于post请求我们可以通过简化方式操作.          

                                如果请求方式是get,只能手动转换码 –》tomcat默认请求编码格式iso8859-1,所以我们只能先用iso8859-1解码,然后在用utf-8编码。                     

             7.request域对象.

                        ServletContext就一个域对象.

                         request的创建与销毁.

                                     当请求来的时候,tomcat服务器会创建request,response对象。

                                     当响应产生,request对象销毁。

                                     也就是说,每一次请求都是一个新的request。

                        request也是一个域对象,它也可以存取删除数据。

                                     setAttribute()

                                     getAttribute()

                                     removeAttribute();

                   请求转发----在服务器内部进行跳转。这时我们这几个servlet就共享同一个request对象,这就是request域作用范围。我们使用请求转发可以让多个servlet之间共享同一个request,那么我们如果想要在多个servlet之间进行信息传递,可以使用setAttribute().

                   ~~ 如果我们在request域中存储了信息,到其它的页面时,需要得到这个信息,这时我们就需要进行请求转发.                                       

                   ~~  请求转换的代码----  request.getRequestDispatcher("url").forward(request,response);

                    注意:url是服务器端路径。要以/开头。这里是绝对路径,基本格式是/资源路径.   

    请求转发与重定向的区别?

                       1.请求转换是服务器内部跳转,所有地址栏上的路径不会改变.重定向是浏览器在次发送请求,地址栏上的路径会发生改变.

                       2.请求转发只发送一次请求。重定向会发送两次请求.                                                  

                       3.请求转发只能在当前应用内部跳转.重定向可以在内部跳转也可以跳出当前应用.

                       4.请求转发时,因为是内部跳转。它的路径写法是   /资源路径。重定向,它的路径需要写   /工程名/资源路径.                                               

                       5.请求转发,可以共享reqeust。重定向不可能,因为每一次都是一个新的request。          

                       6.请求转换是通过reqeust发起  request.getRequestDispatcher().forward();

                          重定向  response发起      response.sendRedirect();              

        ----------------------------------------------------------------------------------------------------

             请求转发与包含  重定向

    1. 在实现包含时,会先将被包含进来的页面中的头信息清空。
    2. 在请求转发和重定向前,服务器会把response中的数据先全部清空。
    3. 请求转发,可以实现request域中数据共享,原因是一次请求。
     

    路径

    1 绝对路径与相对路径

    绝对路径就是以http开头,例如:http://localhost/hello/index.jsp,这就是绝对路径。但这并不是我们要研究的,我们要研究的是相对路径。

    相对路径需要有父路径,即相对路径相对的谁!例如:index.jsp、jspsindex.jsp,这都是相对路径。相对路径一定要有一个父路径,也就是说我们需要把相对路径转换成绝对路径。

    大多数情况下我们都是使用相对路径,而不是绝对路径。因为这有助与我们发布、部署项目。我们在本机上的主机名可能为127.0.0.1,但是当项目开发结束后会放到服务器机上,在公网上使用。这时的主机IP,以及域名就不再是我们现在使用的域名了。所以,相对路径要方便我们的项目移置。

    2 与客户端相关的相对路径

    与客户端相关的相对路径大多数都是在网页中,例如超链接、表单等。还有重定向指定的路径也是与客户端相关的路径。respnse.sendRedirect(“BServlet”),其中BServlet就是一个相对路径。

    相对路径分为两种,一种是以“/”开头,另一种是不以“/”开头。其中以“/”开头的相对路径表示其父路径是当前主机。不以“/”开头的相对路径表示其父路径是当前路径。

    例如response.sendRedirect(“/hello/BServlet”)以“/”开头,那么就是主机的相对路径,即主机地址加上相对路径:http://localhost/hello/BServlet。其中hello是上下文路径!

    例如<a href=”/hello/BServlet”>BSERVLET</a>,也是以“/”开头,而且超链接与重定向都是与客户端相关的路径,所以都是http://localhost/hello/BServlet。

    下面我们要讨论一下不以“/”开头的相对路径。它是比较让人头痛的相对路径!而且我们也不建议使用它!!!

    上面已经说了,不以“/”开头的相对路径是当前路径的相对路径,即父路径是当前路径。那什么又是当前路径呢?例如在http://localhost/hello/jsps/index.jsp页面中存在一个超链接,其内容为:<a href=”BServlet”>BSERVLET</a>,那么父路径就是http://localhost/hello/jsps/,也就是与当前index.jsp页面在同一父路径下:http://localhost/hello/jsps/BSERVLET。

    在http://localhost/hello/servlet/AServlet中的重定向语句为response.sendRedirct(“BServlet”),那么重定向的路径为:http://localhost/hello/servlet/BServlet

    <!-- 当前页http://localhost/day07_02/jsps/index.jsp -->
    
    <a href="a.jsp">A</a><!--   http://localhost/day07_02/jsps/a.jsp -->
    
    <a href="/b.jsp">B</a><!--   http://localhost/b.jsp -->
    
    <form action="a.jsp"><!--   http://localhost/day07_02/jsps/a.jsp -->
    
        <input type='submit'   value="Submit"/>
    
    </form>
    
    <form action="/b.jsp"><!--   http://localhost/b.jsp -->
    
        <input type='submit'   value="Submit"/>
    
    </form>

    在要注意,我们在基础班中学习过HTML,知道什么叫<base>元素了,<base>元素会影响当前页面中所有相对路径的父路径。

     <head>
    
        <base href="http://localhost/day07_02/">
    
      </head>
    
      <body>
    
        <!-- 当前页http://localhost/day07_02/jsps/index.jsp -->
    
        <a href="a.jsp">A</a><!--   http://localhost/day07_02/a.jsp -->
    
        <a href="/b.jsp">B</a><!-- http://localhost/b.jsp   -->
    
        <form action="a.jsp"><!--   http://localhost/day07_02/a.jsp -->
    
           <input type='submit' value="Submit"/>
    
        </form>
    
        <form action="/b.jsp"><!--   http://localhost/b.jsp -->
    
           <input type='submit' value="Submit"/>
    
        </form>
    
      </body>

    当页面中存在<base>时,那么不以“/”开头的相对路径都是<base>元素的href属性值加上相对路径。例如<base>元素的href属性值为http://localhost/day07_02/,页面中相对路径为a.jsp,那么相对路径转换成绝对路径后为:http://localhost/day07_02/a.jsp。也就是说在没有<base>时,是当前路径的相对路径,在有了<base>后,那么就是<base>的href属性值的相对路径了!

    注意,如果是以“/”开头的相对路径,永远都是主机的相对路径,即http://localhost/。

    3 与Tomcat(服务器)相关的相对路径

    与Tomcat相关的相对路径就是Tomcat内部的相对路径,例如在web.xml文件中的<url-pattern>元素的内容,还有请求转发时的路径,这些都是与Tomcat相关的相对路径。

    <url-pattern>/servlet/AServlet</url-pattern><!—http://localhost/day07_02/servlet/AServlet   -->

    <url-pattern>   /BServlet</url-pattern><!—http://localhost/day07_02/AServlet   -->

    在<url-pattern>中必须以“/”开头(除非使用了通配符),与Tomcat相关的相对路径,如果以“/”开头,那么父路径就是当前上下文路径。

    对于<url-pattern>没有什么可说的,因为它必须以“/”开头,所以容易理解。但是对于请求转发就不一样了。请求转发可以以“/”开头,也可以不以“/”开头!

    request.getRequestDispatcher("BServlet").forward(request, response);

    request.getRequestDispatcher("/BServlet").forward(request, response);

      以“/”开头表示相对上下文路径(http://localahost/day07_02),不以“/”开头,那么相对当前路径。

    4 规范路径的编写

      建议大家一律使用“/”开头来编写相对路径,无论是页面中,还是Servlet中,都以“/”开头来编写。

    各种URL地址的写法

        相对路径:
        绝对路径:推荐使用。必须以"/"开头
     
        绝对路径在使用时:如果地址给服务器端用的,"/"就代表当前应用。否则就需要加上当前应用名称。
     
        form的action:要加应用名称
        <a href=""/>:要加应用名称
        <img src=""/>:要加应用名称
        <script src=""></script>:要加应用名称
        <link href=""/>:要加应用名称
        HttpServletResponse.sendRedirect(String path):要加应用名称
        ServletContext.getRealPath(String url):不要加
        ServletRequest.getRequestDispatcher(String path):不要加

     4种获得表单数据 封装数据的方法

    package cn.zl.request.web;
    
    import java.beans.PropertyDescriptor;
    import java.io.IOException;
    import java.lang.reflect.Field;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import java.util.Enumeration;
    import java.util.Map;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.apache.commons.beanutils.BeanUtils;
    
    import cn.zl.request.domain.User;
    /*
     * 4种得到浏览器表单方法 
     * 
     */
    public class UserServlet1 extends HttpServlet {
    
        public void doGet(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            //1.用request接收数据 封装到user中    使用getParameter
            //requestTest1(request);
            //反射的方式  暴力设置属性
            //requestTest2(request);
            //javaBean内省的方式    geter seter 操作属性
            //requestTest3(request);
            //首先遍历map集合    然后使用工具BeanUtils 的setProperty设置javaBean的属性与值
            //requestTest4(request);
            //借用BeanUtiles操作页面提交的参数  跟方便 更简洁 推荐使用
            requestTest5(request);
            
            
        }
    
        private void requestTest5(HttpServletRequest request) {
            User user = new User();//封装前
            System.out.println("封装前:"+user);
            
            //封装过程
            
                //引入了一个新知识点  BeanUtils
                try {
                    //传入一个对象    与一个map集合
                    BeanUtils.populate(user, request.getParameterMap());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            
            System.out.println("封装后:"+user);
        }
    
        private void requestTest4(HttpServletRequest request) {
            User user=new User();
            //用getParameterMap得到所有的参数值与参数名
            Map<String,Object[]> map=request.getParameterMap();
            //遍历   map集合    得到的key就是参数名   value是所对应的值 可能有多个
            for (Map.Entry<String, Object[]> entry : map.entrySet()) {
                String paramet=entry.getKey();
                Object []objs=entry.getValue();
                try {
                    BeanUtils.setProperty(user, paramet, objs);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                
            }
            System.out.println("封装后:"+user);
        }
    
        private void requestTest3(HttpServletRequest request) {
            User user = new User();//封装前
            System.out.println("封装前:"+user);
            
            //封装过程
            //1.服务器接收客户端发过来请求数据 ,如果 页面上请求很多时,可以用getParameterNames();得到所有的请求参数名
            Enumeration<String> enumsss  = request.getParameterNames();
            while(enumsss.hasMoreElements()){
                String paramet = enumsss.nextElement();//取出其中的一个参数名name="username"    <input type="text" name="username" >
                String []parametValues = request.getParameterValues(paramet);//得到这个参数所对应的一组值
                
                //封装到对象user中  ,此时的paramName 一定要与User的属性保持一致
                //内省
                try {
                    PropertyDescriptor pd =new PropertyDescriptor(paramet, user.getClass());//属性描述器 第一个参数是指哪个属性   第二个参数是哪个Class
                    Method method = pd.getWriteMethod();//通过属性描述器,得到setter方法    getWriteMethod:获得应该用于写入属性值的方法。
                    if(parametValues!=null && parametValues.length>1){
                        method.invoke(user, (Object)parametValues);//参考反射Main方法,   setUsername(String []username)
                    }else {
                        method.invoke(user, parametValues[0]);//只有一个参数,不要包装
                    }
                } catch (Exception e) {
                    
                    e.printStackTrace();
                }
            }
    
            System.out.println("封装后:"+user);
        }
    
        private void requestTest2(HttpServletRequest request) {
            //2.利用反射
            User user = new User();
            Enumeration<String> enums=request.getParameterNames();
            while (enums.hasMoreElements()) {
                String paramet = (String) enums.nextElement();
                String []parametValues=request.getParameterValues(paramet);
                Class clazz=user.getClass();
                
                try {
                    Field f=clazz.getDeclaredField(paramet);//利用反射得到user对象的私有的paramet属性    
                    f.setAccessible(true);//暴力反射   这样就可以操作这个私有属性
                    if(parametValues!=null&&parametValues.length>1)
                    {
                        f.set(user, (Object)parametValues);
                        //(Object)parametValues 这样写的原因是如果parametValues是一个数组的话   
                        //反射会自动拆分它,这样会使有多个参数,而用object包装后   对象就不会拆分  这样就能保证方法正确性
                    }else
                    {
                        f.set(user, parametValues[0]);//只有一个参数  可以不包装
                    }
                    
                } catch (Exception e) {
                    
                    e.printStackTrace();
                }
                
            }
             System.out.println("封装后User"+user);
        }
    
        private void requestTest1(HttpServletRequest request) {
            //1.服务器接收客户端发过来请求数据
            String username = request.getParameter("user");//username来自于表单<input type="text" name="username" >name的名字
            
            String password []= request.getParameterValues("pwd");//得到一组值
            
            User user = new User();//封装前
            System.out.println("封装前:"+user);
            
            //封装过程
            user.setUser(username);
            user.setPwd(password);
            
            
            System.out.println("封装后:"+user);
        }
    
        public void doPost(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            this.doGet(request, response);
    
        }
    
    }
    获得表单参数

    所使用javaBean

    package cn.zl.request.domain;
    
    import java.util.Arrays;
    
    public class User {
    
        private String user;
        private String pwd[];
        
        public User() {
            
        }
        
        
    
        @Override
        public String toString() {
            return "User [user=" + user + ", pwd=" + Arrays.toString(pwd) + "]";
        }
    
    
    
        public String getUser() {
            return user;
        }
        public void setUser(String user) {
            this.user = user;
        }
        public String[] getPwd() {
            return pwd;
        }
        public void setPwd(String[] pwd) {
            this.pwd = pwd;
        }
        
        
    }
    user对象
  • 相关阅读:
    select server 于青林
    server client 于青林
    嵌入式系统移植三部曲 于青林
    server-client之间的通信 刘峰
    select注释执行过程 刘峰
    嵌入式系统移植三部曲 刘峰
    select server 李敏敏
    服务器与客户端 李敏敏
    嵌入式移植三步曲 郑明莉
    嵌入式系统移植三步曲 翟长伟
  • 原文地址:https://www.cnblogs.com/lulu638/p/4234757.html
Copyright © 2020-2023  润新知