即时通讯实现

2016-6-1 chenhui 随笔

本文整理自博主以前做的仿微信项目源代码以及笔记。


即时通讯本身比较简单,所以本文就大概说一下要点。


即时通讯是网络应用,所以他除了一个 Android 客户端以外,还需要实现一个服务端。

服务端的实现可以有两种:

  1. 使用 PHP 此类 Web 后台开发常用的语言(好吧,Web 后台开发我只会 PHP)
  2. 使用 C、C++、Java 等语言

这两种方法的区别主要是:第一种实现起来简单,但因为不能做长连接,因此做不了推送,一般需要第三方来做推送;第二种稍微复杂一些,但能解决推送问题。


怎么做到既能实现推送,又能达到比较高的开发效率呢?比较好的方法是两个方法结合起来:我们在做增删改查等比较简单的工作时,使用 PHP,同时再用 C/C++/Java 等语言编写一个推送服务器,客户端和推送服务器建立一个长连接,当 PHP 收到消息并发现接收者在线时,就通知推送服务器把消息发送给接收者。


当然,如果你想干脆不这么麻烦,用 C++ 或 Java 一次性解决掉他们(这可能会使你付出更大的代价),那就一定要注意网络状态和 Android 特有的特性:只有线程才能访问网络。由于 Android 只有线程才能访问网络,所以多个网络操作会导致多个线程同时操作 Socket,这会导致数据的混乱,以至于服务器无法识别数据,也就是说你需要对 Socket 的操作进行同步或者一些其他的处理。


对于这个问题,我当时并没有使用同步的方式。当时的解决方法是:创建两个线程,一个专门发送数据,令专门接收数据,他们各和服务端建立长连接。前者不停地读一个管道,后者不停地读推送Socket,由于管道和 Socket 没数据他们就会被阻塞;然后再设置一个队列,队列里放置描述了网络操作的对象,如发送的数据以及数据返回时的回调方法。当我们要发送一个数据时,就创建网络操作对象存入队列,然后往管道里写一个数据唤醒线程,线程把数据发送出去后继续阻塞在管道上。服务器返回数据时,读线程被唤醒,然后从队列中取出网络操作对象,并执行回调函数来处理返回的数据。


如果服务器是单线程模型,那么直接队列头部取出即可,因为顺序肯定不会乱;如果服务器是多线程模式,那么多个请求可能完成的时间不一样,那么网络操作对象就要有一个独一无二的 ID,发送数据时带上他,服务端返回数据时也带上他,以此来找到对应的网络操作对象。


注意,若回调方法里要操作 View,则一定要使用 Handler。


发表评论:

Copyright ©2015-2016 freehui All rights reserved