|
|
作者:Hackfan ; f$ L8 w* y9 ?, x' i8 w! c
日期:2005.8.21凌晨
8 s6 ^& I3 X: p联系:QQ:106814 Email:hackfan@vip.sina.com 5 U, v! g6 Q ]; U
* h+ G. B4 J/ n' F: A+ h+ \1、研究说明
+ [% a! L7 I F8 M& t/ H' _( A) }$ U' k4 J9 c& \5 a: L
Tencent在tqq.tencent.com的8000有一个使用HTTP的QQ接口,通过这个接口,可以进行一些基本的操作,如:登陆、登出、改变登陆状态(上线、忙碌、离线、隐身)、添加删除好友、查看好友信息、发送验证信息(接受被加为好友、申请加对方为好友、拒绝被加为好友)、收发用户消息、系统信息。
! E y2 L9 z1 n$ s4 R# ~, R! ^
目前我研究的是1.1版本的HTTP QQ协议,研究是微程在的成果上进行的,不敢说有什么超越,只不过更为详细和准确。 ' i+ @7 g& l, ^' _* Z, l% B
5 ~& _' l$ A p ?2、接口说明: # Z' H( P# D9 g/ {
- `" {+ d, a# h+ |$ h* R7 T. W
接口位置:tqq.tencent.com:8000 9 t. G* ]6 B7 u
通信协议:HTTP / j% O2 R- E7 n; x# G
数据传输方法:POST
2 a: l: T: T! Q2 B, S! i- E1 z HTTP请求格式:
& V/ O& W0 w3 _% [3 z# R4 C0 c# ~) E. c; \0 c7 E5 I
POST HTTP/1.1 ' g* U- ^1 I" t) t
Host: tqq.tencent.com:8000 $ a( n* c) E2 G3 i
Content-Type: text/plain; charset=UTF-8 3 y( L" b+ R% V
Content-length: 长度
% N5 f* |* S2 N# j" _Connection: close + a! e2 H: y/ S! E4 r6 I
: w7 p% R0 G, ~# C7 h: P
数据
( M/ Y" C' j- C6 m" P: \% U" U2 H) h; n; a; I1 u( W6 U7 V
其中长度为 数据 的长度,数据的格式:
- V8 o" G0 G: F7 S! C/ f/ i VER=1.1&CMD=命令&SEQ=标记&UIN=QQ号&....
; U; l) e6 D8 {7 u- X7 ^. G7 ^2 V7 O; J( s" k$ Q4 s# F
以上4个参数是每个请求都必有的。其中,VER表示协议的版本,目前为1.1,据说1.2已经出来了,这个乱写的话,服务器返回NULL; CMD为操作的指令,有Login、List、Query_Stat、GetInfo、AddToList、Ack_AddToList、 DelFromList、Change_Stat、GetMsgEx、CLTMSG、Logout;SEQ为当前请求的标记,防止重复发送,可以用当前时间,也可以用随机数;UIN是当前执行操作的QQ号。不过不同的CMD还需要不同的参数,下面我就公布我的研究成果。
9 ^5 T, }! d' u1 {
$ c$ H% U* p$ K2 J3、研究方法:
8 P, e9 b0 r1 |) R' I$ Q
+ u; Y0 ~8 O7 X, f) d 我对目前网上的资料不够满意,就自己写程序,发送多条相同CMD不同参数的请求,根据服务器的返回,来做判断。感兴趣的朋友可以参考一下,此处可以跳过。
6 G( c. Y/ A+ e, J4 d: N! \ 下面我公布我探测的代码(PHP):- <? $ D9 l p5 i" O7 m& |4 ]
- $uin = "QQ号";
) N; v: r6 C3 b2 N" y$ k/ G& ? - $pwd = md5("QQ密码"); D* l. a# h8 D8 l4 j
- 1 B; S G) K8 R- i6 Z& \! \" a
- //登陆测试 3 B0 V6 ?/ L* S- U; C" i
- $poststring[] = "VER=1.1&CMD=Login&SEQ=".rand(1000,9000)."&UIN=".$uin."&PS=".$pwd."&M5=1&LC=9326B87B234E7235"; . L/ d3 z/ J. Y! z9 k
- //注意:登陆测试不能同时进行,必须等到服务器认为QQ断开了,才能够测试,不然结果不可信 + L, k x. T. w" D. a1 n
- /******* " e: [8 Q' x# u
- $poststring[] = "VER=1.1&CMD=Login&SEQ=".rand(1000,9000)."&UIN=".$uin."&PS=".$pwd."&M5=0&LC=9326B87B234E7235"; & M/ z8 g( r6 k2 {2 M
- $poststring[] = "VER=1.1&CMD=Login&SEQ=".rand(1000,9000)."&UIN=".$uin."&PS=".$pwd."&M5=1&LC=9326B87B234E7235"; 0 T9 @$ g; f: D2 P* J V
- $poststring[] = "VER=1.1&CMD=Login&SEQ=".rand(1000,9000)."&UIN=".$uin."&PS=".$pwd."&M5=2&LC=9326B87B234E7235";
; ^! Q# l' v! m( Q( N2 \ - $poststring[] = "VER=1.1&CMD=Login&SEQ=".rand(1000,9000)."&UIN=".$uin."&PS=".$pwd."&M5=3&LC=9326B87B234E7235";
1 P7 F# n+ E0 p - $poststring[] = "VER=1.1&CMD=Login&SEQ=".rand(1000,9000)."&UIN=".$uin."&PS=".$pwd."&M6=1&LC=9326B87B234E7235"; # c) D/ q! j/ _, Y2 p& G! y) I2 l
- $poststring[] = "VER=1.1&CMD=Login&SEQ=".rand(1000,9000)."&UIN=".$uin."&PS=".$pwd."&M6=1&LC=1223423545756679"; & Y# l. F" s+ Q% Q3 Z, h2 g' o2 a! D
- *******/
3 g: E6 T. f' J - 0 @7 t9 }3 w8 x; R
- . I- G1 C9 V1 q, y# ~# I4 e
- //得到好友列表 1 L; z8 I* i9 B5 V( i1 |
- $poststring[] = "VER=1.1&CMD=List&SEQ=".rand(1000,9000)."&UIN=".$uin;
7 p0 j7 }5 ~# N( M7 k& ? - $poststring[] = "VER=1.1&CMD=List&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=0"; 5 j( o( U9 y% r2 K& m
- $poststring[] = "VER=1.1&CMD=List&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=160";
1 v4 E6 E2 {. z2 x - $poststring[] = "VER=1.1&CMD=List&SEQ=".rand(1000,9000)."&UIN=".$uin."&UN=0";
$ }! w: y( `( p: t$ j7 _ - $poststring[] = "VER=1.1&CMD=List&SEQ=".rand(1000,9000)."&UIN=".$uin."&UN=".rand(1,10); ) G2 z6 U; P# v. F; a
- $poststring[] = "VER=1.1&CMD=List&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=0&UN=0";
. J* j- q: F" P6 K# j. @ - $poststring[] = "VER=1.1&CMD=List&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=160&UN=0";
) U1 J# i* @# w4 C" A - $poststring[] = "VER=1.1&CMD=List&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=160&UN=0";
$ l! \& Y9 z) O2 \ - $poststring[] = "VER=1.1&CMD=List&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=".rand(1,200)."&UN=0";
* P/ g* k/ I9 K7 a9 H) f0 M2 e0 N9 } - $poststring[] = "VER=1.1&CMD=List&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=".rand(1,200)."&UN=0"; 0 k* c* n& x% r: @4 \2 n, V( M! P
- $poststring[] = "VER=1.1&CMD=List&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=".rand(1,200)."&UN=0"; ! d( ~; i1 b( f
- $poststring[] = "VER=1.1&CMD=List&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=0&UN=".rand(1,10);
. l# a. b' j- P4 D% V. a. ^' ` - $poststring[] = "VER=1.1&CMD=List&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=0&UN=".rand(1,10);
# Q- n. I! T% ?5 C* u7 @- P - $poststring[] = "VER=1.1&CMD=List&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=0&UN=".rand(1,10); 6 f* Q# Y3 {$ R' a6 Z8 a% c
- $poststring[] = "VER=1.1&CMD=List&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=0&UN=106814"; . A4 Q2 u' R0 ]; p" C. Q1 C1 K
- ) K2 `, D2 B' P; y1 f
- //得到在线列表 . O( J3 G4 M# E& j5 V
- $poststring[] = "VER=1.1&CMD=Query_Stat&SEQ=".rand(1000,9000)."&UIN=".$uin; ! l# p( x+ F5 X+ R
- $poststring[] = "VER=1.1&CMD=Query_Stat&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=0"; + v, b" [, |' y7 h* k6 n
- $poststring[] = "VER=1.1&CMD=Query_Stat&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=160"; 3 S# c- F1 ^! W: D3 b$ X
- $poststring[] = "VER=1.1&CMD=Query_Stat&SEQ=".rand(1000,9000)."&UIN=".$uin."&UN=0"; $ M5 K, y0 y+ P4 S! T, P. M
- $poststring[] = "VER=1.1&CMD=Query_Stat&SEQ=".rand(1000,9000)."&UIN=".$uin."&UN=".rand(1,10);
+ J6 }* G0 }7 ?. x - $poststring[] = "VER=1.1&CMD=Query_Stat&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=0&UN=0";
0 _& w1 p% k( l) D' l4 L - $poststring[] = "VER=1.1&CMD=Query_Stat&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=160&UN=0"; * i6 D$ V3 P- M( L5 v$ B2 i" m1 N
- $poststring[] = "VER=1.1&CMD=Query_Stat&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=160&UN=0"; ; } m/ }# b& x( ?
- $poststring[] = "VER=1.1&CMD=Query_Stat&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=".rand(1,200)."&UN=0"; " {1 A% \' [2 ~" o0 {) e7 q
- $poststring[] = "VER=1.1&CMD=Query_Stat&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=".rand(1,200)."&UN=0"; $ X7 c9 O: Z& A) A/ t* v
- $poststring[] = "VER=1.1&CMD=Query_Stat&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=".rand(1,200)."&UN=0";
" L! q+ F/ I' z$ f& A" B1 J9 c - $poststring[] = "VER=1.1&CMD=Query_Stat&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=0&UN=".rand(1,10); 6 h& I; b1 S6 w% l+ Q9 D
- $poststring[] = "VER=1.1&CMD=Query_Stat&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=0&UN=".rand(1,10);
1 l( x* _7 R m) a( W - $poststring[] = "VER=1.1&CMD=Query_Stat&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=0&UN=".rand(1,10);
' l4 T: S; d5 z - $poststring[] = "VER=1.1&CMD=Query_Stat&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=0&UN=106814"; $ X" `# ~4 }3 K( g. ?" {. y% y
4 V0 d+ f) _! y. Z& ~9 \- //查看好友信息 : h- D: K& q* {) l% A
- $poststring[] = "VER=1.1&CMD=GetInfo&SEQ=".rand(1000,9000)."&UIN=".$uin."&LV=0&UN=106814"; 4 P4 T- S5 W( U- H
- $poststring[] = "VER=1.1&CMD=GetInfo&SEQ=".rand(1000,9000)."&UIN=".$uin."&LV=1&UN=106814"; 1 h. [4 D+ |% `- @4 @
- $poststring[] = "VER=1.1&CMD=GetInfo&SEQ=".rand(1000,9000)."&UIN=".$uin."&LV=2&UN=106814"; . F- S: p. U2 Q8 ~! t2 i
- $poststring[] = "VER=1.1&CMD=GetInfo&SEQ=".rand(1000,9000)."&UIN=".$uin."&LV=3&UN=106814";
/ u, O5 \, k x! ~3 S: i; O - $poststring[] = "VER=1.1&CMD=GetInfo&SEQ=".rand(1000,9000)."&UIN=".$uin."&LV=4&UN=106814"; 3 L7 _1 {3 T% x( H0 E# i1 c3 \/ `) _
- $poststring[] = "VER=1.1&CMD=GetInfo&SEQ=".rand(1000,9000)."&UIN=".$uin."&LV=5&UN=106814"; / z/ Q. _' J! Y2 U" f" Q
- 5 o2 H1 v' c& l/ J# q
- //增加好友
! d# u: B1 b2 n) X( l* W( R1 i - $poststring[] = "VER=1.1&CMD=AddToList&SEQ=".rand(1000,9000)."&UIN=".$uin."&UN=106814";
7 U8 q2 ?$ Z7 J5 [, o9 \
4 }" ^! s5 e/ K5 g" x A- //发送验证 2 d5 I3 t9 e3 i- R3 o6 g
- $poststring[] = "VER=1.1&CMD=Ack_AddToList&SEQ=".rand(1000,9000)."&UIN=".$uin."&UN=106814&CD=0&RS=TEST";
/ T, W3 I( M% Z9 B" T) p, z - $poststring[] = "VER=1.1&CMD=Ack_AddToList&SEQ=".rand(1000,9000)."&UIN=".$uin."&UN=106814&CD=1&RS=TEST"; 0 ~9 S4 h) a* B) ?! V7 R
- $poststring[] = "VER=1.1&CMD=Ack_AddToList&SEQ=".rand(1000,9000)."&UIN=".$uin."&UN=106814&CD=2&RS=TEST";
' V" N6 j& l. f, `0 |( w! _2 Z - $poststring[] = "VER=1.1&CMD=Ack_AddToList&SEQ=".rand(1000,9000)."&UIN=".$uin."&UN=106814&CD=3&RS=TEST";
7 ` G+ X, b2 h! I - $poststring[] = "VER=1.1&CMD=Ack_AddToList&SEQ=".rand(1000,9000)."&UIN=".$uin."&UN=106814&CD=4&RS=TEST";
9 h/ A/ m: X( X$ x7 ~9 K% t3 {9 F9 \! i0 K - $poststring[] = "VER=1.1&CMD=Ack_AddToList&SEQ=".rand(1000,9000)."&UIN=".$uin."&UN=106814&CD=5&RS=TEST"; % s3 h% i- Y: `7 L$ _$ B
- 7 g# R/ t+ R6 y0 A$ e9 _4 ?
- //删除好友
/ L6 L; b& X) @! n - $poststring[] = "VER=1.1&CMD=DelFromList&SEQ=".rand(1000,9000)."&UIN=".$uin."&UN=106814"; , ?& s. C: S7 r: x( ~- ]
$ A# `8 A1 {4 `. Q, q- //改变状态
- R$ A& h! t. E4 s( L' ? - for($i=0;$i<=60;$i=$i+5)
6 O6 J6 |" v* P8 U/ M( \$ e0 b - { % l6 y4 D; m/ i. O5 d
- $poststring[] = "VER=1.1&CMD=Change_Stat&SEQ=".rand(1000,9000)."&UIN=".$uin."&ST=".$i;
5 q, E- v: t0 R1 N' r - } * N) N( ]/ S( f: C4 d
- , j! u& {+ n u& q0 K3 j. D2 {2 S3 B
- //获得消息
( }/ t! P% Y8 K - $poststring[] = "VER=1.1&CMD=GetMsgEx&SEQ=".rand(1000,9000)."&UIN=".$uin.""; + ?- c( S( E# M: J2 `6 g/ v2 p
( V9 R; s' f3 v" g+ x# g: z- //发送消息
6 _9 g7 U5 K' T1 O, l% R; B - $poststring[] = "VER=1.1&CMD=CLTMSG&SEQ=".rand(1000,9000)."&UIN=".$uin."&UN=106814&MG=TEST";
7 H4 E: w8 E8 C" y; t2 o - # L* Q0 j$ O9 ?4 z5 X
- //登出
* \6 x1 C# y2 K5 R# N% N7 O9 c - $poststring[] = "VER=1.1&CMD=Logout&SEQ=".rand(1000,9000)."&UIN=".$uin.""; ; r. ~$ m4 z' {: R S- g
- ; ?/ ]8 S+ T* C# D
- $file = fopen("p.txt","w");
( t4 l4 ]. }5 s( X. J1 X( x! |0 c
- W3 Y# g6 @ r( i- foreach($poststring as $k=>$v) B! E7 X3 y+ u( s6 O6 E' [
- {
$ y! X0 b& R! i$ L7 A5 G# F9 r R - ss_timing_start(); 6 n& X: H% m" C; P$ |6 b+ M
- $fp = fsockopen('tqq.tencent.com', '8000', $errno, $errstr, $timeout = 10);
0 k! r) e% l3 K) W+ F. g! F/ n% N
3 u3 U* o. [% u- if(!$fp){ 7 Z- D8 W- c! l! Q' [4 i
- //error tell us ) v/ n( t$ K0 n; M6 N
- $content = $k.chr(13).chr(10)."ERROR:$errstr ($errno)";
6 @0 D! r: Y# X0 Y/ a -
- ]/ l- n2 F7 q9 V6 F) ~ - }else{
+ W" m, B& D5 q8 a) P$ q8 e; |. ^ - " E) X1 R' @4 p6 H; w0 _+ I7 b( M
- //send the server request 6 n- t0 O/ b; c3 F. W! _
- fputs($fp, "POST HTTP/1.1\r\n");
~; K: M y G/ x' N7 j8 r - // fputs($fp, "Host: $host\r\n"); 1 X& C7 O {9 F8 R7 Y: T
- // fputs($fp, "Content-type: application/x-www-form-urlencoded\r\n"); - p% b) i7 Y$ I8 ?+ a- x3 r( Y
- fputs($fp, "Content-length: ".strlen($v)."\r\n");
4 E1 b* [* M0 g7 c7 s - fputs($fp, "Connection: close\r\n\r\n"); ' m+ }3 a0 q6 k/ X# S
- fputs($fp, $v . "\r\n\r\n"); * K% @; j1 @; l) B7 z
) b; [# p2 o' [+ o$ t, U# s- //loop through the response from the server
* W6 K2 K: S F9 t - $res = ""; 1 z- U0 G8 g3 n& x! K& }
- while(!feof($fp)) {
k- `4 K/ w: `* K7 v2 L6 N7 p - $res .= fgets($fp, 4096); 6 z8 d4 b, m$ D8 G
- } 7 c: u7 J. V3 x4 v' N) R
- //close fp - we are done with it
: ]( W, U' G7 h: X. v p- m; o - fclose($fp); 4 M% |# Z' H n) H" z/ J9 G
- {# B) ~6 u$ t* }5 \% c- $content = $v.chr(13).chr(10).$res; 0 v' T7 E; u5 k+ S
- } $ R& s, |1 s0 q0 X0 Z
- ss_timing_stop(); + ?" Z$ |; e. w$ K# M: w
- $content .= chr(13).chr(10)."Time: ".ss_timing_current().chr(13).chr(10)."--------------------------------------".chr(13).chr(10);
7 o' g% x+ Z6 M - fputs($file,$content);
$ u; z4 }( r" w1 `" Z" `+ ~ - } + W- S% d. P e* ?
- fclose($file); ' [; ^* ^5 e9 ~. W* V8 T
- ?>
0 U* ?. L+ Q& F. _+ P; D - <?
, _7 J' k4 m3 b, `4 r( x! C9 j - function ss_timing_start ($name = "default") {
- O% x. q& @2 B# ]" J% h. J& P - global $ss_timing_start_times; 0 V% X3 k3 p. J# u1 c
- $ss_timing_start_times[$name] = explode(' ', microtime()); $ j' W1 u. {2 s0 O0 O0 A6 M/ \
- }
8 k L e' H$ B4 c - function ss_timing_stop ($name = "default") { % X5 w: A# V$ G, f/ F/ [4 k* V4 A
- global $ss_timing_stop_times; 9 P7 J/ L0 t% ?; \9 E4 T
- $ss_timing_stop_times[$name] = explode(' ', microtime());
6 F2 D/ Y+ I. h# _+ V( P3 q* ~* N: i - } ' I) W' V$ j6 T' @
- function ss_timing_current ($name = "default") { # x/ \0 Q2 K `4 q6 l: e
- global $ss_timing_start_times, $ss_timing_stop_times; # J/ ^4 s: X5 O& m9 n- C# r
- if (!isset($ss_timing_start_times[$name])) {
) |, ?' n/ }9 e - return 0;
/ r/ c5 F5 i2 l: s+ S$ P - }
2 K( |8 X, d+ [ - if (!isset($ss_timing_stop_times[$name])) { ; s: u; M) k' j; f* E
- $stop_time = explode(' ', microtime()); 9 |8 I% l( @% r2 u
- }
4 Q2 v; \% Y' g% V3 I% L - else {
& _4 {$ y: L3 m1 r5 `' Y - $stop_time = $ss_timing_stop_times[$name]; 6 Q9 C) g& ^* {7 @- E+ ^3 ^
- } 0 w6 o. X& y5 ]) X
- $current = $stop_time[1]-$ss_timing_start_times[$name][1];
7 N, F6 X7 H$ _) c. a0 x - $current += $stop_time[0]-$ss_timing_start_times[$name][0]; 2 p* m* ^5 f% S. a8 R
- return $current; ! |' ^. D. v+ Z y5 N
- } 1 L+ ^1 P3 F+ y$ Z1 X
- ?>
复制代码 ' F2 x+ x3 J B$ `$ T4 Q( w1 l- ]1 b
4、研究成果: 7 p" p0 W6 g7 r ^
' x' L$ [0 {+ ^. D2 W* g1 c) T
(1).登陆 $ y4 b7 R& [4 t- Q0 Q$ p& H" G
说明:在你做任何其他操作以前,你必须登陆。只有在登陆以后,你的其他指令才有可能被正确执行(返回RES=0),不然服务器会返回RES= 20,不过有个例外,就是logout。当你成功登陆以后,服务器就会根据你的IP*和参数中的UIN来验证身份。一台电脑可以同时登陆多个QQ,互不影响,就是因为有参数UIN。
8 [) U/ T5 y/ \+ D, W ]# P. L( a9 g *至于我能够确定服务器是通过IP来验证的,是因为服务器不可能通过我的请求获得其他信息了^_^ . f- [0 a' \6 C0 K
: V) O+ p& Z+ j* Q: W Q 提交数据:VER=1.1&CMD=Login&SEQ=标记&UIN=QQ号&PS=QQ密码&M5=1&LC=9326B87B234E7235
( f1 i6 d. i& d* k 说明:QQ密码是通过md5加密的字符串,在PHP中可以直接用md5()进行加密; ) _1 d4 r; a+ S
M5这个参数的作用还不清楚,但最好为1。 ' K1 V$ Z, r8 T4 c
LC这个参数有点神秘,不能有丝毫改动,不然服务器就没有响应(没有响应就是返回NULL)。
: U7 b& Z, J" S- X$ \
6 G! o! A" m8 p 返回:VER=1.1&CMD=LOGIN&SEQ=标记&UIN=QQ号&RES=0&RS=0&HI=60&LI=300(成功)
. n3 \" k/ w+ @; e; O% e T( l; w VER=1.1&CMD=LOGIN&SEQ=标记&UIN=QQ号&RES=0&RS=1&RA=密码错误(密码错误)
/ X# K7 I+ ?* d) J) Z# K) X7 v VER=1.1&CMD=LOGIN&SEQ=标记&UIN=QQ号&RES=5(QQ号非法,如100)
) c( A3 y) K1 a6 ` NULL(UIN为字符、PS为空、LC错误) * n. G% ^! E: l& R G1 }8 A0 g
% F+ Y$ s& _+ L+ r: m/ x) u
(2).得到好友列表 . i9 `) Z5 v! P$ ]* ?
提交数据:VER=1.1&CMD=List&SEQ=标记&UIN=QQ号&TN=160&UN=0 6 M) q5 r+ R4 i
说明:TN、UN还不清楚具体表示什么,但是TN的值会影响返回的结果,有没有UN对结果没有影响 2 T8 o2 s6 B6 v
7 X4 V4 n# h' H" A4 g: g 返回:VER=1.1&CMD=LIST&SEQ=标记&UIN=QQ号&RES=0&FN=9(当TN=0或没有TN参数时,FN表示好友数) 0 F8 @" x7 h- I. v/ n8 }8 ?/ \
VER=1.1&CMD=LIST&SEQ=标记&UIN=QQ号&RES=0&FN= 1&SN=9&UN=3814526,...,(当TN存在且非0时,FN=1,SN表示好友数,UN为好友列表,用","分割) $ Q$ H0 [- b+ L3 k
VER=1.1&CMD=LIST&SEQ=标记&UIN=QQ号&RES=20(没有正确登陆) x8 u4 \/ N& k' l2 L2 _
NULL(UIN、TN、UN为字符) 3 W' Q8 r: G4 k# I% w- O/ v5 U2 e
* E2 {' N9 }% H: u/ i5 r& d3 [
(3).得到在线好友列表 % e. ]+ z, A9 D3 U" m
提交数据:VER=1.1&CMD=Query_Stat&SEQ=标记&UIN=QQ号&TN=50&UN=0
+ i1 R) _# c) O1 N+ y: K 说明:TN、UN还不清楚具体表示什么,但是TN的值会影响返回的结果,有没有UN对结果没有影响
P5 z8 X: t5 a. b' }! X/ A1 S% w! C. p9 A" F& @1 C
返回:VER=1.1&CMD=QUERY_STAT&SEQ=标记&UIN=QQ号&RES= 0&FC=0,&FN=1&SN=1&ST=10,&UN=106814,&NK=Hackfan 好,(当TN存在且非0时,FN=1,SN表示在线好友数,FC、ST、UN、NK的值用','分割,分别表示头像、状态、号码、昵称) " l: R% k' y: m
VER=1.1&CMD=QUERY_STAT&SEQ=标记&UIN=QQ号&RES=20(没有正确登陆) , l# m! z! A8 T* C- ^) H% P
NULL(UIN、TN、UN为字符) , s `! U& o' O3 u7 D2 _
说明:FC为QQ头像的的ID,如的头像ID为270,那么其头使用的图片为91.bmp,其算法为ID/3+1;
7 h }+ g+ X5 b7 a. D8 S0 b ST为QQ用户的状态,10为上线,20为离线(或隐身),30为忙碌; 5 ~' @* `0 c! H/ f4 d7 f
1 F: _/ e$ e. ]; q, [' s
特别说明:当参数TN=0或不存在时,服务器返回:
; N' I I0 {" C" N; pVER=1.1&CMD=Query_Stat&SEQ=标记&UIN=QQ号
6 k2 K1 d* E( d& ]4 y3 G: eHTTP/1.1 200 OK A% t8 W' x! e6 H: J
Server: tencent imserver/1.0.0
- z5 [" E: r5 J6 pContent-Type: text/plain; charset=UTF-8
7 I" R0 q. a+ p. x* eContent-Length: 56 2 q, B, z( u0 A$ K4 k" P
! g9 W( q* _( A. n) mVER=1.1&CMD=QUERY_STAT&SEQ=标记&UIN=QQ号&RES=0&FN=1
7 V6 b9 F0 [. v$ z; E' CHTTP/1.1 200 OK
- N7 g8 k3 n- s8 I% W% `% `" B4 qServer: tencent imserver/1.0.0 " J# z/ b4 S g6 ]& L
Content-Type: text/plain; charset=UTF-8
5 H; `& U1 ~0 `9 u+ {! YContent-Length: 77 ! {- N9 L+ m5 L
( @, F0 y6 N5 @1 T+ PVER=1.1&CMD=QUERY_STAT&SEQ=标记&UIN=QQ号&RES=0&FC=&FN=1&SN=0&ST=&UN=&NK=
6 K' z$ T6 w* B0 n4 w' g9 o9 } 返回了2次,第一次的结果中,FN为在线好友数,第二次返回的数据基本没用。 + m! K8 q. u, o( ~- e: ]" N8 t" \
1 e! k, _; X, F( L S6 o
(4).查看好友信息 : t9 b( M( ?2 |# q
提交数据:VER=1.1&CMD=GetInfo&SEQ=标记&UIN=QQ号&LV=查询类型&UN=被查询QQ号码
: X/ b- ?% a2 j$ V( z* i 说明:LV=0,1为精简查询,LV=2为普通查询,LV>=3为详细查询 & k- `) A- Y# \7 _: S# N2 b
% i; ^$ d9 u$ D0 U- A. A' y1 I
返回:VER=1.1&CMD=GETINFO&SEQ=标记&UIN=QQ号&RES=0&LV=0&UN=106814&NK=Hackfan 好(精简查询)
- I7 X4 s$ a# ?% ~ VER=1.1&CMD=GETINFO&SEQ=标记&UIN=QQ号&RES=0&AD =地址&AG=19&EM=hackfan@qq.com&FC=0&HP=http: //blog.hackfan.net&JB=学生 # l! D0 [* V9 X6 i" S! W2 C/ e
&LV=2&PC=邮编&PH=电话&PR= The guy is updating to .NET Frameword......&PV=江苏&RN=胡吉阳&SC= 毕业院校&SX=0&UN=106814&NK=Hackfan , T) N) Y0 K9 K& M# r c
好(普通查询) ( z( G, v4 p8 A1 q+ N: H
VER=1.1&CMD=GETINFO&SEQ=标记&UIN=QQ号&RES=0&AD =地址&AG=19&BT=2&CO=6&CT=苏州&CV=%01&CY=中华人民共和国 8 \1 y3 |5 N; W; O/ s3 Z- t; f
&EM=hackfan@qq.com&FC=0&HP=http://blog.hackfan.net&ID =-&JB=学生&LV=3&MO=136********&MT=0&MV=&PC=邮编& PH=电话&PR=The guy is ' c! O" Y& @8 w" c- U) ?4 }' [0 Y- j
updating to .NET Frameword......&PV=江苏&RN=胡吉阳&SC=毕业院校&SH=3&SX=0&UN=106814&NK=Hackfan 好(详细查询)
; |3 A* k- @. q4 D2 J* O0 p3 U VER=1.1&CMD=GETINFO&SEQ=标记&UIN=QQ号&RES=20(没有正确登陆)
4 U" A6 P$ Z* E r4 ]/ x4 \( R NULL(UIN、LV、UN为字符) `4 S- @! A) l1 \9 M
) i/ o0 `# T3 k' V/ t: R
说明:AD为联系地址
& I0 s5 B6 |. ^ a* N7 t0 ` AG为年龄 7 u) R) q; c( o) y `
BT为血型
' F) i2 p9 Q2 Q2 z CO为星座 8 k6 g" i# r: h G' Q2 v. ~; r x
CT为城市 3 N- a5 H! B* g3 s8 E; d, V
CV为未知*
+ H- N, F; a0 S1 E# S. T- [2 N' ] CY为国家
2 s3 ^/ X+ P0 o/ l) s EM为Email
! d+ I, H2 z: l4 R0 [ FC为头像 " i% O& `' S9 t: F/ { D+ Z+ J, @& j
HP为网站
$ Z: \) r, X( Q, {3 d3 S ID为未知 / c' V+ G" @5 ^; \, Q5 |
JB为职业 v0 ^- L" Z7 v9 S0 {# s
LV为查询代码(就是发送的LV)
4 t7 X1 } N" H1 w/ l MO为移动电话
# w1 v3 l0 u: W y MT为未知
6 X7 s( r; O2 n2 z MV为未知
6 ]% T- \- v5 d1 d PC为邮编 4 ?5 M) G: g- @! I, T5 j
PH为联系电话
2 Y6 ]0 y- m( G+ |5 W PR为简介 5 y* v0 Z, c! P$ X# d2 e- u7 Z8 ?
PV为省
( G/ R7 n' O+ M RN为真实姓名
2 F; ~! h7 R/ q SC为毕业院校 7 Y7 s) R1 y' j! K
SH为生肖 2 K h1 R4 s$ A) M5 V q! d: @
SX为性别 5 }2 f. U' n- [- \. `6 V- ]6 D1 `
UN为QQ号 " T$ \0 t1 d9 W! N* E4 q
NK为昵称
' e9 A9 I2 F9 `! F2 y; ^% p6 {$ }+ E7 L) K" O5 ]
血型:0 => '', 3 _+ m: B9 _# O9 y: r3 y5 Z4 e* E
1 => 'A型',
5 N7 c0 e, f. ]: l0 M, Y- ?; G 2 => 'B型',
( e2 Z7 K3 R e% z3 M+ W6 q" l 3 => 'O型', 9 _( B, p2 E) O- o
4 => 'AB型',
9 i& _4 h' P. g/ q: M 5 => '其他' 3 R: T: U9 K$ G/ t8 H: j7 R- v
6 c& B8 F, ]8 q9 E0 N; V. m" K7 o
" _! k* h5 j8 d3 x& j( X$ K
星座:0 => '', & V+ C( t1 \! W( K+ U& \# i
1 => '水瓶座',
( l5 ]+ i6 |1 T* u' E+ ~ 2 => '双鱼座', : O3 f! S7 L7 e* t- c; |
3 => '牡羊座',
! f+ M4 _1 l$ Z0 H0 Q5 P 4 => '金牛座',
9 B3 `; m1 l9 H& `) F+ c 5 => '双子座', $ A, u" K' f% c$ |
6 => '巨蟹座', . o# {$ c1 h- ^7 D5 i
7 => '狮子座',
$ Q9 P5 r$ u* k. c* u. d1 Y, ] 8 => '座', . D. _: }; k! }( n% ]! V7 U
9 => '天秤座', 1 q! D6 K% R7 K8 F
10 => '天蝎座',
0 t: p! X) n3 w8 S4 s8 P5 p 11 => '射手座',
6 W: B) {7 s6 P1 H& }4 J3 x 12 => '摩羯座'
. J8 M; F, t2 T( a: t( Z& {- A9 |! h: n: P, O% q' Q
生肖:0 => '',
. e& |! W2 n, R+ Z) @ 1 => '鼠', $ h4 t4 B) N9 e
2 => '牛', . P% z+ P& `( T4 u) L {1 ^
3 => '虎', ! ~2 e) q- {5 m- ]) Y6 ]
4 => '兔', / V: v8 u2 A* _* b9 s( d( q
5 => '龙',
8 r% x( k/ p# c9 n 6 => '蛇',
* W$ j3 q, R. z, i: i 7 => '马',
, m) o! q0 P& N' {4 k6 x! o q' \ 8 => '羊',
8 d, f! ?( u# B ? \6 ] 9 => '猴', ( u/ a% J. _+ X; J/ D- `
10 => '鸡', & W j+ j: F6 j+ L
11 => '狗',
- |1 ~1 M& S( O3 W8 ` 12 => '猪' 6 y2 p B( K$ i
# u9 q- e" W# y& ?
性别:0 => '男',
8 z+ h6 H) B% T: z8 ^6 s5 ^: _ 1 => '女' & p5 y9 _( Q# O X- |; p1 ~6 a
6 P8 u' ^% i; z4 B& ?( M
(5).增加好友 4 G2 W5 O3 K* S( q
提交数据:VER=1.1&CMD=AddToList&SEQ=标记&UIN=QQ号&UN=对方QQ号 : o1 ]. q3 w( q, c, m3 x2 p
+ ]/ f* U4 A! L" [4 [
返回:VER=1.1&CMD=AddToList&SEQ=标记&UIN=QQ号&RES=0&CD=0&UN=对方QQ号(允许被加为好友,此时他已经是你的好友)
6 q) R. U; l; i$ K5 x+ m VER=1.1&CMD=AddToList&SEQ=标记&UIN=QQ号&RES=0&CD=1&UN=对方QQ号(需要验证)
2 j4 f' U% N) ~2 U4 ? VER=1.1&CMD=AddToList&SEQ=标记&UIN=QQ号&RES=0&CD=2&UN=对方QQ号(决绝被加为好友) + K5 F0 X7 q* r
VER=1.1&CMD=AddToList&SEQ=标记&UIN=QQ号&RES=20(没有正确登陆) 2 R; [; k: O: ?+ G. F' A
NULL(UIN、UN为字符) " i. O0 Q" i. V8 p% `. x
t6 j4 Y9 S! p1 t q& H(5).发送验证
9 S2 V! G- h5 u* h) y) y3 m 说明:1、如果你加对方为好友,你需要发送验证
/ h1 `$ M% B( z7 l, T) u( d 2、对方加你为好友,发送了验证,你要通过或者拒绝
0 U6 P" a& ~9 w% G1 C, g0 P. r 这2种情况需要发送验证消息
6 d* m( g! m& ]# Z! R/ p9 D0 H$ r
提交数据:VER=1.1&CMD=Ack_AddToList&SEQ=标记&UIN=QQ号&UN=对方QQ号&CD=验证类型&RS=理由 : [+ b5 K0 n: ?9 }6 W
说明:CD为0表示“通过验证”,CD为1表示“拒决加为对方为好友”,CD为2表示“为请求对方加为好友”。 ; r& T' J2 z' Q3 Q8 D* H
v1 {& }7 W6 J$ b# z' S
返回:VER=1.1&CMD=Ack_AddToList&SEQ=标记&UIN=QQ号&RES=0(成功) + M+ H! d$ q' M
VER=1.1&CMD=Ack_AddToList&SEQ=标记&UIN=QQ号&RES=3(*)
7 j9 v5 V$ P8 E3 y4 z% q; w VER=1.1&CMD=Ack_AddToList&SEQ=标记&UIN=QQ号&RES=20(没有正确登陆) # L$ W c% U! n; F3 n. R
NULL(UIN、UN、CD为字符,RS为非UTF-8字符)
: e# S7 c' A" @3 o& w *如果服务器返回RES=3,那么这次对话的响应时间在20s。当发送验证请求的时候,必须连发2次(请求内容不必一样),其中一条RES=3,对方收不到,一条RES=0,对方能够收到。当CD>=3时,RES=3,响应时间20s。
7 N) E2 ], Y5 g6 z+ O5 X( F/ Q
+ j. x# j5 a; V q' {4 W' j(6).删除好友
; d6 d# |. W; P" l2 n$ i2 O 提交数据:VER=1.1&CMD=DelFromList&SEQ=标记&UIN=QQ号&UN=删除的QQ号
3 Z3 d# A, t+ b) {0 U) s9 { r; Y3 \( X# u( X
返回:VER=1.1&CMD=DelFromList&SEQ=标记&UIN=QQ号&RES=0&(成功)
8 Y- k7 v2 L( {" B3 Y- n# \ VER=1.1&CMD=DelFromList&SEQ=标记&UIN=QQ号&RES=3(响应时间30s,重复发送的后果)
$ R: D1 z8 J9 `" y3 ~ VER=1.1&CMD=DelFromList&SEQ=标记&UIN=QQ号&RES=20(没有正确登陆)
+ Q7 F& R/ r: F5 v NULL(UIN、UN为字符)
1 M" N! f3 Y& Z# m J. i a) S
5 ~! P+ S8 Q/ B! q3 b/ C6 S* H(7).改变状态
; P" |( c* C3 |5 [9 E5 k- b' R 提交数据:VER=1.1&CMD=Change_Stat&SEQ=标记&UIN=QQ号&ST=状态代码
* S1 j* C/ C. S, I3 X 说明:状态代码:10为上线,20为离线,30为忙碌,40为隐身,其他视为非法 + s8 P6 z- v0 |5 z, D
1 P3 h5 B) O& E5 ` 返回:VER=1.1&CMD=Change_Stat&SEQ=标记&UIN=QQ号&RES=0&(成功) 6 N2 m3 i i$ @" [4 j4 d& s
VER=1.1&CMD=Change_Stat&SEQ=标记&UIN=QQ号&RES=3(失败,原因不明,响应时间20s,可能是过于频繁的改变状态引起的)
* P6 c; j6 {$ K0 C1 h! ~9 E: v5 B VER=1.1&CMD=Change_Stat&SEQ=标记&UIN=QQ号&RES=20(没有正确登陆) 3 R3 z0 o6 Y, p1 [; Z% a
NULL(UIN为字符,ST非法) + u- Z- l+ R& s9 j7 G2 L
- r1 s' i8 T0 c- j) P7 |( b) z" Y
特别说明:如果你改变好友,将会给所有好友发送一条系统信息,内容就是状态代码;如果隐身,发送的状态代码为20,表示离线。 ; ^9 B# H( y" ]- d1 ~! ]5 m
同理,当你的好友改变状态,你也会收到一条系统信息。
/ _& ^+ c1 x1 T, y, z7 V$ j/ R
B6 c6 M8 L: S* Z(9).获得消息 , x1 ?5 Y6 A! N) D
提交数据:VER=1.1&CMD=GetMsgEx&SEQ=标记&UIN=QQ号
' U. q$ e, k: O' N) W& C8 t# e
+ F' T7 x0 P- a 返回:VER=1.1&CMD=GETMSGEX&SEQ=标记&UIN=QQ号&RES=0& MN=4&MT=99,99,99,9,&UN=36791785,99833581,99833581,106814,&MG= 20,30,10,hi ,(MN表示信息数量,MT、UN、MG的值用","分割,分别表示消息类型、发送人号码、消息内容)
4 I! F) Y; W8 d7 z7 s VER=1.1&CMD=GETMSGEX&SEQ=标记&UIN=QQ号&RES=0&MN=0&MT=&UN=&MG=(表示没有信息) 0 x N. i7 x9 V& B
VER=1.1&CMD=GETMSGEX&SEQ=标记&UIN=QQ号&RES=20(没有正确登陆)
: |9 J2 N9 P, z3 A% A8 C NULL(UIN为字符)
7 x* e+ E: D* V 说明:关于MT:
8 p/ Y8 _8 R' l2 N2 ^/ P 9为用户消息,99为系统消息,2为请求信息,3为通过验证,4为拒绝被加好友 : G4 H$ S/ c% Z/ k8 q, ?3 n
关于MG: 7 d% s+ P a% B
当MT=9时,MG为用户发送的消息内容
# C: k$ U- Z$ a& m 当MT=99时,
0 `) m3 x* ]* ^2 _# h3 z MG=10(QQ_STATUS_ONLINE)表示对方上线
$ i+ Y5 E1 y5 ]1 G MG=20(QQ_STATUS_OFFLINE)表示对方下线
5 _9 s m3 Z2 \) X' P' F' v( V1 N4 |8 E MG=30(QQ_STATUS_BUSY)表示对方进入忙碌状态 ; z. U4 m$ j1 W2 V7 w7 M! v5 V) o
当MT=2时,MG为对方请求你验证的信息 5 g$ d1 H! o/ [( M
当MT=3时,表示对方通过你的验证 ' f* \$ @ b; {# F
当MT=4时,MG为对方拒绝你理由
- c4 V* \5 F, J
5 I+ U( W2 T3 P: X(10).发送消息
4 Q/ U6 |3 C( ~. ~1 @ | 提交数据:VER=1.1&CMD=CLTMSG&SEQ=标记&UIN=QQ号&UN=对方QQ号&MG=发送内容 7 r7 ?- a5 m$ ?6 F( S
: {, \2 z1 i/ }7 L) Z, x* E 返回:VER=1.1&CMD=CLTMSG&SEQ=标记&UIN=QQ号&RES=0&(成功发送,对方不一定能收到哦)
$ }% c. u2 P1 S8 c$ L VER=1.1&CMD=CLTMSG&SEQ=标记&UIN=QQ号&RES=3(发送过快)
3 B) t; a$ Z' {' y1 m VER=1.1&CMD=CLTMSG&SEQ=标记&UIN=QQ号&RES=20(没有正确登陆) 3 b4 D0 t; P3 m' l$ r- k
NULL(UIN、UN为字符,MG含非UTF-8字符) * @6 Z& ~7 x- g0 ?/ _: C
说明:1、当你发消息时,以下情形对方可能看不到(其实是收到了,QQ不提示)你发送的消息:
' B9 f% o5 K. D9 H 你俩互为陌生人,且对方没有和你说过话
4 b# _5 ^2 A3 D) O! t+ J 你在他的陌生人列表里,并且他没有和你说过话(没有验证)
3 Z! I7 m! w L E/ p/ \ 2、当你过快发送消息时,系统会给你一个惩罚,RES=3,相应时间20s $ T4 K, N" {) Q6 y- G5 k
3、当我发送含有小写字母h的信息时,服务器有可能返回NULL 5 B4 z9 k+ b6 M5 d4 K W8 X
8 E0 `- P- u& Y) ], [' X" F(11).登出 ! Q3 G" V0 c8 A% @5 p) M \
提交数据:VER=1.1&CMD=Logout&SEQ=标记&UIN=QQ号
! x! s8 d- c9 t) `
+ w! ~' p) n" u' H& ] 返回:VER=1.1&CMD=LOGOUT&SEQ=标记&UIN=QQ号&RES=0(成功,好像永远成功的,不管你是否登陆)
# S" Z% m" v$ I3 f NULL(UIN为字符) 8 n" p0 R$ [% j$ H2 ]2 o8 s4 o
, B. h( y6 D, _5、总结 # w1 _& t; ~* r5 m
' `7 }/ Q6 m2 M& m& f1 I) V; f( h1 x
通过对照以上的接口说明,我开发出了能够实现基本QQ功能的PHP类,它整合了以上所有的接口,使用更方便,可以开发QQ机器人、群发广告程序等。免费获得类的代码请到 ' I! Z/ [; \5 Q
http://blog.hackfan.net/index.ph ... d=a_20050819_223558
! I4 ^1 V( e: m4 v- v# L& T 本文撰写时间仓促,难免有误,希望各位不吝赐教
0 J2 N* [ z/ c# p. L. D! W7 z
0 ]' Q9 d" A; B( a: p' `3 g
5 O X% G/ _! b1 Y+ |3 t. |Trackback: http://tb.donews.net/TrackBack.aspx?PostId=520301 |
|