Android技术知识Android开发Android开发

Android 基于TCP/IP的Socket通信

2019-02-15  本文已影响13人  Kandy_JS

参考

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) ̄) 诸事顺利!

上一篇下一篇

猜你喜欢

热点阅读