Android 基于TCP/IP的Socket通信

作者: Kandy_JS | 来源:发表于2019-02-15 15:06 被阅读13次

    参考

    1、Android网络编程 - TCP/IP协议实践
    2、Android-TCP客户端的实现
    3、Android之从TCP/IP、HTTP看Socket通信

    截图

    1、Android 客户端
    image.png
    2、PC服务端:用的是SocketTool软件模拟
    image.png

    流程

    1、连接socket的服务端(ip和port):开启异步线程和socket
    2、发送数据(OutputStream):异步
    3、接收数据(InputStream):注意连接状态,异步读取
    4、关闭连接:关闭socket和对应线程

    注意

    1、异常:android.os.NetworkOnMainThreadException。 socket需要在线程中使用
    2、前后端统一传输或者接收协议 [requestcode size d1 d2 d3 ... ],在解析时候用得到
    3、实施监控socket的连接状态,还是用心跳包发过去,然后返回数据,一段时间没有的话则代表socket连接失败。

    代码

    1、SocketClient.java:socket的客户端,略微做了通用封装,主要是连接,发送,接收,然后设置监听
    /**
     * Created by wujn on 2019/2/15.
     * Version : v1.0
     * Function: socket client
     */
    public class SocketClient {
    
    
        /**
         * single instance SocketClient
         * */
        private static SocketClient mSocketClient = null;
        private SocketClient(){}
        public static SocketClient getInstance(){
            if(mSocketClient == null){
                synchronized (SocketClient.class) {
                    mSocketClient = new SocketClient();
                }
            }
            return mSocketClient;
        }
    
    
        String TAG_log = "Socket";
        private Socket mSocket;
    
        private OutputStream mOutputStream;
        private InputStream mInputStream;
    
        private SocketThread mSocketThread;
        private boolean isStop = false;//thread flag
    
    
        /**
         * 128 - 数据按照最长接收,一次性
         * */
        private class SocketThread extends Thread {
    
            private String ip;
            private int port;
            public SocketThread(String ip, int port){
                this.ip = ip;
                this.port = port;
            }
    
            @Override
            public void run() {
                Log.d(TAG_log,"SocketThread start ");
                super.run();
    
                //connect ...
                try {
                    if (mSocket != null) {
                        mSocket.close();
                        mSocket = null;
                    }
    
                    InetAddress ipAddress = InetAddress.getByName(ip);
                    mSocket = new Socket(ipAddress, port);
    
                    //设置不延时发送
                    //mSocket.setTcpNoDelay(true);
                    //设置输入输出缓冲流大小
                    //mSocket.setSendBufferSize(8*1024);
                    //mSocket.setReceiveBufferSize(8*1024);
    
                    if(isConnect()){
                        mOutputStream = mSocket.getOutputStream();
                        mInputStream = mSocket.getInputStream();
    
                        isStop = false;
    
                        if (null != onDataReceiveListener) {
                            onDataReceiveListener.onConnectSuccess();
                        }
                    }
                    /* 此处这样做没什么意义不大,真正的socket未连接还是靠心跳发送,等待服务端回应比较好,一段时间内未回应,则socket未连接成功 */
                    else{
                        if (null != onDataReceiveListener) {
                            Log.e(TAG_log,"SocketThread connect fail");
                            onDataReceiveListener.onConnectFail();
                            disconnect();
                        }
                    }
    
                }
                catch (IOException e) {
                    if (null != onDataReceiveListener) {
                        Log.e(TAG_log,"SocketThread connect io exception = "+e.getMessage());
                        onDataReceiveListener.onConnectFail();
                        disconnect();
                    }
                    e.printStackTrace();
                    return;
                }
                Log.d(TAG_log,"SocketThread connect over ");
    
    
                //read ...
                while (isConnect() && !isStop && !isInterrupted()) {
    
                    int size;
                    try {
                        byte[] buffer = new byte[1024];
                        if (mInputStream == null) return;
                        size = mInputStream.read(buffer);//null data -1 , zrd serial rule size default 10
                        if (size > 0) {
                            if (null != onDataReceiveListener) {
                                onDataReceiveListener.onDataReceive(buffer, size, requestCode);
                            }
                        }
                        Log.i(TAG_log, "SocketThread read listening");
                        //Thread.sleep(100);//log eof
                    }
                    catch (IOException e) {
                        if (null != onDataReceiveListener) {
                            Log.e(TAG_log,"SocketThread read io exception = "+e.getMessage());
                            onDataReceiveListener.onConnectFail();
                            disconnect();
                        }
                        e.printStackTrace();
                        return;
                    }
                }
            }
        }
    
    
    
        //==============================socket connect============================
        /**
         * connect socket in thread
         * Exception : android.os.NetworkOnMainThreadException
         * */
        public void connect(String ip, int port){
            mSocketThread = new SocketThread(ip, port);
            mSocketThread.start();
        }
    
        /**
         * socket is connect
         * */
        public boolean isConnect(){
            boolean flag = false;
            if (mSocket != null) {
                flag = mSocket.isConnected();
            }
            return flag;
        }
        
        /**
         * socket disconnect
         * */
        public void disconnect() {
            isStop = true;
            try {
                if (mOutputStream != null) {
                    mOutputStream.close();
                }
    
                if (mInputStream != null) {
                    mInputStream.close();
                }
    
                if (mSocket != null) {
                    mSocket.close();
                    mSocket = null;
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            if (mSocketThread != null) {
                mSocketThread.interrupt();//not intime destory thread,so need a flag
            }
        }
    
    
    
        /**
         * send byte[] cmd
         * Exception : android.os.NetworkOnMainThreadException
         * */
        public void sendByteCmd(final byte[] mBuffer,int requestCode) {
            this.requestCode = requestCode;
    
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        if (mOutputStream != null) {
                            mOutputStream.write(mBuffer);
                            mOutputStream.flush();
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
    
        }
    
    
        /**
         * send string cmd to serial
         */
        public void sendStrCmds(String cmd, int requestCode) {
            byte[] mBuffer = cmd.getBytes();
            sendByteCmd(mBuffer,requestCode);
        }
    
    
        /**
         * send prt content cmd to serial
         */
        public void sendChsPrtCmds(String content, int requestCode) {
            try {
                byte[] mBuffer = content.getBytes("GB2312");
                sendByteCmd(mBuffer,requestCode);
            }
            catch (UnsupportedEncodingException e1){
                e1.printStackTrace();
            }
        }
    
        
        /**
         * socket response data listener
         * */
        private OnDataReceiveListener onDataReceiveListener = null;
        private int requestCode = -1;
        public interface OnDataReceiveListener {
            public void onConnectSuccess();
            public void onConnectFail();
            public void onDataReceive(byte[] buffer, int size, int requestCode);
        }
        public void setOnDataReceiveListener(
                OnDataReceiveListener dataReceiveListener) {
            onDataReceiveListener = dataReceiveListener;
        }
        
    
    }
    
    MainActivity.java:使用,简单明了
    private void initListener(){
            //socket connect
            btn_connect.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    String ip = et_ip.getText().toString();
                    String port = et_port.getText().toString();
    
                    if(TextUtils.isEmpty(ip)){
                        Toast.makeText(MainActivity.this,"IP地址为空",Toast.LENGTH_SHORT).show();
                        return;
                    }
                    if(TextUtils.isEmpty(port)){
                        Toast.makeText(MainActivity.this,"端口号为空",Toast.LENGTH_SHORT).show();
                        return;
                    }
    
                    connect(ip, Integer.parseInt(port));
                }
            });
    
            //socket disconnect
            btn_disconnect.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    disconnect();
                }
            });
    
            //socket send
            btn_send.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (SocketClient.getInstance().isConnect()) {
                        byte[] data = et_send.getText().toString().getBytes();
                        send(data);
                    } else {
                        Toast.makeText(MainActivity.this,"尚未连接,请连接Socket",Toast.LENGTH_SHORT).show();
                    }
                }
            });
    
            //clear receive
            btn_clear.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    tv_receive.setText("");
                }
            });
        }
    
        /**
         * socket data receive
         * */
        private void initDataReceiver(){
            SocketClient.getInstance().setOnDataReceiveListener(dataReceiveListener);
        }
    
        /**
         * socket connect
         * */
        private void connect(String ip, int port){
            SocketClient.getInstance().connect(ip, port);
        }
    
        /**
         * socket disconnect
         * */
        private void disconnect(){
            SocketClient.getInstance().disconnect();
            tv_state.setText("未连接");
        }
    
        /**
         * socket send
         * */
        private void send(byte[] data){
            SocketClient.getInstance().sendByteCmd(data,1001);
        }
    
    
        /**
         * socket data receive
         * data(byte[]) analyze
         * */
        private SocketClient.OnDataReceiveListener dataReceiveListener = new SocketClient.OnDataReceiveListener() {
            @Override
            public void onConnectSuccess() {
                Log.i(TAG_log,"onDataReceive connect success");
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        tv_state.setText("已连接");
                    }
                });
    
            }
    
            @Override
            public void onConnectFail() {
                Log.e(TAG_log,"onDataReceive connect fail");
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        tv_state.setText("未连接");
                    }
                });
    
            }
    
            @Override
            public void onDataReceive(byte[] buffer, int size, int requestCode) {
                //获取有效长度的数据
                byte[] data = new byte[size];
                System.arraycopy(buffer, 0, data, 0, size);
    
                final String oxValue = Arrays.toString(HexUtil.Byte2Ox(data));
                Log.i(TAG_log,"onDataReceive requestCode = "+requestCode + ", content = "+oxValue);
    
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        tv_receive.setText(tv_receive.getText().toString() + oxValue + "\n");
                    }
                });
    
            }
        };
    
    
    
        @Override
        protected void onDestroy() {
            SocketClient.getInstance().disconnect();
            super.onDestroy();
        }
    

    2019 (* ̄(oo) ̄) 诸事顺利!

    相关文章

      网友评论

        本文标题:Android 基于TCP/IP的Socket通信

        本文链接:https://www.haomeiwen.com/subject/drnpeqtx.html