Android开发:长连接通信设计与实现

一.前言

Android长连接应用于服务器需要主动通知客户端的一些场景,例如推送消息和即时通讯。除了接入第三方SDK来实现外,在业务要求不是很高的情况下,完全可以自己编写一套实现方案。

二.正文

Android客户端长连接通信通过TCP协议的套接字(Socket)实现。下面通过对Socket的封装来实现长连接通信:

  • ClientSocket:Socket创建、连接和数据传输;
  • SocketInterface:Socket运行周期回调接口;
  • ClientService:业务逻辑处理。

 (1)ClientSocket通过开启一个线程来进行Socket的创建和连接,连接成功后,等待服务器信息,并按照text协议(以“\n”结尾的字符串)来读取输入流。

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.InetSocketAddress;
import java.net.Socket;

public class ClientSocket {
    //连接超时时间(ms)
    private int TIME_OUT = 3000;
    //远程ip地址
    private String host;
    //远程端口
    private int port;
    //socket对象
    private Socket socket;
    //输出流
    private BufferedWriter bufferedWriter;
    //输入流(text协议)
    private BufferedReader bufferedReader;
    //回调接口
    private SocketInterface socketInterface;
    //socket是否正常运行中
    private boolean isRunning = false;

    /**
     * 设置通信地址
     *
     * @param host 主机ip
     * @param port 端口
     */
    public void setAddress(String host, int port) {
        this.host = host;
        this.port = port;
    }

    /**
     * 开启(子线程)
     */
    public void start() {
        new Thread(this::connect).start();
    }

    /**
     * 开始连接
     */
    private void connect() {
        //连接
        try {
            this.socket = new Socket();
            this.socket.connect(new InetSocketAddress(this.host, this.port), this.TIME_OUT);
            this.socketInterface.onConnect();
            OutputStreamWriter outputStreamWriter = new OutputStreamWriter(this.socket.getOutputStream());
            this.bufferedWriter = new BufferedWriter(outputStreamWriter);
            InputStreamReader inputStreamReader = new InputStreamReader(this.socket.getInputStream());
            this.bufferedReader = new BufferedReader(inputStreamReader);
            this.isRunning = true;
            this.socketInterface.onReady();
        } catch (Exception e) {
            this.isRunning = false;
            this.socketInterface.onConnectFailure(e.getLocalizedMessage());
            return;
        }
        //接收数据
        try {
            while (isRunning) {
                String msg = bufferedReader.readLine();
                socketInterface.onMessage(msg);
            }
        } catch (Exception e) {
            isRunning = false;
        }
        //连接关闭
        socketInterface.onClose();
    }

    /**
     * 发送信息
     *
     * @param msg 信息体
     */
    synchronized public void send(String msg) {
        if (!this.isRunning) {
            return;
        }
        try {
            this.bufferedWriter.write(msg + "\n");
            this.bufferedWriter.flush();
        } catch (IOException e) {
            isRunning = false;
        }
    }

    /**
     * 关闭Socket连接
     */
    public void close() {
        if (isRunning) {
            try {
                socket.close();
                isRunning = false;
            } catch (IOException ignored) {
            }
        }
    }

    /**
     * @return 当前Socket运行状态
     */
    public boolean isRunning() {
        return this.isRunning;
    }

    /**
     * 设置Socket运行周期回调
     */
    public void setSocketInterface(SocketInterface socketInterface) {
        this.socketInterface = socketInterface;
    }
}

(2) SocketInterface 声明了简单接口,可按照实际情况来更改。

public interface SocketInterface {
    void onConnect();

    void onConnectFailure(String error);

    void onReady();

    void onMessage(String msg);

    void onClose();

}

 (3)ClientService 采用单例模式,只进行一个Socket通信,通过设置回调来进行逻辑处理。

public class ClientService {
    static ClientSocket clientSocket;
    static SocketInterface socketInterface;

    static {
        clientSocket = new ClientSocket();
        initSocketInterface();
    }

    /**
     * 开启通信服务
     *
     * @param host 主机ip
     * @param port 端口
     */
    static public void startService(String host, int port) {
        if (clientSocket.isRunning()) {
            return;
        }
        clientSocket.setAddress(host, port);
        clientSocket.setSocketInterface(socketInterface);
        clientSocket.start();
    }

    /**
     * 发送信息
     */
    static public void sendMessage(String msg) {
        if (clientSocket.isRunning()) {
            clientSocket.send(msg);
        }
    }

    /**
     * 关闭通信服务
     */
    static public void closeService() {
        clientSocket.close();
    }

    /**
     * 初始化回调
     */
    static private void initSocketInterface() {
        socketInterface = new SocketInterface() {
            @Override
            public void onConnect() {
                //成功连接
                LogUtil.log("onConnect");
            }

            @Override
            public void onConnectFailure(String error) {
                //连接失败,可根据错误类型进行相应处理,如重连
                LogUtil.log("onConnectFailure:" + error);
            }

            @Override
            public void onReady() {
                //已准备完毕,可进行发送信息,开启心跳线程等
                LogUtil.log("onReady");

            }

            @Override
            public void onMessage(String msg) {
                //服务器信息到达,进行业务处理
                LogUtil.log("onMessage:" + msg);
            }

            @Override
            public void onClose() {
                //连接关闭,此处可进行重连或清理操作
                LogUtil.log("onClose");
            }
        };
    }
}

在需要开启时候传入服务器ip和端口即可。 

//开启服务
ClientService.startService("192.168.1.102", 8080);

 这只是Android长连接通信的一个基本实现,实际情况还要考虑通信数据协议和通信保活问题。

三.结语

本文基于自身知识经验编写,只供参考学习,不足之处还请指正,欢迎伙伴们来一起探讨交流!

你可能感兴趣的:(Android开发,java,tcp/ip)