美文网首页
客户端的Socket

客户端的Socket

作者: 编程的猫 | 来源:发表于2020-03-08 21:40 被阅读0次
    什么是Socket?

    socket是一个编程调用接口,不是一种协议,是属于传输层,主要解决数据如何在网络中传输。通过Socket,我们才能在Andorid平台上通过 TCP/IP协议进行开发,实现客户端和服务端双向的通信连接。

    IP 协议
    • 即互联网协议(Internet Protocol),用于报文交换网络的一种面向数据的协议,是TCP/IP协议中网络层的主要协议。
    • 作用:根据源主机和目的主机的地址传送数据。
    • IP定义了寻址方法和数据报的封装结构。(IPv4、IPv6)
    TCP协议
    • TCP/IP模型中,面向连接的、可靠的、基于字节流的传输层通信协议;
    传输层存在的意义:

    应用层之间需要可靠的,像管道一样的连接,但网络层不提供这样的流机制,只提供不可靠的包交换,因此需要传输层的协调。

    TCP协议作用:
    • TCP协议把应用层向传输层发送网间传输的、用8位字节表示的数据流分成适当长度的报文段(受数据链路层最大传输单元MTU限制);
    • 把包传给网络层,由网络层将包传送给接收端实体的传输层;TCP为了不发生丢包,给每个包一个序号,同时序号保证了传送到接收端实体的包能按序接收。然后接收实体成功收到包后回复相应的ACK确认;
    • 如果发送端实体在合理的往返时延(RTT)内未收到确认,那么对应的数据包就会被认为丢失,将被重传;
    • TCP协议用一个校验和(Checksum)函数来检验数据是否错误,发送与接收时候都需要计算校验和。
    UDP协议
    • TCP/IP模型中面向无连接的传输层协议,提供面向事务的简单不可靠信息传输服务。
    • UDP不提供对IP协议的可靠机制、流控制以及错误恢复功能等,在数据传输之前不需要简历连接。
    • 由于UDP较简单,因此比TCP负载消耗少。
    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连接失败。

    tcp-socket的客户端
    /**
     * Created by wujn on 2019/2/15.
     * Version : v1.0
     * Function: tcp client  长度无限制
     */
    public class TcpClient {
    
    
        /**
         * single instance TcpClient
         * */
        private static TcpClient mSocketClient = null;
        private TcpClient(){}
        public static TcpClient getInstance(){
            if(mSocketClient == null){
                synchronized (TcpClient.class) {
                    mSocketClient = new TcpClient();
                }
            }
            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;
    
                        uiHandler.sendEmptyMessage(1);
                    }
                    /* 此处这样做没什么意义不大,真正的socket未连接还是靠心跳发送,等待服务端回应比较好,一段时间内未回应,则socket未连接成功 */
                    else{
                        uiHandler.sendEmptyMessage(-1);
                        Log.e(TAG_log,"SocketThread connect fail");
                        return;
                    }
    
                }
                catch (IOException e) {
                    uiHandler.sendEmptyMessage(-1);
                    Log.e(TAG_log,"SocketThread connect io exception = "+e.getMessage());
                    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) {
                            Message msg = new Message();
                            msg.what = 100;
                            Bundle bundle = new Bundle();
                            bundle.putByteArray("data",buffer);
                            bundle.putInt("size",size);
                            bundle.putInt("requestCode",requestCode);
                            msg.setData(bundle);
                            uiHandler.sendMessage(msg);
                        }
                        Log.i(TAG_log, "SocketThread read listening");
                        //Thread.sleep(100);//log eof
                    }
                    catch (IOException e) {
                        uiHandler.sendEmptyMessage(-1);
                        Log.e(TAG_log,"SocketThread read io exception = "+e.getMessage());
                        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();
            }
        }
    
    
        Handler uiHandler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                switch(msg.what){
                    //connect error
                    case -1:
                        if (null != onDataReceiveListener) {
                            onDataReceiveListener.onConnectFail();
                            disconnect();
                        }
                        break;
    
                    //connect success
                    case 1:
                        if (null != onDataReceiveListener) {
                            onDataReceiveListener.onConnectSuccess();
                        }
                        break;
    
                    //receive data
                    case 100:
                        Bundle bundle = msg.getData();
                        byte[] buffer = bundle.getByteArray("data");
                        int size = bundle.getInt("size");
                        int mequestCode = bundle.getInt("requestCode");
                        if (null != onDataReceiveListener) {
                            onDataReceiveListener.onDataReceive(buffer, size, mequestCode);
                        }
                        break;
                }
            }
        };
    
        
        /**
         * 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(TcpActivity.this,"IP地址为空",Toast.LENGTH_SHORT).show();
                        return;
                    }
                    if(TextUtils.isEmpty(port)){
                        Toast.makeText(TcpActivity.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 (TcpClient.getInstance().isConnect()) {
                        byte[] data = et_send.getText().toString().getBytes();
                        send(data);
                    } else {
                        Toast.makeText(TcpActivity.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(){
            TcpClient.getInstance().setOnDataReceiveListener(dataReceiveListener);
        }
    
        /**
         * socket connect
         * */
        private void connect(String ip, int port){
            TcpClient.getInstance().connect(ip, port);
        }
    
        /**
         * socket disconnect
         * */
        private void disconnect(){
            TcpClient.getInstance().disconnect();
            tv_state.setText("未连接");
        }
    
        /**
         * socket send
         * */
        private void send(byte[] data){
            TcpClient.getInstance().sendByteCmd(data,1001);
        }
    
    
        /**
         * socket data receive
         * data(byte[]) analyze
         * */
        private TcpClient.OnDataReceiveListener dataReceiveListener = new TcpClient.OnDataReceiveListener() {
            @Override
            public void onConnectSuccess() {
                Log.i(TAG_log,"onDataReceive connect success");
                tv_state.setText("已连接");
            }
    
            @Override
            public void onConnectFail() {
                Log.e(TAG_log,"onDataReceive connect fail");
                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);
    
                tv_receive.setText(tv_receive.getText().toString() + oxValue + "\n");
    
            }
        };
    
    
    
        @Override
        protected void onDestroy() {
            TcpClient.getInstance().disconnect();
            super.onDestroy();
        }
    

    参考博文:
    https://www.jianshu.com/p/4fca571f8a74
    https://www.jianshu.com/p/7dac7e5dffb2
    https://www.jianshu.com/p/089fb79e308b
    OkSocket库:https://www.jianshu.com/p/8ee3ee766265

    相关文章

      网友评论

          本文标题:客户端的Socket

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