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

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)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值