参考别人研究的QQ协议做的简单的WPF版手机QQ聊天器,界面不太美观!
简单功能:
1.登陆
2.消息查看器
3.托盘消息闪烁
4.查看个人基本资料
5.聊天
6.点击闪烁图标与最近的好友聊天
截图
主要通讯核心类:(有些是参考的网上的,基本上自己都改动过)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Net; using System.Security.Cryptography; using System.Text.RegularExpressions; using System.Threading; using My.Properties; namespace My { /// <summary> /// 获取腾讯QQ数据操作类 /// </summary> public class ServerPostProcess { private string num = string.Empty; //构造函数的QQ号码 private string pwd = string.Empty; //构造函数的QQ密码 private string md5Pwd = string.Empty;//加密后的QQ密码 public string[] online_Face = { "" }; //在线的头像号码 public string[] online_Station = { "" }; //在线的状态 public string[] online_Number = { "" }; //在线的号码 public string[] online_NameK = { "" }; //在线的昵称 private WebClient wc1 = null; private WebClient wc2 = null; private WebClient wc3 = null; #region WebClient操作池(暂时放弃)出现_clientSends并发问题 //private List<WebClient> _clientSends = new List<WebClient>(3); //// <summary> //// 尝试从集合里面拿到一个发送器 //// </summary> //private WebClient ClientSends //{ // get { // lock (_clientSends) // { // int tnum = GetClientSendsNoBusyNum; // if (_clientSends.Count <= 5 && tnum <= 0) // { // WebClient addWc = new WebClient(); // _clientSends.Add(addWc); // return addWc; // } // if (tnum == 0) // { // return null; // } // //拿出一个不繁忙的发送器进行处理请求 // foreach (WebClient wct in _clientSends) // { // if (wct != null && !wct.IsBusy) // { // return wct; // } // } // return null; // } // } //} ///// <summary> ///// 获取发送器不繁忙的可用数量 ///// </summary> //private int GetClientSendsNoBusyNum //{ // get // { // int i = 0; // foreach (WebClient wc in _clientSends) // { // if (wc != null && !wc.IsBusy) // { // i++; // } // } // return i; // } //} #endregion private string postStr; //发送给服务器的字符串 private byte[] postArray; //把要发送的字符串变成字符数组 private byte[] returnArray; //接受服务器返回的字符数组 private string returnStr; //把返回的字符数组变成字符串 public string[] MT; //储存信息类型 public string[] UN; //储存信息来源号码 public string[] MG; //储存信息内容 public bool is_RightLogin;//是否正确的登陆 /// <summary> /// 登陆前提:必须通过验证 /// </summary> public ServerPostProcess() { Users user = ManagerStaticResouce.LoginingUser; if (user != null) { num = user.Uid; pwd = user.Pwd; } else { throw new Exception("用户名称不存在!"); } wc1 = new WebClient(); wc2 = new WebClient(); wc3 = new WebClient(); md5Pwd = MD5(pwd); } /// <summary> /// 向服务器POST数据 /// </summary> private bool UploadData(int type) { try { WebClient wc = GetClientSends(type);//尝试拿到一个发送器 if (wc != null)//双重判断 { returnArray = wc.UploadData("http://tqq.tencent.com:8000", "POST", postArray); } else { return false; } } catch (Exception ex) { throw new WebException(ex.Message); } return true; } /// <summary> /// 得到一个发送器 /// </summary> /// <param name="type">操作类型(1 其他,2 发送消息,3 获取消息)</param> /// <returns></returns> private WebClient GetClientSends(int type) { if (wc1 != null && !wc1.IsBusy && type == 1) { return wc1; } else if (wc2 != null && !wc2.IsBusy && type == 2) { return wc2; } else if (wc3 != null && !wc3.IsBusy && type==3) { return wc3; } else { return null; } } /// <summary> /// 登陆QQ /// </summary> /// <returns>登陆成功就返回True</returns> public bool QQ_Login(ref string returnResult) { postStr = "VER=1.1&CMD=Login&SEQ=" + DateTime.Now.Ticks.ToString().Substring(7, 7) + "&UIN=" + num + "&PS=" + md5Pwd + " &M5=1&LC=9326B87B234E7235"; postArray = System.Text.Encoding.UTF8.GetBytes(postStr); //向服务器POST数据 if (!UploadData(1)) { returnResult = "服务器忙!请重新点击登陆!"; return false; } returnStr = Encoding.UTF8.GetString(returnArray); returnResult = returnStr; if (returnStr.Contains("RES=0&RS=0")) { is_RightLogin = true; return true; } else { return false; } } /// <summary> /// QQ退出登陆,并改变is_RightLogin为False /// </summary> public void QQ_Logout() { postStr = "VER=1.1&CMD=Logout&SEQ=" + DateTime.Now.Ticks.ToString().Substring(7, 7) + "&UIN=" + num; postArray = System.Text.Encoding.UTF8.GetBytes(postStr); //向服务器POST数据 while (true) { if (!UploadData(1)) { continue; } break; } returnStr = Encoding.UTF8.GetString(returnArray); if (returnStr.Contains("&RES=0")) { is_RightLogin = false; return; } } /// <summary> /// MD5加密 /// </summary> /// <param name="toCryString"></param> /// <returns></returns> public static string MD5(string toCryString) { //using System.Security.Cryptography安全.密码系统 MD5CryptoServiceProvider hashmd5 = new MD5CryptoServiceProvider(); //asp是小写,把所有字符变小写 string tmp =BitConverter.ToString(hashmd5.ComputeHash(Encoding.UTF8.GetBytes(toCryString))).Replace("-", "").ToLower(); hashmd5.Clear(); return tmp; } /// <summary> /// 获取QQ好友列表 /// </summary> /// <returns>返回一个字符串数组,数组最后一个元素是空格</returns> public string[] QQ_List() { postStr = "VER=1.1&CMD=List&SEQ=" + DateTime.Now.Ticks.ToString().Substring(7, 7) + "&UIN=" + num + "&TN=160&UN=0"; postArray = System.Text.Encoding.UTF8.GetBytes(postStr); //向服务器POST数据 if (!UploadData(1)) { return null; } returnStr = Encoding.UTF8.GetString(returnArray); if (!returnStr.Contains("&RES=0")) is_RightLogin = false; string s2 = returnStr.Remove(0, returnStr.IndexOf("&UN=") + 4); string[] QQ_Friend_List = s2.Split(','); return QQ_Friend_List; } /// <summary> /// 更新QQ类中目前在线online_四个字符串数组的值 /// </summary> public void QQ_Query_Stat() { postStr = "VER=1.1&CMD=Query_Stat&SEQ=" + DateTime.Now.Ticks.ToString().Substring(7, 7) + "&UIN=" + num + "&TN=50&UN=0"; postArray = System.Text.Encoding.UTF8.GetBytes(postStr); //向服务器POST数据 if (!UploadData(1)) { return; } returnStr = Encoding.UTF8.GetString(returnArray); if (!returnStr.Contains("&RES=0")) is_RightLogin = false; StringBuilder sb = new StringBuilder(returnStr); sb.Remove(returnStr.IndexOf("&FN="), returnStr.Length - returnStr.IndexOf("&FN=")); sb.Remove(0, returnStr.IndexOf("&FC=") + 4); online_Face = sb.ToString().Split(','); sb = new StringBuilder(returnStr); sb.Remove(returnStr.IndexOf("&UN="), returnStr.Length - returnStr.IndexOf("&UN=")); sb.Remove(0, returnStr.IndexOf("&ST=") + 4); online_Station = sb.ToString().Split(','); sb = new StringBuilder(returnStr); sb.Remove(returnStr.IndexOf("&NK="), returnStr.Length - returnStr.IndexOf("&NK=")); sb.Remove(0, returnStr.IndexOf("&UN=") + 4); online_Number = sb.ToString().Split(','); string ss = returnStr.Remove(0, returnStr.IndexOf("&NK=") + 4); online_NameK = ss.Split(','); } /// <summary> /// 输入一个QQ号,查询这个QQ号的信息 /// </summary> /// <param name="search_num">输入一个QQ号,查询该QQ信息</param> /// <returns>字符串数组(0联系地址,1用户年龄,2用户邮箱,3头像,4个人网站,5职业,6邮箱,7联系电话,8简介,9省份,10真实姓名,11毕业院校,12性别,13QQ号,14昵称)</returns> public string[] QQ_GetInfo(string search_num) { postStr = "VER=1.1&CMD=GetInfo&SEQ=" + DateTime.Now.Ticks.ToString().Substring(7, 7) + "&UIN=" + num + "&LV=2&UN=" + search_num; postArray = System.Text.Encoding.UTF8.GetBytes(postStr); //向服务器POST数据 if (!UploadData(1)) { return null; } returnStr = Encoding.UTF8.GetString(returnArray); if (!returnStr.Contains("&RES=0")) is_RightLogin = false; MatchCollection matches = Regex.Matches(returnStr, "&([^=][^=])=([^&]*)"); List<string> Info = new List<string>(); for (int i = 0; i < matches.Count; i++) Info.Add(matches[i].Groups[2].ToString()); Info.RemoveAt(6); //去除LV=多少, 这表示查询方式,默然就是普通查询 if (Info[12].ToString() == "0") Info[12] = "男"; else Info[12] = "女"; string[] Inf = Info.ToArray(); return Inf; } /// <summary> /// 添加好友功能 /// </summary> /// <param name="fir_num">输入一个QQ号,请求加为好友</param> /// <returns>0表示已经加为好友,1表示需要验证请求,2表示拒绝</returns> public string AddToList(string fir_num) { postStr = "VER=1.1&CMD=AddToList&SEQ=" + DateTime.Now.Ticks.ToString().Substring(7, 7) + "&UIN=" + num + "&UN=" + fir_num; postArray = System.Text.Encoding.UTF8.GetBytes(postStr); //向服务器POST数据 if (!UploadData(1)) { return null; } returnStr = Encoding.UTF8.GetString(returnArray); if (!returnStr.Contains("&RES=0")) is_RightLogin = false; MatchCollection matchs = Regex.Matches(returnStr, "&CD=(.)"); return matchs[0].Groups[1].ToString(); } /// <summary> /// 回应加为好友的响应 /// </summary> /// <param name="fri_Num">请求的QQ号码</param> /// <param name="agree_Type">0表示通过验证,1表示拒绝对方,2表示请求加对方为好友</param> public void Ack_AddToList(string fri_Num, string agree_Type) { postStr = "VER=1.1&CMD=Ack_AddToList&SEQ=" + DateTime.Now.Ticks.ToString().Substring(7, 7) + "&UIN=" + num + "&UN=" + fri_Num + "&CD=" + agree_Type + "&RS="; postArray = System.Text.Encoding.UTF8.GetBytes(postStr); //向服务器POST数据 if (!UploadData(1)) { return; } returnStr = Encoding.UTF8.GetString(returnArray); if (!returnStr.Contains("&RES=0")) is_RightLogin = false; } /// <summary> /// 删除好友,成功返回True /// </summary> /// <param name="del_num">输入一个QQ号,删除这个QQ好友</param> /// <returns></returns> public bool DelFromList(string del_num) { postStr = "VER=1.1&CMD=DelFromList&SEQ=" + DateTime.Now.Ticks.ToString().Substring(7, 7) + "&UIN=" + num + "&UN=" + del_num; postArray = System.Text.Encoding.UTF8.GetBytes(postStr); //向服务器POST数据 if (!UploadData(1)) { return false; } returnStr = Encoding.UTF8.GetString(returnArray); if (returnStr.Contains("&RES=0")) return true; else return false; } /// <summary> /// 改变QQ当前状态(在线,离线,忙碌) /// </summary> /// <param name="Stat">输入10在线,20离线,30忙碌</param> /// <returns></returns> public bool Change_Stat(string stat) { postStr = "VER=1.1&CMD=Change_Stat&SEQ=" + DateTime.Now.Ticks.ToString().Substring(7, 7) + "&UIN=" + num + "&ST=" + stat; postArray = System.Text.Encoding.UTF8.GetBytes(postStr); //向服务器POST数据 if (!UploadData(1)) { return false; } returnStr = Encoding.UTF8.GetString(returnArray); if (returnStr.Contains("&RES=0")) return true; else return false; } /// <summary> /// 向一个QQ号码发送消息 /// </summary> /// <param name="msgTo">输入一个QQ号,向他发送消息</param> /// <param name="msg">输入消息内容</param> /// <returns>成功返回True</returns> public bool QQ_SendMsg(string msgTo, string msg) { postStr = "VER=1.2&CMD=CLTMSG&SEQ=" + DateTime.Now.Ticks.ToString().Substring(7, 7) + "&UIN=" + num + "&UN=" + msgTo + "&MG=" + msg; postArray = System.Text.Encoding.UTF8.GetBytes(postStr); //向服务器POST数据 if (!UploadData(2)) { return false; } returnStr = Encoding.UTF8.GetString(returnArray); if (returnStr.Contains("&RES=20")) { is_RightLogin = false; return false; } if (returnStr.Contains("&RES=0")) return true; else return false; } //待处理 public void GetMsgEx() { postStr = "VER=1.1&CMD=GetMsgEx&SEQ=" + DateTime.Now.Ticks.ToString().Substring(7, 7) + "&UIN=" + num; postArray = System.Text.Encoding.UTF8.GetBytes(postStr); //向服务器POST数据 if (!UploadData(3)) { return; } returnStr = Encoding.UTF8.GetString(returnArray); if (returnStr.Contains("\r")) returnStr = returnStr.Replace("\r", "\n"); if (returnStr.Contains("&RES=0") && returnStr.Contains("&MN=")) { is_RightLogin = true; MatchCollection matches = Regex.Matches(returnStr, "&MN=([^&]*)"); if (matches[0].Groups[1].ToString() != "0") //判断返回的信息数量是否为0条 { matches = Regex.Matches(returnStr, "&MT=([^&]*)&UN=([^&]*)&MG=([^&]*)"); MT = matches[0].Groups[1].ToString().Split(','); //信息类型 UN = matches[0].Groups[2].ToString().Split(','); //信息来源号码 returnStr = returnStr.Remove(0, returnStr.IndexOf("&MG=") + 4); MG = returnStr.Split(','); //信息内容 //将消息内容进行转码 for (int i = 0; i < MG.Length - 1; i++) { MG[i] = MG[i].Replace("%25", "%"); MG[i] = MG[i].Replace("%26", "&"); MG[i] = MG[i].Replace("%2c", ","); } } else { MT = null; UN = null; MG = null; is_RightLogin = false; } } else { MT = null; UN = null; MG = null; is_RightLogin = false; } } } }
此程序纯属好玩,单纯的只想研究下手机QQ的协议.
注意没有使用过手机登陆过QQ的用户可能无法正常登陆,解决办法是使用真正的手机QQ登陆一次即可.
程序下载:NatureQQ
源码下载:NatureQQ_Source