android socket通信之—生成xml上传到服务器并解析xml数据

需求描述:将测试数据封装成xml形式并上传到指定的服务端
在这里插入图片描述

本文实现:

  1. 生成指定形式的xml
  2. socket将xml数据上传到服务端
  3. 服务端对xml数据进行解析,验证接收到的xml和发送的数据是否一致

第一步:生成xml数据

  • xml数据的格式:
<?xml version="1.0" encoding="utf-8"?>
<ryd>

    <pro_name>8802</pro_name>

    <pro_SN>123456789</pro_SN>

    <pro_Mac>0c:12:05:01:25:25</pro_Mac>

    <test_mode>pqc</test_mode>

    <test>

        <name>CameraTest</name>

        <result>Success</result>

        <errmsg></errmsg>
    </test>

    <test>

        <name>EarphoneTest</name>

        <result>Fail</result>

        <errmsg>Fail</errmsg>
    </test>
</ryd>

说明:前面规定了产品的一些参数,后面是具体测试项test部分,这里只列举了两个test

  • 根据xml的形式,新建一个实体类ryd:
public class ryd {
    private String pro_name;

    private String pro_SN;

    private String pro_Mac;

    private String test_mode;

    private String name;

    private String result;

    private String errmsg;

    public String getPro_name() {
        return pro_name;
    }

    public void setPro_name(String pro_name) {
        this.pro_name = pro_name;
    }

    public String getPro_SN() {
        return pro_SN;
    }

    public void setPro_SN(String pro_SN) {
        this.pro_SN = pro_SN;
    }

    public String getPro_Mac() {
        return pro_Mac;
    }

    public void setPro_Mac(String pro_Mac) {
        this.pro_Mac = pro_Mac;
    }


    public String getTest_mode() {
        return test_mode;
    }

    public void setTest_mode(String test_mode) {
        this.test_mode = test_mode;
    }


    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getResult() {
        return result;
    }

    public void setResult(String result) {
        this.result = result;
    }

    public String getErrmsg() {
        return errmsg;
    }

    public void setErrmsg(String errmsg) {
        this.errmsg = errmsg;
    }
}

说明:test部分的get和set基本没用到,因为test部分都是key-value形式,所以用map来保存和读取

初始化产品参数部分:

    /**
     * 初始化xml数据
     */
    private void init_xml() {
        //[1]初始化我们要备份的数据
        smsLists = new ArrayList<ryd>();
        sms = new ryd();
        //在这里可以获取你想设置的数据,这里举例设置sn
        String serial = Build.SERIAL;//获取SN
        sms.setPro_name("8802");
        sms.setPro_SN(serial);
        sms.setPro_Mac("0c:12:05:01:25:25");
        sms.setTest_mode("pqc");
    }

在初始化test部分之前,先模拟生成测试结果:
测试项:保存在value文件夹下的stringarrays.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <string-array name="listview_item_name">
        <item>MIC测试</item>
        <item>Camera输入测试</item>
    </string-array>

    <string-array name="listview_item_uri">
        <item>com.android.nirvana.tools.HeadsetMicTestActivity</item>
        <item>com.android.nirvana.tools.HdmiTestActivity</item>
    </string-array>

</resources>

说明:所有的测试项都保存string-array中,通过SP的put来保存测试结果,大家可以根据实际的测试结果设置,这里只是简单模拟。

    private void init_data() {
        Resources res = getResources();
        names = res.getStringArray(R.array.listview_item_name);

        sharedPreferencesHelper = new SharedPreferencesHelper(this);
        //在这里模拟测试结果,camera测试成功,mic测试失败
        sharedPreferencesHelper.put("MIC测试", TEST_RESULT_FAIL);
        sharedPreferencesHelper.put("Camera输入测试", TEST_RESULT_SUCC);

    }

初始化test数据部分:

    /**
     * 获取测试结果,补充test部分
     */
    private void get_testresult() {
        for (String str : names) {
            int result = (int) sharedPreferencesHelper.get(str, TEST_RESULT_NONE);

            //在这里可以将测试的中文名称改成英文名称,因为接收中文很可能导致报错,因为数据不匹配,最好用英文
            switch (str.trim()) {
                case "MIC测试":
                    str = "EarphoneTest";
                    break;
                case "Camera输入测试":
                    str = "Camera Test";
                    break;
            }

            if (result == TEST_RESULT_SUCC) {
                map.put(str, "Success");
            } else if (result == TEST_RESULT_NONE) {
                map.put(str, "Fail");
            } else if (result == TEST_RESULT_FAIL) {
                map.put(str, "Fail");
            }
        }

        //放入测试项
        smsLists.add(sms);
    }

说明:这里将中文的测试名称强制转换为英文名称,并根据测试结果,put了对应的value

  • 将数据拼接成xml形式:

说明:(推荐)通过StringBuffer直接以追加字符串的方式生成XML文件(工程里还有用XmlSerializer生成的方式)

    /**
     * 生成xml数据
     */
    private void get_xml() {
        //[1]创建sb对象
        StringBuffer sb = new StringBuffer();

        //[2]开始组拼xml文件头
        sb.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
        //[3]开始组拼xml根节点
        sb.append("<ryd>");
        //[4]开始组拼sms节点
        for (ryd sms : smsLists) {
            //sb.append("<sms>");

            //[5]开始组拼pro_name节点
            sb.append("<pro_name>");
            sb.append(sms.getPro_name());
            sb.append("</pro_name>");

            //[6]开始组拼pro_SN节点
            sb.append("<pro_SN>");
            sb.append(sms.getPro_SN());
            sb.append("</pro_SN>");

            //[7]开始组拼pro_Mac节点
            sb.append("<pro_Mac>");
            sb.append(sms.getPro_Mac());
            sb.append("</pro_Mac>");


            //[7]开始组拼test_mode节点
            sb.append("<test_mode>");
            sb.append(sms.getTest_mode());
            sb.append("</test_mode>");

            //遍历出map的值
            Iterator iter = map.entrySet().iterator();
            while (iter.hasNext()) {
                Map.Entry entry = (Map.Entry) iter.next();
                String key = (String) entry.getKey();
                String value = (String) entry.getValue();

                //[7]开始组拼<test>节点
                sb.append("<test>");

                sb.append("<name>");
                sb.append(key);
                sb.append("</name>");

                sb.append("<result>");
                sb.append(value);
                sb.append("</result>");

                sb.append("<errmsg>");
                if (value.contains("Fail")) {
                    sms.setErrmsg("Fail");
                } else {
                    sms.setErrmsg("");
                }
                sb.append(sms.getErrmsg());
                sb.append("</errmsg>");

                sb.append("</test>");
            }
        }

        sb.append("</ryd>");
        //[8]把数据保存到sd卡中
        try {
            File file = new File(Environment.getExternalStorageDirectory().getPath(), "MesXml.xml");
            FileOutputStream fos = new FileOutputStream(file);
            fos.write(sb.toString().getBytes());
            fos.close();//关闭流
            Log.i("yyy", "文件已经保存到sd卡: ");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

不要忘了添加权限:

    <!-- 往sdcard中写入数据的权限 -->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <!-- 在sdcard中创建/删除文件的权限 -->
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />

最后查看sdcard下的MesXml.xml,发现与规定生成xml数据一致,生成xml数据到此结束

adb pull /sdcard/MesXml.xml C:\1\MesXml.xml

第二步:通过socket将xml上传到服务器

客户端创建一个Socket对象,指定服务器端的ip地址和端口号(socket = new Socket(HOST, PORT); ),通过inputstream读取数据,获取服务器发出的数据(outStream = socket.getOutputStream(); ),最后将要发送的数据写入到outputstream即可进行TCP协议的socket数据传输

    <!--允许应用程序改变网络状态-->
    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>

    <!--允许应用程序改变WIFI连接状态-->
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>

    <!--允许应用程序访问有关的网络信息-->
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

    <!--允许应用程序访问WIFI网卡的网络信息-->
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>

    <!--允许应用程序完全使用网络-->
    <uses-permission android:name="android.permission.INTERNET"/>

下面是socket发送线程,注意:此段代码应在生成xml之后


    //服务端的IP是:192.168.1.x(这里用我的电脑当服务器)
    //手机当做是客户端,端口号可以任意设定,双方一致就OK
    private static final String HOST = "192.168.1.x";
    private static final int PORT = 12333;

    /***
     * 线程
     */
    public class socketThread extends Thread {
        public void run() {
            while (!exit0) {
                try {
                    Log.i("yyy", "进入socketThread----------: ");
                    // 开启与服务器的socket连接
                    socket = new Socket(HOST, PORT);
                    // in:读入  out:写出
                    in = new BufferedReader(new InputStreamReader(
                            socket.getInputStream()));

                    //获取输出流
                    outStream = socket.getOutputStream();
                    out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(outStream)), true);


                    try {
                        File file = new File(Environment.getExternalStorageDirectory().getPath(), "MesXml.xml");
                        //创建SAXReader,读取指定文件
                        System.out.println(file);//D:\1\1.txt
                        Log.i("yyy", "file:-----------: " + file);
                        if (file.exists()) {
                            SAXReader reader = new SAXReader();
                            Document doc = null;
                            doc = reader.read(file);
                            //创建XML输出流
                            XMLWriter writer = new XMLWriter();
                            writer.setOutputStream(outStream);
                            writer.write(doc);
                        } else {
                            Log.i("yyy", "MesXml文件还没有生成: ");
                        }


                    } catch (DocumentException e) {
                        e.printStackTrace();
                    } catch (IOException e) {
                        e.printStackTrace();
                    } finally {
                        if (socket != null) {
                            msocketThread.stopDownload();
                            try {
                                out.flush();
                                out.close();
                                System.out.println("socket已关闭---");
                                socket.close();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                } catch (IOException ex) {
                    ex.printStackTrace();
                }

            }
        }

        public void stopDownload() {
            Log.i("yyy", "线程已经停止------------: ");
            exit0 = true;
        }
    }

说明:这里生成xml和解析xml都是使用SAX解析方式,需要先导入jar包才可以,具体可以参考文末

第三步:服务端解析xml数据

服务器端首先声明一个ServerSocket对象并且指定端口号,然后调用Serversocket的accept()方法接收客户端的数据。accept()方法在没有数据进行接收的处于堵塞状态。一旦接收到数据,通过socket.getInputStream()读取接收的数据。

服务端完整代码如下:

/**
 * 服务端
 */
public class Server {
    private ServerSocket server;

    //这里的端口号必须和客户端的保持一致,
    public Server() throws IOException {
        server = new ServerSocket(12333);
    }

    public void start() {
        try {
            //监听客户端,建立连接
            System.out.println("等待连接..........");
            Socket socket = server.accept();
            System.out.println("服务端连接成功!");
            //获取输入流   写出  读入
            InputStream in = socket.getInputStream();
            //创建SAXReader,读取指定文件
            SAXReader reader = new SAXReader();
            Document doc = reader.read(in);
            //获取根节点
            Element root = doc.getRootElement();
            getNodes(root);//遍历根节点下的所有节点,也就是整个xml文件的所有节点
            System.out.println("解析完毕!");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (server != null) {
                try {
                    server.close();
                    System.out.println("服务端已关闭!");
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }


    /**
     * 从指定节点开始,递归遍历所有子节点,这个方法很好用
     */
    public void getNodes(Element node) {
        System.out.println("--------------------");

        //当前节点的名称、文本内容和属性
        System.out.println("当前节点名称:" + node.getName());//当前节点名称
        System.out.println("当前节点的内容:" + node.getTextTrim());//当前节点内容

        //递归遍历当前节点所有的子节点
        List<Element> listElement = node.elements();//所有一级子节点的list
        for (Element e : listElement) {//遍历所有一级子节点
            this.getNodes(e);//递归
        }
    }


    public static void main(String[] args) {
        try {
            Server s = new Server();
            s.start();
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("初始化服务端失败!");
        }
    }
}

说明:服务端是一个java程序,鼠标右击下图开始运行
在这里插入图片描述
正确接收的数据:

等待连接..........
服务端连接成功!
--------------------
当前节点名称:ryd
当前节点的内容:
--------------------
当前节点名称:pro_name
当前节点的内容:8802
--------------------
当前节点名称:pro_SN
当前节点的内容:000000000000
--------------------
当前节点名称:pro_Mac
当前节点的内容:0c:12:05:01:25:25
--------------------
当前节点名称:test_mode
当前节点的内容:pqc
--------------------
当前节点名称:test
当前节点的内容:
--------------------
当前节点名称:name
当前节点的内容:Camera Test
--------------------
当前节点名称:result
当前节点的内容:Success
--------------------
当前节点名称:errmsg
当前节点的内容:
--------------------
当前节点名称:test
当前节点的内容:
--------------------
当前节点名称:name
当前节点的内容:EarphoneTest
--------------------
当前节点名称:result
当前节点的内容:Fail
--------------------
当前节点名称:errmsg
当前节点的内容:Fail
解析完毕!
服务端已关闭!

说明:可以看到每一个节点的名称,sn是根据具体板子获取的,不用纠结这个。

至此:一个完整的工程结束,从生成xml到上传到服务器并且解析xml。

github地址:https://github.com/felicity520/xmlTosocket.git

作者:鸣人的修炼场
出处:https://blog.csdn.net/baidu_33693586

参考博客:
Android 生成xml文件
Android XML解析的三种方式

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值