Android Socket 通信

时间:2020-12-13 18:35:42

Android socket 通信

安卓编写Socket客户端,实现连接Socket服务端通信。

创建Socket连接并获取服务端数据

先创建几个全局变量吧

private BufferedWriter writer = null;
Socket socket;

创建Socket

                // 填好IPV4的IP地址和端口,服务端会提供,问服务端要
                socket = new Socket("192.168.1.156", 1234);
                // 下面三句照抄就行
                writer = new BufferedWriter(new OutputStreamWriter(
                        socket.getOutputStream()));
                InputStream inputStream = socket.getInputStream();
                DataInputStream input = new DataInputStream(inputStream);
                // 创建一个字节数组用来接收服务端发来的字节流,多大自己说了算
                byte[] b = new byte[100000];
                // 写一个死循环,不停的接收服务端发来的数据
                while (true) {
                    // 将数据读入字节数组,返回长度
                    int length = input.read(b);
                    // 如果服务端没发数据就return不在往下执行,继续读数据
                    if (length <= 0) return;
                    // 如果服务端发的数据不为空,则把字节数组转成字符串
                    msg = new String(b, 0, length, "gb2312");
                    // 后边就可以调用数据解析的方法
                    ....
                }

一般的通讯格式都是Json的,查一下把json格式的字符串转换成json对象然后根据key值获取value的代码:

// 其中,data是json格式的字符串,转换成了jsonObject对象
JSONObject jsonObject = new JSONObject(data);
// 获取jsonObject对象的device_id值,当然device_id是String类型的,如果是int就用int
String i = jsonObject.getString("device_id");

发送数据给服务端

发送数据给服务端的前提是已经完成了Socket连接

// 首先判断一下socket是不是已经创建连接了,如果没有就不管它
if (socket == null) return;
// str是准备发给服务端的字符串
writer.write(str);
// 发出去(留坑,继续看完)
writer.flush();

这就完成了Android编写Socket与服务端通信的功能。但是这个Socket IPV4的地址可以,IPV6的地址我没试过,听说好像有点问题,但是大部分都用IPV4,如果真的用到IPV6的话,再百度!

纠错

问题来咯!!!
我遇到的大坑!
在很早之前我开发的时候上面的操作编写方式完全没问题!
但是,昨天我写的时候发现会报错!报错在 writer.flush() 这个地方。
百度之后发现:
老版的android不会有问题,但是新版本的android(好像是sdk10以上)已经不允许在UI线程(主线程)中发起网络请求了,会抛出NetWorkInUIThreadException。
所以说给服务端发送数据的时候需要写到子线程里。

        new Thread(new Runnable() {
            @Override
            public void run() {
                // 首先判断一下socket是不是已经创建连接了,如果没有就不管它
                if (socket == null) return;
                // str是准备发给服务端的字符串
                writer.write("我是Android客户端发的数据");
                // 发出去
                writer.flush();
            }
        }).start();

这样就开一个子线程,在子线程中编写发送数据的代码或调用发送数据的方法就没问题了!

留坑!

生命不息,留坑不止!!
如果我们把发送数据的代码封装成一个方法,并且发送的数据需要方法传参,比如:

public void sendData(String str){
        new Thread(new Runnable() {
            @Override
            public void run() {
                // 首先判断一下socket是不是已经创建连接了,如果没有就不管它
                if (socket == null) return;
                // str是准备发给服务端的字符串,会报错,传进来的参数子线程进不来
                writer.write(str);
                // 发出去
                writer.flush();
            }
        }).start();
}

发现父线程传进的参数,子线程读不到,我郁闷了好久,自己写了个内部类解决了。

    /**
     * 接口类,实现主线程向子线程传值
     */
    class sendData implements Runnable {
        String str;
        public sendValueToServer(String str) {
            this.str = str;
        }
        @Override
        public void run() {
            try {
                // 如果socket连接失败,则停止执行
                if (socket == null) return;
                // 发送传进来的值
                writer.write(str);
                // 发出去
                writer.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

然后在需要发送的地方写:

new Thread(new sendData ("传值数据")).start();

完成!哈哈哈,刺激!