• 项目笔记:测试类的编写


      由于需要客户终端上报数据,所以做一个测试类,模拟上报的数据信息。

      首先看下测试类的目录,主要是在 http 下面

      客户端上报的数据是这样的JSON:

    {"pcInfo":{"ip":"192.168.118.45","mac":"11-22-12-23","onlyId":"1"},"user":{"name":"test"},"log":{"version":"1.0","type":"8001","content":{"policyName":"VRV","templateType":"0","contentlist":[{"SoftID":"1","MatchResult":"1","GenRule":"1001,1002","PirRule":"2001,2002","Remark1":"12365"},{"SoftID":"2","MatchResult":"0","GenRule":"1001","PirRule":"2002","Remark1":"125"}]},"areaCode":"4310"}}

      我们就来模拟生成这样的JSON。

      注意:测试方式的@Test是必须得加的。

    /**
     * @author 正版化上报测试类
     * @version 2017/9/14
     * */
    public class TestHttp {
    
        public HttpURLConnection connection = null;
        public OutputStreamWriter out = null;
        public JSONObject jsonObject = null;
        public JSONObject jsonObject1 = null;
        public JSONObject jsonObject2 = null;
        public JSONObject jsonObject3 = null;
        public JSONObject jsonObject4 = null;
        public JSONObject jsonObject5 = null;
        public JSONObject jsonObject6 = null;//分别定义6个JSONObject来存放不同的层级内容
        List<String> list = new ArrayList<String>();//需要定义一个list来存放contentlist的内容
        public URL postUrl = null;
        public TreeMap<String, Object> data = new TreeMap<String, Object>();
        
        public void initData(){
             try {
                postUrl = new URL("http://192.168.118.221:8080/JJFX/reportDataAction.do");//这里的ip要是我本机的ip
                connection = (HttpURLConnection) postUrl.openConnection();
                connection.setDoInput(true);
                connection.setDoOutput(true);
                connection.setRequestMethod("POST");
                connection.setUseCaches(false);
                connection.setInstanceFollowRedirects(true);
                connection.setRequestProperty("Content-Type",
                        "application/x-www-form-urlencoded");
                connection.setChunkedStreamingMode(5);
                connection.connect();
                out = new OutputStreamWriter(connection.getOutputStream(), "utf-8");
                jsonObject = new JSONObject();
                jsonObject1 = new JSONObject();
                jsonObject2 = new JSONObject();
                jsonObject3 = new JSONObject();
                jsonObject4 = new JSONObject();
                jsonObject5 = new JSONObject();
                jsonObject6 = new JSONObject();
                List<String> list = new ArrayList<String>();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        /**
         * 正版化信息上报接口
         * @author gwf
         * @version 2017-9-14
         * */
        @Test
        public void test1001(){
            
            initData();    
            //pcInfo
            jsonObject1.put("ip", "192.158.129.35");
            jsonObject1.put("mac", "11-32-22-43");
            jsonObject1.put("onlyId", "4");
            jsonObject.put("pcInfo", jsonObject1);//jsonObject1用于存放pcInfo的内容
            
            //user
            jsonObject2.put("name", "test4");
            jsonObject.put("user", jsonObject2);//jsonObject2用于存放user的内容
            
            //log
        //    jsonObject3.put("time", "");
            jsonObject3.put("version", "1.5");
            jsonObject3.put("type", "8001");//jsonObject3用于存放log的内容
                            
            //content
            jsonObject4.put("policyName", "VRV");
            jsonObject4.put("templateType", "0");//jsonObject4用于存放content的内容
            //contentList里的数组
            jsonObject5.put("softId", "1");
            jsonObject5.put("matchResult", "1");
            jsonObject5.put("genRule", "1001,1002");
            jsonObject5.put("pirRule", "2001,2002");
            jsonObject5.put("remark1", "123665");
            jsonObject5.put("softVer", "ff199");//jsonObject5用于存放contentlist的内容1
            
            jsonObject6.put("softId", "2");
            jsonObject6.put("matchResult", "0");
            jsonObject6.put("genRule", "1001");
            jsonObject6.put("pirRule", "2002");
            jsonObject6.put("remark1", "1245");
            jsonObject6.put("softVer", "ff59");//jsonObject5用于存放contentlist的内容2
            
            list.add(jsonObject5.toString());
            list.add(jsonObject6.toString());//把contentlist里面的内容1/2分别放入一个list中保存
            
            /*jsonObject4.put("antivirusDbVer", "1.0");
            jsonObject4.put("operationType", "1");
            jsonObject4.put("optTime", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));*/
            jsonObject4.put("contentlist", list);//把保存的list放入contentlist
            
            jsonObject3.put("content", jsonObject4);//把contentlist放入content
            jsonObject3.put("areaCode", "4310");//jsonObject3继续存放log的内容areaCode
            jsonObject.put("log", jsonObject3);//jsonObject存放log的键值对
            String content ="jsonData="+ jsonObject.toString();    
            try {
                out.write(content);
            
                out.flush();
                // out.close();
                BufferedReader reader = new BufferedReader(new InputStreamReader(
                        connection.getInputStream()));
                out.flush();
                // out.close();
                String line;
                while ((line = reader.readLine()) != null) {
                    System.out.println(line);
                }
                out.close();
                reader.close();
                connection.disconnect();
            } catch (IOException e) {
            
                e.printStackTrace();
            }
        }
    
        public static void main(String args[]){
              JSONObject jsonObject = new JSONObject();
              JSONObject jsonObject1 = new JSONObject();
              JSONObject jsonObject2 = new JSONObject();
              JSONObject jsonObject3 = new JSONObject();
              JSONObject jsonObject4 = new JSONObject();
              jsonObject1.put("ip", "192.168.118.212");
            jsonObject1.put("mac", "88-12-33-67-80");
            jsonObject1.put("onlyId", "123456");
            jsonObject.put("pcInfo", jsonObject1);
            
            //user
            jsonObject2.put("name", "服务器");
            jsonObject.put("user", jsonObject2);
            
            //log
        //    jsonObject3.put("time", "");
            jsonObject3.put("version", "1.0");
            jsonObject3.put("type", "7001");
                            
            //content
            jsonObject4.put("antivirusName", "VRV");
            jsonObject4.put("antivirusVer", "test2");
            jsonObject4.put("antivirusDbVer", "1.0");
            jsonObject4.put("operationType", "1");
            jsonObject4.put("optTime", "2017-7-12 15:27:01");
        
            jsonObject3.put("content", jsonObject4);
            jsonObject3.put("areaCode", "4310");
            jsonObject.put("log", jsonObject3);
            String jsonData = jsonObject.toString();
            System.out.println("===客户端上报数据================:"+jsonData);    
             Gson gson = new Gson();
    
            //System.out.println("===客户端上报数据================:"+ jsonObj111.getString("type"));
             
            ReportDataBean2 reportDataBean = gson.fromJson(jsonData, ReportDataBean2.class);
        
            PCInfo pcInfo = reportDataBean.getPcInfo();
            CloudAccount user = reportDataBean.getUser();
            ReportLog2 log = reportDataBean.getLog();
        //    ContentInfo content=log.getContent();
        }
        
    }

      然后选择test1001,右键Run As,选择JUnit Test,运行

    /**<B>说 明</B>: 数据上报Action
     * @author 作 者 名:gwf<br/>
     * @version 版 本 号:V1.0<br/>
     */
    @Controller
    @Scope("prototype")
    public class ReportDataAction extends BaseAction {
        private static final long serialVersionUID = 7143456155737588152L;
        private Gson gson = new Gson();
        private String jsonData;
        private String crc;
        public String getJsonData() {
            return jsonData;
        }
        public void setJsonData(String jsonData) {
            this.jsonData = jsonData;
        }
        public String getCrc() {
            return crc;
        }
        public void setCrc(String crc) {
            this.crc = crc;
        }
        @Resource
        private PCInfoService pcInfoService;
        @Resource
        private CloudAccountService cloudAccountService;
        @Resource
        private ReportLogService reportLogService;
        @Resource
        private GenuineManagementStaticDao genuineManagementStaticDao;
        
        @SuppressWarnings("unchecked")
        @Override
        public String execute() {
            try {
                // TODO 开发测试使用数据,发布时删除
            //    String data = IOUtils.toString(HttpServletRequest.getInputStream(), "UTF-8")
                log.info("1:===信息上报数据================:"+jsonData);
                // 1.判断上报信息
                if (StringUtils.isBlank(jsonData)) {//这个jsonData就是我模拟过来的JSON字符串
                    this.print("{"result":1,"msg":"上报信息为空!","description":""}");
                    return null;
                }
                // 2.CRC验证判断jsonData数据是否完整
    //            if (StringUtils.isBlank(crc) || !crc.equals(String.valueOf(CRCUtil.getCRC32Value(jsonData)))) {
    //                this.print("{"result":1,"msg":"上报数据不完整或存在安全风险"},"description":"CRC为空或不一致"");
    //                return null;
    //            }
                // 3.解析JSON data
                 JSONObject jsonObj111 =JSONObject.fromObject(jsonData);//解析json对象
                 JSONArray ja=JSONArray.fromObject(jsonObj111.get("log"));//从解析的json对象里面获取key值log的内容
                 String type="";
                 for (int i = 0; i < ja.size(); i++) {//上面数据ja.size()为1
                     JSONObject o=ja.getJSONObject(i);
                     if(o.get("type")!=null){
                        type=o.get("type").toString();//获取接口type
                     }
                 }
                ReportLog reportLog = new ReportLog();
                PCInfo pcInfo = new PCInfo();
                CloudAccount user = new CloudAccount();
                
                ReportDataBean2 reportDataBean = gson.fromJson(jsonData, ReportDataBean2.class);
                pcInfo = reportDataBean.getPcInfo();
                user = reportDataBean.getUser();
                JSONObject json = null;
                //JSONObject.fromObject(((ReportLog2<StrategyContentInfo>)reportDataBean.getLog()).getContent());
                if("3002".equals(type)||"3002".equals(type)){     //匹配接口的解析方法
                    this.log.info("=======安全基线策略执行上报类型========");
    //                ReportDataBean2 reportDataBean = gson.fromJson(jsonData, ReportDataBean2.class);
    //                pcInfo = reportDataBean.getPcInfo();
    //                user = reportDataBean.getUser();
                    json = JSONObject.fromObject(((ReportLog2<StrategyContentInfo>)reportDataBean.getLog()).getContent());
                    StrategyContentInfo contentInfo = gson.fromJson(json.toString(), StrategyContentInfo.class);
                    ReportLog2<StrategyContentInfo> log2 = (ReportLog2<StrategyContentInfo>)reportDataBean.getLog();
                    if(log2 != null){
                        reportLog.setType(log2.getType());
                        reportLog.setContent(JSONObject.fromObject(contentInfo).toString());
                        reportLog.setTime(log2.getTime());
                        reportLog.setVersion(log2.getVersion());
                        reportLog.setAreaCode(log2.getAreaCode());
                    }
                }else if("5001".equals(type)){
                    this.log.info("=======合规检查===》总体检测结果统计上报类型========");
                    json = JSONObject.fromObject(((ReportLog2<ComplianceCheckTotal>)reportDataBean.getLog()).getContent());
                    ReportLog2<ComplianceCheckTotal> log2 = (ReportLog2<ComplianceCheckTotal>)reportDataBean.getLog();
                    ComplianceCheckTotal contentInfo = gson.fromJson(json.toString(), ComplianceCheckTotal.class);
                    if(log2 != null){
                        reportLog.setType(log2.getType());
                        reportLog.setContent(JSONObject.fromObject(contentInfo).toString());
                        reportLog.setTime(log2.getTime());
                        reportLog.setVersion(log2.getVersion());
                        reportLog.setAreaCode(log2.getAreaCode());
                    }
                }else if("5002".equals(type)){
                    this.log.info("=======合规检查===》单个检测项结果上报类型========");
                    json = JSONObject.fromObject(((ReportLog2<ComplianceCheckSingle>)reportDataBean.getLog()).getContent());
                    ReportLog2<ComplianceCheckSingle> log2 = (ReportLog2<ComplianceCheckSingle>)reportDataBean.getLog();
                    ComplianceCheckSingle contentInfo = gson.fromJson(json.toString(), ComplianceCheckSingle.class);
                    if(log2 != null){
                        reportLog.setType(log2.getType());
                        reportLog.setContent(JSONObject.fromObject(contentInfo).toString());
                        reportLog.setTime(log2.getTime());
                        reportLog.setVersion(log2.getVersion());
                        reportLog.setAreaCode(log2.getAreaCode());
                    }
                }else if("6001".equals(type)){
                    this.log.info("=======补丁信息数据上报类型========");
                    json = JSONObject.fromObject(((ReportLog2<PatchInfo>)reportDataBean.getLog()).getContent());
                    ReportLog2<PatchInfo> log2 = (ReportLog2<PatchInfo>)reportDataBean.getLog();
                    PatchInfo contentInfo = gson.fromJson(json.toString(), PatchInfo.class);
                    if(log2 != null){
                        reportLog.setType(log2.getType());
                        reportLog.setContent(JSONObject.fromObject(contentInfo).toString());
                        reportLog.setTime(log2.getTime());
                        reportLog.setVersion(log2.getVersion());
                        reportLog.setAreaCode(log2.getAreaCode());
                    }
                }else if("1001".equals(type)){//客户端注册,需要检查授权文件
                    ReportDataBean reportDataBean1 = gson.fromJson(jsonData, ReportDataBean.class);
                    pcInfo = reportDataBean1.getPcInfo();
                    user = reportDataBean1.getUser();
                    reportLog = reportDataBean1.getLog();
                    //String onlyId = pcInfo.getOnlyId();
                    PCInfo temp = pcInfoService.queryByOnlyID(pcInfo);
                    if(temp == null){
                        
                    }
                }else if("8001".equals(type)){   //我的接口type是8001
                    this.log.info("=======正版化执行上报类型========");
                    json = JSONObject.fromObject(((ReportLog2<GenuineManagementContentInfo>)reportDataBean.getLog()).getContent());
                    //获取content里面内容
                    //{"policyName":"VRV","templateType":"0","contentlist":[{"softId":"1","matchResult":"1","genRule":"1001,1002","pirRule":"2001,2002","remark1":"123665","softVer":"ff11"}]}
                    GenuineManagementContentInfo contentInfo = gson.fromJson(json.toString(), GenuineManagementContentInfo.class);
                    ReportLog2<GenuineManagementContentInfo> log2 = (ReportLog2<GenuineManagementContentInfo>)reportDataBean.getLog();
                    if(log2 != null){
                        reportLog.setType(log2.getType());
                        reportLog.setContent(JSONObject.fromObject(contentInfo).toString());
                        reportLog.setTime(log2.getTime());
                        reportLog.setVersion(log2.getVersion());
                        reportLog.setAreaCode(log2.getAreaCode());//把一个个数据设置到reportLog里面去
                    }
                }else{//没有content字段或者content字段内容为字符串非json对象
                    ReportDataBean reportDataBean1 = gson.fromJson(jsonData, ReportDataBean.class);
                    pcInfo = reportDataBean1.getPcInfo();
                    user = reportDataBean1.getUser();
                    reportLog = reportDataBean1.getLog();        
                }
                // 4.入库操作
                reportLogService.saveReportDate(pcInfo, user, reportLog);
                this.print("{"result":0,"msg":"上报数据成功","description":""}");
            } catch (Exception e) {
                this.print("{"result":1,"msg":"上报数据失败","description":""}");
                e.printStackTrace();
            }
            return null;
        }
    }

    上面获取数据的这三行要特别注意:GenuineManagementContentInfo 里面的数据必须跟json里面的一一对应才可以获取到数据,否则是获取不到的

    json = JSONObject.fromObject(((ReportLog2<GenuineManagementContentInfo>)reportDataBean.getLog()).getContent());
    GenuineManagementContentInfo contentInfo = gson.fromJson(json.toString(), GenuineManagementContentInfo.class);
    ReportLog2<GenuineManagementContentInfo> log2 = (ReportLog2<GenuineManagementContentInfo>)reportDataBean.getLog();

      先看下我的  GenuineManagementContentInfo 里的内容,与content里一致,这个是在bean目录下

    /**
     * 正版化数据上报content数据类
     * @author gwf
     * @version 2017.09.06 16:06
     * */
    public class GenuineManagementContentInfo {
        
        private String policyName;
        private String templateType;
        private List<GenuineManagementStaticList> contentlist;
        
        public String getPolicyName() {
            return policyName;
        }
        public String getTemplateType() {
            return templateType;
        }
        public void setPolicyName(String policyName) {
            this.policyName = policyName;
        }
        public void setTemplateType(String templateType) {
            this.templateType = templateType;
        }
        public List<GenuineManagementStaticList> getContentlist() {
            return contentlist;
        }
        public void setContentlist(List<GenuineManagementStaticList> contentlist) {
            this.contentlist = contentlist;
        }
        
    }

       注意:这里面还有个List,这个list的实体类型GenuineManagementStaticList,也要和contentlist里的数据一一对应才行。看下下面数据,与contentlist里的数据一一对应。

    public class GenuineManagementStaticList  implements Serializable{
    
        private static final long serialVersionUID = -7081067901120934024L;
        /** 软件ID  **/
        private Integer softId;    
        /** 匹配结果 **/
        private Integer matchResult;
        /** 正版规则的检查依据 **/
        private String genRule;
        /** 非正版规则的检查依据 **/
        private String pirRule;
        /** 备注 **/
        private String remark1;
        /** 版本 **/
        private String softVer;
    
        public String getSoftVer() {
            return softVer;
        }
        public void setSoftVer(String softVer) {
            this.softVer = softVer;
        }
        public Integer getSoftId() {
            return softId;
        }
        public void setSoftId(Integer softId) {
            this.softId = softId;
        }
        public Integer getMatchResult() {
            return matchResult;
        }
        public void setMatchResult(Integer matchResult) {
            this.matchResult = matchResult;
        }
        public String getGenRule() {
            return genRule;
        }
        public void setGenRule(String genRule) {
            this.genRule = genRule;
        }
        public String getPirRule() {
            return pirRule;
        }
        public void setPirRule(String pirRule) {
            this.pirRule = pirRule;
        }
        public String getRemark1() {
            return remark1;
        }
        public void setRemark1(String remark1) {
            this.remark1 = remark1;
        }
    
        public GenuineManagementStaticList() {
            super();
        }
        public GenuineManagementStaticList(Integer softId, Integer matchResult, String genRule, String pirRule,
                String remark1, String softVer) {
            this.softId = softId;
            this.matchResult = matchResult;
            this.genRule = genRule;
            this.pirRule = pirRule;
            this.remark1 = remark1;
            this.softVer = softVer;
        }
        
    }

      最后看下保存各数据的saveReportDate方法。

        @Override
        public void saveReportDate(PCInfo pcInfo, CloudAccount user, ReportLog log) {
    
            String type=log.getType();//获取接口type
            pcInfo = pcInfoDao.saveNoExist(pcInfo);//保存pcInfo表
            if(null != pcInfo){
                log.setPcInfo(pcInfo);//然后呢,把pcInfo设置到log中,主要是为了拿到关联的pcInfoId
            }
            else{
                 System.out.println("设备不存在!");
            }
            if(null != user){
                user = cloudAccountDao.saveByName(user);//保存user表
            }
            else{
                 System.out.println("云账号为空,不存在!");
            }
            log.setCloudAccount(user);//然后呢,把user设置到log中,主要是为了拿到关联的cloudAccountId
    
            if ("1001".equals(type) || "1003".equals(type)) {//这些都是匹配接口类型
                log = specialTypeOperate("1001", log);
            } else if ("1002".equals(type)) {
                log = specialTypeOperate("1002", log);
            }
            if (type.equals("5001") ) { // 合规检查总体检测结果
                if (StringUtils.isNotBlank(log.getContent())) {
                    Gson gson = new Gson();
                    ComplianAlarmInfo complianAlarmInfo =gson.fromJson(log.getContent(), ComplianAlarmInfo.class);
                    complianAlarmInfo.setIpAddress(pcInfo.getIp());
                    complianAlarmInfo.setMacAddress(pcInfo.getMac());
                    complianAlarmInfo.setUserName(user.getName());
                    complianAlarmInfo.setOrganization(log.getAreaCode());
                    complianAlarmInfoDao.save(complianAlarmInfo);   
                }
    
            } else if (type.equals("5002")) {// 合规检查单个检测结果
                if (StringUtils.isNotBlank(log.getContent())) {
                    Gson gson = new Gson();
                    ComplianAlarmInfoDetail complianAlarmInfoDetail =gson.fromJson(log.getContent(), ComplianAlarmInfoDetail.class);            
                    complianAlarmInfoDetailDao.save(complianAlarmInfoDetail);
                }
            }  else if (log.getType().equals("5101")) {// 杀毒软件安装上报
                if (StringUtils.isNotBlank(log.getContent())) {
                    Gson gson = new Gson();
                    AntivirusSoftStatic antivirusSoftStatic =gson.fromJson(log.getContent(), AntivirusSoftStatic.class);    
                    String pcInfoId=pcInfoDao.queryByOnlyID(log.getPcInfo()).getId();
                    AntivirusSoftStatic  rl=antivirusSoftStaticDao.queryByPcInfoId(pcInfoId,antivirusSoftStatic.getAntivirusName());
                    if (rl!=null) {            
                        try {
                            rl.setAntivirusName(antivirusSoftStatic.getAntivirusName());
                            rl.setInstallTime(antivirusSoftStatic.getInstallTime());
                            rl.setInstallType(antivirusSoftStatic.getInstallType());
                            rl.setPcInfo(log.getPcInfo());
                            rl.setCloudAccount(log.getCloudAccount());
                            rl.setVersion(antivirusSoftStatic.getVersion());
                        }  catch (Exception e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }                    
                    }else{
                        antivirusSoftStatic.setPcInfo(log.getPcInfo());
                        antivirusSoftStatic.setCloudAccount(log.getCloudAccount());
                        antivirusSoftStaticDao.save(antivirusSoftStatic);
                    }
                }
            }else if (log.getType().equals("8001")) {// 正版化上报
                if (StringUtils.isNotBlank(log.getContent())) {
                    Gson gson = new Gson();
                    GenuineManagementContentInfo genuineManagementStatic =gson.fromJson(log.getContent(), GenuineManagementContentInfo.class);
                    //和前面一样获取到content里面内容,主要是为了拿到genuineManagementStatic.getContentlist()
                    for(GenuineManagementStaticList gm : genuineManagementStatic.getContentlist()){//遍历contentlist
                        GenuineManagementStatic gms = new GenuineManagementStatic();//声明一个新的实体类实例用于保存到数据库表
                        gms.setSoftId(gm.getSoftId());
                        gms.setGenRule(gm.getGenRule());
                        gms.setMatchResult(gm.getMatchResult());
                        gms.setPirRule(gm.getPirRule());
                        gms.setRemark1(gm.getRemark1());
                        gms.setVersion(gm.getSoftVer());
                        gms.setPcInfo(log.getPcInfo());
                        gms.setCloudAccount(log.getCloudAccount());
                        genuineManagementStaticDao.save(gms);    //保存到数据库表genuineManagementStatic里
                    }
                }
            }else {
                if(log.getType().equals("1001")||log.getType().equals("1002")||log.getType().equals("1003")){
                    String pcInfoId=pcInfoDao.queryByOnlyID(log.getPcInfo()).getId();
                    ReportLog rl=reportLogDao.queryByPcInfoId(pcInfoId,log.getType());
                    if (rl!=null) {
                        //更新reportLog
                        log.setId(rl.getId());
                        rl.setAreaCode(log.getAreaCode());
                        rl.setCloudAccount(log.getCloudAccount());
                        //rl.setCloudAccount(cloudAccount);
                        rl.setContent(log.getContent());
                        //rl.setPcInfo(pcInfo2);
                        rl.setPcInfo(log.getPcInfo());
                        rl.setTime(log.getTime());
                        rl.setType(log.getType());
                        rl.setVersion(log.getVersion());
    //                    log.setId(rl.getId());
    //                    reportLogDao.update(log);    
                    } else {
                        reportLogDao.save(log);
                    }
                }else{
                    reportLogDao.save(log);
                }        
            }
        }

      至此,测试类编写完毕,测试数据,发现数据都存入到了表里。

  • 相关阅读:
    SEO优化---学会建立高转化率的网站关键词库
    从一个程序员的角度看——微信小应用
    当AngularJS POST方法碰上PHP
    angularJS(6)
    彻底解决显示Opencv中Mat图像到Mfc窗口问题
    数据结构与算法基础总结
    java类别问题
    java基础知识
    逻辑地址、线性地址、物理地址和虚拟地址的区别
    TCP协议中的三次握手和四次挥手(图解)
  • 原文地址:https://www.cnblogs.com/goloving/p/7528259.html
Copyright © 2020-2023  润新知