【Android】消息推送1-Socket长连接技术点总结

鉴于以往习惯,文章言简意赅,不拖泥带水,本文主要写Android消息推送中Socket长连接相关技术点。

1、TCP/IP 协议
(1)IP协议
IP 协议提供了主机和主机间的通信。采用IP地址来唯一标识一台主机。
(2)TCP协议

TCP 协议在 IP 协议提供的主机间通信功能的基础上,完成这两个主机上进程对进程的通信。我们采用端口号来标识数据属于哪个进程。

2、TCP三次握手 & 四次挥手


说明:SYN包和FIN包都会消耗一个序列号,纯ACK包不消耗序列号。

3、Socket 基本用法

Socket 是 TCP 层的封装。在 Java 的 SDK 中,socket 共有两个接口:用于监听客户连接的 ServerSocket 和用于通信的 Socket。使用 socket 的步骤如下:
(1)创建 ServerSocket 并监听客户连接。
(2)Socket 连接服务端。
(3)Socket 获取输入输出流进行通信。

(1)Socket客户端实现

public class SocketClient {

	public static void main(String[] args) {
		SocketClient client = new SocketClient();
		client.start();
	}
	
	public void start() {
		BufferedReader inputReader = null;
		BufferedReader reader = null;
		BufferedWriter writer = null;
		Socket socket = null;
		try {
			socket = new Socket("127.0.0.1", 9898);
			reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			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 (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				reader.close();
				writer.close();
				inputReader.close();
				socket.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	public 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 (IOException e) {
					e.printStackTrace();
				}
			}
		}).start();
	}

}

(2)Socket服务端实现

public class SocketServer {

	public static void main(String[] args) {
		SocketServer socketServer = new SocketServer();
		socketServer.startServer();
	}
	
	public void startServer() {
		ServerSocket serverSocket = null;
		Socket socket = null;
		try {
			serverSocket = new ServerSocket(9898);
			System.out.println("server started..");
			while (true) {
				socket = serverSocket.accept();
				manageConnection(socket);
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				socket.close();
				serverSocket.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	public 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() + " connedted");
					reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
					writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
					String receivedMsg;
					while ((receivedMsg = reader.readLine()) != null) {
						System.out.println("client " + socket.hashCode() + ": " + receivedMsg);
						writer.write("server reply: " + receivedMsg + "\n");
						writer.flush();
					}
				} catch (IOException e) {
					e.printStackTrace();
				} finally {
					try {
						reader.close();
						writer.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}
		}).start();
	}

}
4、Socket、ServerSocket区分
(1)ServerSocket
创建ServerSocket实例时,会先调用bind将该ServerSocket绑定到一个指定的地址(IP地址+port端口),然后调用SocketImpl的listen方法监听客户端连接。最后我们调用accept,阻塞等待客户端的连接,连接成功后返回一个通信socket实例。
(2)Socket
创建Socket实例时,会调用connect去跟server建立连接。


5、Socket长连接
Socket长连接,指的是在客户和服务端之间保持一个 socket 连接长时间不断开。
(1)Socket的setKeepAlive方法
这是TCP协议实现保活的一种策略。遗憾的是,生活并不总是那么美好。对于 4.4BSD 的实现来说,Socket 的这个 keep alive 选项如果打开并且两个小时内没有通信,那么底层会发一个心跳,看看对方是不是还活着。注意,两个小时才会发一次。也就是说,在没有实际数据通信的时候,我把网线拔了,你的应用程序要经过两个小时才会知道。
(2)心跳包在socket连接中的意义
通过socket连接的双方为了保证在一段时间未发消息不被防火墙断开连接或者使对方及时知道自己是否已经断线而定期给对方发送的某些特殊标识字符,这个字符可以根据双方自定义,没有实际的通讯意义。只要心还在跳,socket 就是活的。
(3)socket断线重连

6、Java IO & NIO
(1)java.nio
java.nio全称java non-blocking IO,是指jdk1.4 及以上版本里提供的新api(New IO) ,为所有的原始类型(boolean类型除外)提供缓存支持的数据容器,使用它可以提供非阻塞式的高伸缩性网络。它具有三大特性:Channel,Buffer,Selector。
Java API中提供了两套NIO,一套是针对标准输入输出NIO,另一套就是网络编程NIO。
(2)NIO和IO的主要区别
(a)IO是面向流的,NIO是面向缓冲区的。 Java IO面向流意味着每次从流中读一个或多个字节,直至读取所有字节,它们没有被缓存在任何地方。此外,它不能前后移动流中的数据。如果需要前后移动从流中读取的数据,需要先将它缓存到一个缓冲区。 Java NIO的数据读取到一个它稍后处理的缓冲区,需要时可在缓冲区中前后移动。这就增加了处理过程中的灵活性。
(b)Java IO的各种流是阻塞的。这意味着,当一个线程调用read() 或 write()时,该线程被阻塞,直到有一些数据被读取,或数据完全写入。该线程在此期间不能再干任何事情了。线程通常将非阻塞IO的空闲时间用于在其它通道上执行IO操作,所以一个单独的线程现在可以管理多个输入和输出通道(channel)。
(c)Java NIO的选择器selector允许一个单独的线程来监视多个通道,你可以注册多个通道使用一个选择器,然后使用一个单独的线程来“选择”通道。
(3)NIO和IO的使用场景
(a)NIO可让您只使用一个(或几个)线程管理多个通道,但付出的代价是解析数据可能会比从一个阻塞流中读取数据更复杂。如果需要管理同时打开的成千上万个连接,这些连接每次只是发送少量的数据,例如聊天服务器,实现NIO的服务器可能是一个优势。

(b)如果你有少量的连接使用非常高的带宽,一次发送大量的数据,也许典型的IO服务器实现可能非常契合。


7、离线消息推送
(1)原理:当服务器有message要发送给客户端C时,先检测C是否在线,如果在线,直接推送;如果不在线,暂存数据库DB中,等下次C启动连接服务器时再查询数据库重新推送。
(2)例如,创建数据库表notification,对应实体类如下:

public class Notification {
  private long id;//主键
  private String title;//标题
  private String message;//消息内容
  private String username;//接收消息的用户
  …
}
8、共享推送通道
  如果一个手机里有多个App使用了同一家推送服务,那么这些App将共用一条消息通道,即使你家的App推送服务被杀死了,那么只要用户打开了其他集成该推送服务的App,你家的推送就能到达用户。
  由于Android系统的机制,后台推送 Service 会被各种主动的或是被动的行为给杀死,而服务一旦被杀死,意味着就接收不到推送消息。
  手机厂商的推送服务在自家的手机上属于系统级别的服务,这意味着系统不会杀死自家的推送服务。比如说,Android原生系统是不会杀死C2DM消息推送服务,MIUI系统是不会杀死小米的推送服务。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值