Android推送的核心原理:长连接的简单实现

实际需求

移动端需要实时的获取服务器的数据

解决方案

  1. 轮询方式:应用程序开启定时的轮询,不停的向服务器请求数据。
  2. SMS push:发送二进制短信到移动终端,来达到通知终端的目的。客户端拦截这类短信,然后采取相应的操作
  3. 持久连接方式:应用程序与服务器建立一个长连接,使服务器可以随时的与手机端通信

方案分析

  • 方法一:轮询频率过高,则太过消耗性能,轮询频率低,则数据显示不及时,不可取
  • 方式二:android短信push的关键在于拦截短信,一旦拦截到了短信,可以利用android自带的特性去完成后续操作,比如可以Push notification,可以Toast,可以发起连接服务器的请求,客户端应用不在线时,可以发一个Intent启动该应用然后再进行处理。单由于是短信的方式,就势必要涉及通信收费的问题,当需要推送的消息多的时候,就会产生很大的额外开销
  • 方式三:这种方式可以比较好的解决上面两种方式的弊端,也是下文中要分析的方式

Socket

持久化连接就是所谓的长连接,现在基本上不会使用原生的Socket来实现长连接,都是使用第三方的推送服务,如极光推送、小米推送等,这里只是使用Socket来简要说明长连接的原理

概念

Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个外观模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。
这里写图片描述

交互如下:
这里写图片描述

服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客户端连接。在这时如果有个客户端初始化一个Socket,然后连接服务器(connect),如果连接成功,这时客户端与服务器端的连接就建立了。客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束

长连接和短连接

整个通讯过程,客户端和服务端只用一个Socket对象,长期保持Socket的连接,这种称之为“长连接”;每一次请求都新建一个Socket,处理完成之后直接关闭Socket,这种称之为“短连接”。所以,其实区分长短连接就是:整个客户和服务端的通讯过程是利用一个Socket还是多个Socket进行的

我们在eclipse中新建两个Java工程SocketClient、SocketServer来来模拟客户端和服务器端

客户端:SocketClient
功能:既可以主动的向服务器端发送信息,也可以被动的接收服务器发来的消息

public class SocketClient {

    public static void main(String[] args) {
        SocketClient client = new SocketClient();
        client.start();
    }

    private void start() {
        BufferedReader inputReader = null;
        BufferedReader reader = null;
        BufferedWriter writer = null;
        Socket socket = null;

        try {
            // 连接目标
            socket = new Socket("192.168.1.101", 9898);
            // 读取socket的内容
            reader = new BufferedReader(new InputStreamReader(
                    socket.getInputStream()));
            // 写入socket的内容
            writer = new BufferedWriter(new OutputStreamWriter(
                    socket.getOutputStream()));

            // 获取控制台输入
            inputReader = new BufferedReader(new InputStreamReader(System.in));

            // 对服务器的监听,收到来自服务器的内容
            startServerReplyListener(reader);

            // 控制台输入
            String inputContent;
            while (!(inputContent = inputReader.readLine()).equals("bye")) {
                //向服务器主动发送消息
                writer.write(inputContent+"\n");
                writer.flush();
            }


        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                //注意这里的关闭socket是为了客户端出现异常的时候关闭,正常是执行try块的while()循环
                reader.close();
                writer.close();
                inputReader.close();
                socket.close();

            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private void startServerReplyListener(final BufferedReader reader) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    String response;
                    while ((response = reader.readLine()) != null) {
                        System.out.println(response);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();

    }
}

服务器:SocketServer
功能:可主动的接收客户端的信息,主动的推送消息给客户端

package com.zsk.server;

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

public class SocketServer {

    public static void main(String[] args) {
        SocketServer socketServer = new SocketServer();
        socketServer.startServer();
    }

    private void startServer(){
        ServerSocket serverSocket = null;
        Socket socket = null;
        try {
            serverSocket = new ServerSocket(9898);
            System.out.println("服务已开启...");
            while(true){
                //当没有Socket连接时,阻塞
                socket = serverSocket.accept();
                //管理连接
                manageConnection(socket);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally{
            try {
                socket.close();
                serverSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private void manageConnection(final Socket socket){
        new Thread(new Runnable() {
            @Override
            public void run() {
                BufferedReader reader = null;
                BufferedWriter writer = null;
                try {
                    System.out.println("client:"+socket.hashCode()+"已连接");
                    reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                    writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
                    String receivedMsg;

                    /**
                    这一段可以模拟服务器端主动推送消息,只不过太过粗糙
                    new Timer().schedule(new TimerTask() {
                        @Override
                        public void run() {

                            try {
                                writer.write("server reply: " + "服务器推送!!!" + "\n");
                                writer.flush();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }

                        }
                    }, 3000,3000);
                    */

                    //将接收到的数据,重新返回给客户端
                    while((receivedMsg = reader.readLine()) != null) {
                        System.out.println("client"+socket.hashCode()+receivedMsg);
                        writer.write("server reply: " + receivedMsg + "\n");
                        writer.flush();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                } finally{
                    try {
                        reader.close();
                        writer.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }

            }   
        }).start();
    }
}

在服务器SocketServer中可以看到,每一次的连接都是新开一个线程,这就是很大的一个弊端,当有很多的连接的时候,比方说数十万的连接时,这种高并发的情况对于这种处理方法是不可取的,同时这种方式是阻塞式的,需要开线程去进行维护,考虑到这种情况,Java1.4之后新加了nio可以提供多路非阻塞式的高伸缩性网络,但是这种方式使用十分复杂,所以多是采用基于nio的第三方框架如Mina、Nety

https://www.cnblogs.com/wangcq/p/3520400.html
https://www.jianshu.com/p/b9f3f6a16911

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 在Android实现WebSocket长连接,可以通过以下步骤来实现: 1. 导入WebSocket库:首先,需要在Android项目的build.gradle文件中添加WebSocket库的依赖项。例如,在dependencies块中添加以下代码: ```java implementation 'org.java-websocket:Java-WebSocket:1.5.1' ``` 2. 创建WebSocket客户端:在需要使用WebSocket长连接的地方,创建一个WebSocket客户端对象。例如,可以在Activity或Fragment中创建WebSocketClient对象。 ```java WebSocketClient mWebSocketClient = new WebSocketClient(URI.create("ws://your_server_url"), new Draft_17()) { // WebSocket事件回调方法 @Override public void onOpen(ServerHandshake serverHandshake) { // 连接成功后的处理逻辑 } @Override public void onMessage(String message) { // 接收到服务器发送的消息时的处理逻辑 } @Override public void onClose(int code, String reason, boolean remote) { // 连接关闭时的处理逻辑 } @Override public void onError(Exception ex) { // 连接发生错误时的处理逻辑 } }; ``` 3. 连接WebSocket服务器:调用WebSocketClient对象的connect()方法来连接WebSocket服务器。 ```java mWebSocketClient.connect(); ``` 4. 发送和接收消息:可以使用WebSocketClient对象的send()方法发送消息,并在onMessage()方法中接收服务器发送的消息。 ```java mWebSocketClient.send("Hello, Server!"); ``` 5. 关闭WebSocket连接:当不再需要长连接时,可以调用WebSocketClient对象的close()方法来关闭WebSocket连接。 ```java mWebSocketClient.close(); ``` 注意:以上代码只是简单示例,实际使用时可能需要根据具体需求进行适当的改进和处理,例如添加重连机制、处理心跳包等。 ### 回答2: Android实现WebSocket长连接可以使用Java开发,具体步骤如下: 1. 引入相应的WebSocket依赖库,如Java-WebSocket库。 2. 创建一个WebSocket连接类,继承自WebSocketClient类,并实现其中的各个回调方法。 3. 在连接类中,重写onOpen()方法,在该方法中进行WebSocket连接的初始化和握手操作。 4. 重写onMessage()方法,用于接收服务器发送的消息,可以在此方法中处理收到的消息。 5. 重写onClose()方法,处理WebSocket连接关闭的逻辑。 6. 重写onError()方法,处理WebSocket连接发生错误的逻辑。 7. 在需要使用WebSocket长连接的地方,创建WebSocket连接对象,传入服务器的WebSocket地址和端口号等参数。 8. 调用WebSocket连接对象的connect()方法,发起WebSocket连接。 9. 可以通过WebSocket连接对象的send()方法发送消息给服务器。 10. 在连接不需要时,调用WebSocket连接对象的close()方法关闭WebSocket连接。 总结:通过引入相应的WebSocket依赖库,并创建WebSocket连接类来实现WebSocket长连接,可以实现Android应用与服务端的实时通讯。在连接的各个回调方法中,可以处理接收到的消息和连接关闭等事件。使用WebSocket连接对象的connect()方法发起连接,send()方法发送消息,close()方法关闭连接。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值