zoukankan      html  css  js  c++  java
  • atomQQ 笔记 之 聊天消息、状态消息等各种消息的轮询

    要做一个im软件,消息收发的即时性就是灵魂了,我在atomQQ中,使用了service来进行对服务器的消息轮询(-_-!! 除了service还能用啥呢。。)

    这里首先说明webqq3的消息轮询机制

    通过抓包发现,webqq接受各种即时消息是通过这个post http://d.web2.qq.com/channel/poll2这个地址实现的

    POST http://d.web2.qq.com/channel/poll2

    这个提交的超时时间要长,一定要长,服务器是这样给你推送消息的:

    * 客户端首先post上面那个地址,并在一个长时间内等待服务器返回

    * 服务器检查是否有没有推送出去的消息,如果没有,而且打到了服务器自己的超时时间,则会返回一个标准json:

      {"retcode":21,"result":"error"}

    * 服务器有消息推送的话,返回的result就不是字符串了。

    我在service中是通过两个线程来获取消息内容,首先同时开启两个线程,第二个线程被阻塞等待,第一个线程只要在httpUrlConnection中得到一个返回,立马把第二个线程的阻塞状态取消,即刻Post服务器的轮询地址,这样,不管消息有多密集,在即时性方面有很大的提高。

    具体代码如下:

      1 **
    2 * 消息轮询器,用以获取各种即时消息,上到系统消息,下到聊天消息
    3 * @author 作者 E-mail:hangxin1940@gmail.com
    4 * @version 创建时间:2011-9-3 上午01:45:15
    5 */
    6 public class MessagePoll {
    7 private boolean beRun;
    8
    9 private String pars;
    10 private Thread pollThread;
    11 private Thread pollHandler;
    12 private BlockingQueue<String> threadQueue;
    13
    14 private Context service;
    15
    16 public MessagePoll(Context service) throws Exception {
    17 this.service=service;
    18 JSONObject r=new JSONObject();
    19 String clientid=CookieUtil.getCookieValue("clientid");
    20
    21 r.put("clientid", clientid);
    22 String psession=CookieUtil.getCookieValue("psessionid");
    23 r.put("psessionid",psession );
    24 r.put("key", 0);
    25 JSONArray ja=new JSONArray();
    26 r.put("ids", ja);
    27
    28
    29 pars="r="+URLEncoder.encode(r.toString(),"UTF-8")+"&clientid="+clientid+"&psessionid="+psession;
    30
    31 }
    32
    33 /** 这里用来进行一个持久的访问连接*/
    34 private Runnable pollRuner=new Runnable() {
    35
    36 @Override
    37 public void run() {
    38 HttpPostConnction conn=new HttpPostConnction(URLs.MESSAGE_POLL, pars);
    39 String result;
    40 while(beRun){
    41 try {
    42 result=conn.connect(URLs.REFER_d_web2_qq_com_proxy);
    43 threadQueue.put(result);
    44 } catch (Exception e) {
    45 e.printStackTrace();
    46 }
    47 }
    48 }
    49 };
    50
    51 /**这里用来处理服务器发送来的数据*/
    52 private Runnable handlerRunner=new Runnable() {
    53
    54 @Override
    55 public void run() {
    56
    57
    58 while(beRun){
    59 try {
    60 String result=(String) threadQueue.take();
    61 JSONObject re=new JSONObject(result);
    62 int retcode=re.getInt("retcode");
    63 //如果是消息,组装成非标准bean
    64 if(retcode==0){
    65
    66
    67
    68 JSONArray res=new JSONArray();
    69 try{
    70 res=re.getJSONArray("result");
    71 }catch (Exception e) {
    72 Log.e("Result",result);
    73 }
    74 for(int i=0;i<res.length();i++){
    75 JSONObject message=res.getJSONObject(i);
    76 String poll_type=message.getString("poll_type");
    77
    78
    79 //如果是群消息
    80 if("group_message".equals(poll_type)){
    81 GroupMessage gmessage=new GroupMessage();
    82
    83 JSONObject value=message.getJSONObject("value");
    84 gmessage.msg_id=value.getInt("msg_id");
    85 gmessage.from_uin=Long.toString(value.getLong("from_uin"));
    86 gmessage.to_uin=Long.toString(value.getLong("to_uin"));
    87 gmessage.msg_id2=value.getInt("msg_id2");
    88 gmessage.msg_type=value.getInt("msg_type");
    89 gmessage.reply_ip=Long.toString(value.getLong("reply_ip"));
    90 gmessage.group_code=Long.toString(value.getLong("group_code"));
    91 gmessage.send_uin=Long.toString(value.getLong("send_uin"));
    92 gmessage.seq=value.getInt("seq");
    93 gmessage.time=value.getLong("time")*1000;
    94 gmessage.info_seq=Long.toString(value.getLong("info_seq"));
    95
    96 JSONArray content=value.getJSONArray("content");
    97 MessageContent mcontent=getContent(content);
    98 gmessage.content=mcontent;
    99
    100 Intent intent=new Intent("org.atom.reciver");
    101 intent.putExtra("group_message", gmessage);
    102 sendMessage(intent);
    103 }
    104 //如果是好友信息
    105 else if("message".equals(poll_type)){
    106 FriendMessage fmessage=new FriendMessage();
    107
    108 JSONObject value=message.getJSONObject("value");
    109 fmessage.msg_id=value.getInt("msg_id");
    110 fmessage.from_uin=Long.toString(value.getLong("from_uin"));
    111 fmessage.msg_id2=value.getInt("msg_id2");
    112 fmessage.msg_type=value.getInt("msg_type");
    113 fmessage.reply_ip=Long.toString(value.getLong("reply_ip"));
    114 fmessage.time=value.getLong("time")*1000;
    115
    116 JSONArray content=value.getJSONArray("content");
    117 MessageContent mcontent=getContent(content);
    118 fmessage.content=mcontent;
    119
    120 Intent intent=new Intent("org.atom.reciver");
    121 intent.putExtra("friend_message", fmessage);
    122 sendMessage(intent);
    123
    124 }
    125 //如果是好友状态信息
    126 else if("buddies_status_change".equals(poll_type)){
    127
    128 FriendStatusMessage fsmessage=new FriendStatusMessage();
    129
    130 JSONObject value=message.getJSONObject("value");
    131 fsmessage.client_type=value.getInt("client_type");
    132 fsmessage.uin=Long.toString(value.getLong("uin"));
    133 fsmessage.status=value.getString("status");
    134
    135 Intent intent=new Intent("org.atom.reciver");
    136 intent.putExtra("friend_status_message", fsmessage);
    137 sendMessage(intent);
    138 }
    139
    140
    141 }
    142
    143
    144 }
    145
    146
    147 } catch (Exception e) {
    148 e.printStackTrace();
    149 }
    150 }
    151 }
    152
    153 /**获取消息内容
    154 * @throws JSONException */
    155 private MessageContent getContent(JSONArray content) throws JSONException{
    156 MessageContent mcontent=new MessageContent();
    157
    158
    159 //获取字体信息
    160 JSONArray font=content.getJSONArray(0);
    161 mcontent.font_color=font.getJSONObject(1).getString("color");
    162 mcontent.font_size=font.getJSONObject(1).getInt("size");
    163
    164 for(int i=1;i<content.length();i++){
    165 ChatMessage cmessage=new ChatMessage();
    166
    167
    168 String v=content.getString(i);
    169
    170 //如果当前信息是个图片
    171 if(v.startsWith("[")){
    172
    173 JSONArray m=new JSONArray(v);
    174 String type=m.getString(0);
    175 Log.e("图片json", m.toString());
    176
    177 //如果是默认表情
    178 if("face".equals(type)){
    179 cmessage.type=ChatMessage.FACE;
    180 cmessage.face=String.format("%03d", m.getInt(1));
    181 }
    182 //如果是个自定义表情或图片
    183 else if("cface".equals(type)){
    184 cmessage.type=ChatMessage.CFACE;
    185 cmessage.message=m.getString(1);
    186 }
    187 //如果是个离线图片
    188 else if("offpic".equals(type)){
    189 cmessage.type=ChatMessage.CFACE;
    190 JSONObject path=m.getJSONObject(1);
    191 cmessage.message=path.getString("file_path");
    192 cmessage.success=path.getInt("success");
    193 }
    194
    195 }
    196 //如果是文字信息
    197 else{
    198 cmessage.type=ChatMessage.TEXT;
    199 cmessage.message=v;
    200 }
    201
    202 mcontent.addChatMessage(cmessage);
    203
    204 }
    205
    206
    207 return mcontent;
    208 }
    209 };
    210
    211 /**开始轮询服务器*/
    212 public void startPoll(){
    213 beRun=true;
    214
    215 threadQueue= new ArrayBlockingQueue<String>(1);
    216
    217 pollThread=new Thread(pollRuner);
    218 pollHandler=new Thread(handlerRunner);
    219
    220 pollThread.start();
    221 pollHandler.start();
    222 }
    223
    224 /**自己消化消息或者发送消息*/
    225 private void sendMessage(Intent message){
    226 //如果主程序是打开状态,发送出去
    227 if(true){
    228 service.sendBroadcast(message);
    229 }
    230 }
    231
    232
    233
    234
    235
    236 }

      

    最后,在每次获得消息后,自行组装成bean,通过广播等什么方法发送出去就行了。

  • 相关阅读:
    《认知突围》摘抄
    《java多线程编程核心技术》----ThreadLocal
    java有必要记录的东西
    spring源码几个servlet功能的介绍
    基于openapi3.0的yaml文件生成java代码的一次实践
    Android攻城狮 调试
    Android攻城狮 http协议
    Android攻城狮 Android中更新UI的几种方式
    Android攻城狮 Handler与子线程
    Android攻城狮Handler简介
  • 原文地址:https://www.cnblogs.com/hangxin1940/p/2174973.html
Copyright © 2011-2022 走看看