现在的位置: 首页 > 综合 > 正文

atomQQ 笔记 之 聊天消息、状态消息等各种消息的轮询

2013年06月14日 ⁄ 综合 ⁄ 共 6007字 ⁄ 字号 评论关闭

要做一个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,通过广播等什么方法发送出去就行了。

抱歉!评论已关闭.