您的位置:首页 > 移动开发 > Android开发

Android项目笔记四:Android端的socket客户端建立

2016-06-02 14:35 615 查看
Android的UI线程(主线程)不能操作费时、阻塞的操作,会影响用户体验,所以socket的创建不能再UI线程中;

Android中除了UI线程外,其它线程不能操作UI控件显示,但是可以直接调用创建它所在UI线程内其它变量;

Android线程间通信,用handler,handler中可以Bundle消息;

Android中socket接收不能再UI线程中,发送可以在任意线程;

思路:

1、单独创建一个线程,创建socket,一旦成功,本线程自动退出,销毁;

2、一旦创建socket成功,创建一个监听线程,用于监听从HOST发过来数据;

3、在UI线程中,通过 handleMessage处理从其它线程传进来的消息;

代码:

创建socket:

public void setMy_MainActivityCreateSocketThread(){

        //起一个监听 socket 线程

        my_mian_socket_create_thread = new Thread(new Runnable() {

            @Override

            public void run() {

                CreateSocketThreadisRun = true;

                while (CreateSocketThreadisRun) {

                    Message CreateSocketThreadtoMainUI = new Message();

                    CreateSocketThreadtoMainUI.what = 255;

                    String result;

                    if (my_MainActivitySocket()) {

                        CreateSocketThreadtoMainUI.arg1 = 1;

                        CreateSocketThreadisRun = false;

                        result = "连接主机成功!!!";

                    } else {

                        CreateSocketThreadtoMainUI.arg1 = 2;

                        result = "连接主机失败!!!";

                        CreateSocketThreadisRun = true;

                    }

                    if(CreateSocketThreadisRun) {

                        try {

                                if(my_main_wifi.isWiFiActive(MainActivity.this)) {

                                    my_mian_socket_create_thread.sleep(4000);

                                }else {

                                    CreateSocketThreadisRun = false;

                                    CreateSocketThreadtoMainUI.arg1 = 3;

                                    result = "wifi断开连接!!!";

                                }

                        } catch (InterruptedException e) {

                            //其它线程中断当前线程异常

                            e.printStackTrace();

                            CreateSocketThreadisRun = false;

                        }

                    }

                    CreateSocketThreadtoMainUI.obj = result;

                    my_MainActivityClient.sendMessage(CreateSocketThreadtoMainUI);

                    CreateSocketThreadtoMainUI = null;

                }

                my_mian_socket_create_thread = null;

                SocketThreadisCreating = false;

            }

        });

        my_mian_socket_create_thread.start();

    }

    //创建Socke通信

    public boolean my_MainActivitySocket(){

        if(!my_MainActivitySocketClose()){

            return false;

        }

        my_mainSocketReceiveThread=null;

        //尝试创建一个Socket

/*        try {

            String HostiIP=my_main_wifi.my_getHOSTIp_String(MainActivity.this);

            my_main_clientSocket = new Socket(HostiIP,my_HOST_port);    //异常抛出时间为15s

            *//*my_main_clientSocket.connect(new InetSocketAddress(HostiIP,my_HOST_port),3000);*//*

        }catch (UnknownHostException e){

            e.printStackTrace();

            return false;

        }catch (IOException e){

            e.printStackTrace();

            return false;

        }*/

        try {

            String HostiIP=my_main_wifi.my_getHOSTIp_String(MainActivity.this);

            my_main_clientSocket = new Socket();

            my_main_clientSocket.connect(new InetSocketAddress(HostiIP,my_HOST_port),3000);

        }catch (IllegalArgumentException e){

            my_main_clientSocket=null;

            return false;

        }catch (IOException e){

            e.printStackTrace();

            my_main_clientSocket=null;

            return false;

        }

        my_mainSocketReceiveThread = new SocketReceiveThread(my_main_clientSocket,my_MainActivityClient);

        my_mainSocketReceiveThread.start();

        return true;

    }

要点:

1、创建新的socket前,一定判断之前有没有创建,如果有,一定要线关闭;

2、在关闭socket之前,先关闭输入流;

socket发送:

private void my_SocketSend(byte[] snedData,String sendStr){

    if(null == my_main_clientSocket){

        Toast.makeText(MainActivity.this,"未连接主机",Toast.LENGTH_SHORT).show();

        return;

    }

    OutputStream    sendSocketStream=null;

    try {

        if(null != sendStr){

            snedData = sendStr.getBytes("GB2312");

        }

    }catch (UnsupportedEncodingException e){

        e.printStackTrace();

    }

    try {

        sendSocketStream = my_main_clientSocket.getOutputStream();

    }catch (IOException e){

        e.printStackTrace();

    }

    try {

        sendSocketStream.write(snedData);

    }catch (IOException e){

        e.printStackTrace();

    }

}

要点:

sendSocketStream不要调用sendSocketStream.close(),否则HOST接收那边异常;

监听线程:

监听线程我写了一个CLASS

/**

 * Created by Administrator on 2016/5/19.

 */

public class SocketReceiveThread extends Thread {

    private InputStream  receiveStream =   null;

    private boolean     isStop=false;

    String                receiveStr;

    private byte        receivebuf[]=null;

    protected Handler   UIHandler=null;

    private   Socket    threadSocket=null;

    private   MyMath    myMath = new MyMath();

    SocketReceiveThread(Socket socket,Handler handler){

        try {

            UIHandler=handler;

            this.receiveStream = socket.getInputStream();

            threadSocket=socket;

            isStop=false;

        }catch (IOException e){

            e.printStackTrace();

        }

    }

    @Override

    public void run(){

        this.receivebuf = new byte[200];

        byte[]      tempDATA;

        int receivebufLong=0;

        while(!isStop){

            if(isStop) {

                return;

            }

            try {

                receivebufLong=this.receiveStream.read(this.receivebuf);//线程阻塞

            }catch (IOException e){

                e.printStackTrace();

                Message msg = new Message();

                msg.what=1;

                msg.arg1=1;//出现异常

                UIHandler.sendMessage(msg);

               return;

            }catch (NullPointerException e){

                e.printStackTrace();

                Message msg = new Message();

                msg.what=1;

                msg.arg1=1;//出现异常

                UIHandler.sendMessage(msg);

                return;

            }

            if(isStop) {

                return;

            }

            //判断出异常

            if((-1 == receivebufLong) || (0 == receivebufLong)){

                Message msg = new Message();

                msg.what=1;

                msg.arg1=2;//Host意外断开

                UIHandler.sendMessage(msg);

                return;

            }

            tempDATA = RingBuffer(this.receivebuf);

            if(null == tempDATA){

                continue;

            }

            Bundle  msgBundle = myBusinessLogic(tempDATA);

            if(null == msgBundle){

                continue;

            }

            Message msg = new Message();

            msg.what=0;

            msg.arg1=tempDATA[2];

            msg.setData(msgBundle);

            UIHandler.sendMessage(msg);

/*            try {

                this.receiveStr = new String(this.receivebuf,"GB2312").trim();

            }catch (UnsupportedEncodingException e){

                e.printStackTrace();

                continue;

            }

            Message msg = new Message();

            msg.what=0;

            msg.obj=this.receiveStr;

            UIHandler.sendMessage(msg);*/

            //清除资源

            msgBundle = null;

            msg = null;

            tempDATA = null;

            receivebufLong=0;

        }

    }

    public void SocketReceiveThread_Stop(){

        this.isStop = true;

        try {

            this.receiveStream.close();

        }catch (IOException e){

            e.printStackTrace();

        }

/*        try {

            threadSocket.close();

        }catch (IOException e){

            e.printStackTrace();

        }*/

        this.receiveStream =   null;

        this.receivebuf=null;

        threadSocket=null;

        /*UIHandler=null;*/

    }

    //业务逻辑

    private Bundle myBusinessLogic(byte[] inData){

        Bundle  bundleBusiness = null;

        float  mValue=0;

        float  mTemp=0;

        int    temp=0;

        int tempH = 0;

        int tempL = 0;

        if(null == inData){

            return bundleBusiness;

        }

        //读取数值

        if(0x05 == inData[4]){

            temp = myMath.myMathClass_rand(20000);

        }else if (0x07 == inData[4]){

            tempH = inData[8];

            tempH = (tempH << 8) & 0x0000FF00;

            tempL = inData[9];

            tempL = tempL & 0x000000FF;

            temp = tempH | tempL | 0x00000000;

        }else {

            return bundleBusiness;

        }

        mValue = temp;

        mValue = mValue/10;

        String strNoteValue         = "NoteValue";

        String strNoteValue_Value   = mValue +"";

        //读取温度

        tempH = inData[6];

        tempH = (tempH << 8) & 0x0000FF00;

        tempL = inData[7];

        tempL = tempL & 0x000000FF;

        if((inData[6] == 0x80) && (inData[7] == 0x00)){

            //得到最大的负数

            temp = -32768;

        }else if((inData[6] & 0x80) == 0x80){

            //负数

            temp = tempH | tempL | 0xFFFF0000;

        }else {

            //正数

            temp = tempH | tempL | 0x00000000;

        }

        mTemp = temp;

        mTemp = mTemp/10;

        String strNoteTemp          = "NoteTemp";

        String strNoteTemp_Value    = mTemp +"";

        bundleBusiness = new Bundle();

        bundleBusiness.putCharSequence(strNoteValue,strNoteValue_Value);

        bundleBusiness.putCharSequence(strNoteTemp,strNoteTemp_Value);

        return bundleBusiness;

    }

    //环形缓存区

    public byte[] RingBuffer(byte[] inData){

        byte[]      userData = null;

        int         inDataLong=0;

        int         i=0;

        int         ProtocolFrame_Heard;

        int         ProtocolFrame_Long;

        int         tempCRC=0;

        inDataLong = inData.length;

        for(i=0;i<inDataLong;i++){

            if((0x68 == inData[i]) && (0x68 == inData[i+3])){

                break;

            }

        }

        if(i >= inDataLong){

            return userData;

        }

        ProtocolFrame_Heard = i;

        if((ProtocolFrame_Heard+4) > inDataLong){

            return userData;

        }

        ProtocolFrame_Long = inData[ProtocolFrame_Heard+4] + 5;

        if((ProtocolFrame_Long + ProtocolFrame_Heard) > inDataLong){

            return userData;

        }

        userData = new byte[ProtocolFrame_Long];

        for(i=0;i<ProtocolFrame_Long;i++){

            userData[i] = inData[ProtocolFrame_Heard + i];

        }

        int tempCRCH = 0;

        int tempCRCL = 0;

        tempCRCH = userData[ProtocolFrame_Long - 2];

        tempCRCH = (tempCRCH <<  8) & 0x0000FF00;

        tempCRCL = userData[ProtocolFrame_Long - 1];

        tempCRCL = tempCRCL & 0x000000FF;

        tempCRC  = (tempCRCH | tempCRCL) & 0x0000FFFF;

        if(!myMath.CRC16(userData,ProtocolFrame_Long - 2,tempCRC)){

            userData = null;

        }

        return userData;

    }

}

要点:

receivebufLong=this.receiveStream.read(this.receivebuf);//在正常情况下是阻塞的,

HOST突然断电,receivebufLong = -1;

HOST关闭端口,可能是异常,我没有仔细测试;

根据这些,把消息发给上层,重新发起socket连接;

UI接收消息处理:

my_MainActivityClient     = new Handler(){

    @Override

    public void handleMessage(Message msg){

        switch (msg.what){

            case 0://socke接收到服务器消息

                my_Main_BusinessLogic_Receicve(msg.getData(),msg.arg1);

                break;

            case 1://socket接收监听线程异常消息

                //my_MainActivitySocketClose();

                    switch (msg.arg1){

                        case 1://接收线程发出消息,在SocketReceiveThread

                            System.out.println("Host 出现异常!");

                            break;

                        case 2://接收线程发出消息,在SocketReceiveThread

                            System.out.println("Host 断开连接!");

                            break;

                        case 3://业务逻辑发出消息,在MainActivity

                            System.out.println("socket接收超时");

                            break;

                    }

                if(!my_main_APPisClose && (!SocketThreadisCreating)) {

                    setMy_MainActivityCreateSocketThread();//防止关闭socket引起的异常导致重新建立连接

                    SocketThreadisCreating = true;

                }

                break;

            case 255://创建socket线程消息

                System.out.println(msg.obj.toString());

                    switch (msg.arg1){

                        case 1://主机连接成功

                            //应该添加消息过滤,防止重复发送,怎么添加呢???

                            my_MainActivityHandler.postDelayed(my_MainActivityStartBusiness, 10);

                            break;

                        case 2://主机连接失败

                            break;

                        case 3://wifi断开

                            MainActivity.this.my_toMySocketActivity(null,0);

                            break;

                    }

                break;

        }

        super.handleMessage(msg);

    }

};//END handleMessage(Message msg)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: