using Chat.Framework; using Chat.Framework.WXSdk.Implement; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; namespace Chat.Framework.WXSdk.IPAD { /// /// Socket管理 /// public sealed class SocketClient { class SocketResult { public DateTime Time { get; set; } public byte[] Data { get; set; } } public WeixinBase weixin; public enum WXSocketClientError { connetedErr = 0,//连接错误 sendErr = 1,//发送错误 receiveErr = 2,//接受错误 }; internal Socket clientSocket; internal DnsEndPoint hostEndPoint { get; set; } public bool connected { get { if (this.clientSocket != null) return this.clientSocket.Connected; return false; } } Dictionary mPackDic = new Dictionary(); private object mPackDicLock = new object(); public Func NotifyCallback { get; set; } int Seq = 0; private byte[] packageData = null; public void ClearPack() { lock (mPackDic) { var vas = mPackDic.ToList().Where(f => f.Value.Time < DateTime.Now.AddMinutes(-5)); foreach (var item in vas) { mPackDic.Remove(item.Key); } } } public Func SocketExceptionCallback { get; set; } public ManualResetEvent allDone = new ManualResetEvent(false); public SocketClient(DnsEndPoint hostEndPoint, WeixinBase weixin) { this.weixin = weixin; this.hostEndPoint = hostEndPoint; CreateSocket(); } //创建socket public bool CreateSocket() { clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); clientSocket.SendTimeout = 10000; SetXinTiao(); return true; } private object lock_login = new object(); public void BeginConnection() { try { this.allDone = new ManualResetEvent(false); if (null == clientSocket) { CreateSocket(); } //开始连接到服务器 clientSocket.BeginConnect(hostEndPoint, delegate { try { AsynRecive(); if (weixin.Status == Chat.Framework.WXSdk.WxStatus.在线) { //var client = (this.weixin as WXClientImpl_IPAD); //client.AsyncSyncMessage(); // if (!client.AsyncSyncMessage()) this.weixin.ResetConnection(); } } catch (Exception) { } }, null); Thread.Sleep(200); // wait here until the connect finishes. The callback sets allDone. //阻塞直到connected=true //allDone.WaitOne(1000 * 5); // Log("连接 WeChat 成功!"); LogHelper.GetSingleObj().Info("Wechat Connect", $"{weixin.WeixinHao}-{hostEndPoint}-连接成功!!!!"); } catch (Exception ex) { LogHelper.GetSingleObj().Error("Wechat Connect", $"{weixin.WeixinHao}-{hostEndPoint}-连接失败!{ex.Message}"); // Log("连接 WeChat 失败!" + ex.Message); //Log(new LogInfo(jobinfo.JobID, "调试", "创建wx服务器连接失败,详情:" + ex.Message + Environment.NewLine + ex.StackTrace, 3)); //Log(new LogInfo(jobinfo.JobID, "错误", "创建wx服务器连接异常", 1)); } } //异步连接 public bool Connect() { lock (lock_login) { this.Disconnect(); BeginConnection(); Thread.Sleep(1000); } return connected; } //断开socket public void Disconnect() { try { if (clientSocket != null && clientSocket.Connected) { LogHelper.GetSingleObj().Info("Wechat Disconnect", $"{weixin.WeixinHao}-{hostEndPoint}-关闭"); } clientSocket.Shutdown(SocketShutdown.Both); clientSocket.Disconnect(true); clientSocket.Close(); clientSocket.Dispose(); clientSocket = null; allDone.Dispose(); } catch (Exception) { } } ///// 设置socket心跳 private void SetXinTiao() { //byte[] inValue = new byte[] { 1, 0, 0, 0, 0x20, 0x4e, 0, 0, 0xd0, 0x07, 0, 0 };// 首次探测时间20 秒, 间隔侦测时间2 秒 byte[] inValue = new byte[] { 1, 0, 0, 0, 0x88, 0x13, 0, 0, 0xd0, 0x07, 0, 0 };// 首次探测时间5 秒, 间隔侦测时间2 秒 clientSocket.IOControl(IOControlCode.KeepAliveValues, inValue, null); } /// /// 发送vx socket消息 /// /// /// public void AsynSend(byte[] _SendBuff) { try { int times = 0; while (!connected && times < 5) { // Log(new LogInfo(jobinfo.JobID, "调试", , 3)); // LogHelper.GetSingleObj().Error("Wechat AsynSend", $"{weixin.WeixinHao}-{hostEndPoint}- 等待连接!"); Thread.Sleep(2000); times++; } if (!connected) { LogHelper.GetSingleObj().Error("Wechat AsynSend", $"{weixin.WeixinHao}-{hostEndPoint}- 等待连接!"); if (null != SocketExceptionCallback) { SocketExceptionCallback(WXSocketClientError.connetedErr,this); } return; //Log("wx服务器连接失败,请尝试重启工号"); // this.Connect(); } byte[] SendBuff = _SendBuff; var temp = Encoding.UTF8.GetString(SendBuff); clientSocket.BeginSend(SendBuff, 0, SendBuff.Length, SocketFlags.None, asyncResult => { try { //完成发送消息 int length = clientSocket.EndSend(asyncResult); LogHelper.GetSingleObj().Info("Wechat AsynSend", $"{weixin.WeixinHao}-{hostEndPoint}-已发送{length}字节!"); } catch (Exception) { } }, null); } catch (Exception ex) { //Log ("wx服务器接收数据异常,详情:" + ex.Message + Environment.NewLine + ex.StackTrace) ; LogHelper.GetSingleObj().Error("Wechat AsynSend", $"{weixin.WeixinHao}-{hostEndPoint}- 发送失败!{ex.Message}"); //微信socket异常问题 if (null != SocketExceptionCallback) { if (ex.Message.Contains("主机中的软件中止了一个已建立的连接。")) SocketExceptionCallback(WXSocketClientError.connetedErr,this); else SocketExceptionCallback(WXSocketClientError.sendErr,this); } } } /// /// 通过seq取微信服务器返回的socket包数据 /// /// /// public byte[] GetBuffBySeq(int Seq) { lock (mPackDicLock) { //Thread.Sleep(10); byte[] buf = null; try { if (mPackDic.ContainsKey(Seq)) { buf = mPackDic[Seq].Data; mPackDic.Remove(Seq); return buf; } } catch (Exception ee) { LogHelper.GetSingleObj().Error("Wechat GetBuffBySeq", $"{weixin.WeixinHao}-{hostEndPoint}- 获取超时!{ee.Message}"); } return buf; } } /// /// 接收微信socket返回的数据 /// /// private void AsynRecive() { Thread.Sleep(50); if (connected == false || clientSocket == null) return; //byte[] data = new byte[0x20000]; byte[] data = new byte[150000]; try { //开始接收数据 clientSocket.BeginReceive(data, 0, data.Length, SocketFlags.None, asyncResult => { if (connected == false || clientSocket == null) { return; } try { //本次接收的数据长度 int nowReceiveLenth = clientSocket.EndReceive(asyncResult); //建立起连接后 若长时间不发送数据 wx会立马关闭socket if (nowReceiveLenth == 0) { //vx socket 服务端关闭了连接,需要重连socket //if (clientSocket.Connected)//上次socket的状态 //{ //Log("wxsocket服务端关闭了连接,将尝试新建连接"); //微信socket异常问题 if (null != SocketExceptionCallback) { SocketExceptionCallback(WXSocketClientError.receiveErr,this); } //} return; } byte[] new_data = new byte[nowReceiveLenth]; Buffer.BlockCopy(data, 0, new_data, 0, nowReceiveLenth); LogHelper.GetSingleObj().Info("Wechat AsynRecive", $"{weixin.WeixinHao}-{hostEndPoint}-{data.Length}"); DePack(new_data); AsynRecive(); } catch (Exception ex) { //LogHelper.GetSingleObj().Error("Wechat AsynRecive1", ex.Message); LogHelper.GetSingleObj().Error("Wechat AsynRecive1", $"{weixin.WeixinHao}-{hostEndPoint}- { ex.Message}"); // Log("解析wx数据异常,详情:" + ee.Message + Environment.NewLine + ee.StackTrace); // Log(new LogInfo(jobinfo.JobID, "调试", "wxsocket服务端关闭了连接,将尝试新建连接", 3)); //微信socket异常问题 if (null != SocketExceptionCallback) { SocketExceptionCallback(WXSocketClientError.receiveErr,this); } } }, null); } catch (Exception ex) { // Log("连接被wx服务器关闭,接收数据失败。异常详情:" + ex.Message + Environment.NewLine + ex.StackTrace); // LogHelper.GetSingleObj().Error("Wechat AsynRecive2", ex.Message); LogHelper.GetSingleObj().Error("Wechat AsynRecive2", $"{weixin.WeixinHao}-{hostEndPoint}- { ex.Message}"); //微信socket异常问题 if (null != SocketExceptionCallback) SocketExceptionCallback(WXSocketClientError.receiveErr,this); } //finally //{ //} } //分包 public bool DePack(byte[] bys) { bool result = false; int x = bys.Length; if (packageData != null) { byte[] temp = new byte[packageData.Length + x]; Buffer.BlockCopy(packageData, 0, temp, 0, packageData.Length); Buffer.BlockCopy(bys, 0, temp, packageData.Length, x); packageData = temp; } else { packageData = new byte[x]; Buffer.BlockCopy(bys, 0, packageData, 0, x); } while (packageData != null && packageData.Length > 16) { int newPackageLength = WXClientTool.ReadInt(packageData, 0); if (newPackageLength <= 0 || newPackageLength > 8000000) { LogHelper.GetSingleObj().Error("Wechat DePack", "长度不合法"); packageData = null; } else if (newPackageLength <= packageData.Length) { byte[] newPackage = new byte[newPackageLength]; Buffer.BlockCopy(packageData, 0, newPackage, 0, newPackageLength); if (newPackageLength < packageData.Length) { byte[] temData = new byte[packageData.Length - newPackageLength]; Buffer.BlockCopy(packageData, newPackageLength, temData, 0, packageData.Length - newPackageLength); packageData = temData; } else { packageData = null; } HandlePackage(newPackage); } else { break; } } return result; } //解析包 public void HandlePackage(byte[] bys) { if (bys.Length == 20 && bys[3] == 20 && bys[5] == 16 && bys[7] == 1) { // 有新消息就会接受到此包 SaveBufferToPackDic(bys); return; } else { if (bys.Length >= 16 && bys[16] != (byte)191 && !(bys[3] == 58 && bys[5] == 16 && bys[7] == 1 && bys.Length == 58) && !(bys[3] == 47 && bys[5] == 16 && bys[7] == 1 && bys.Length == 47)) { return; } SaveBufferToPackDic(bys); } } //保存数据到mPackDic public void SaveBufferToPackDic(byte[] bys) { lock (mPackDicLock) { Seq = WXClientTool.ReadInt(bys, 12); if (Seq == 0) { byte[] buffers = new byte[bys.Length]; Buffer.BlockCopy(bys, 0, buffers, 0, bys.Length); int cmd = WXClientTool.ReadInt(buffers, 8); int selector = WXClientTool.ReadInt(buffers, 16); LogHelper.GetSingleObj().Info("Wechat SaveBufferToPackDic", $"{weixin.WeixinHao}-{hostEndPoint}-收到{buffers.Length}字节!"); if (cmd == 318 && NotifyCallback != null) { NotifyCallback(buffers); } if (cmd == 24 && NotifyCallback != null) { NotifyCallback(buffers); } if (cmd != 24 && cmd != 318) { } } else { byte[] buffers = new byte[bys.Length]; Buffer.BlockCopy(bys, 0, buffers, 0, bys.Length); mPackDic[Seq] = new SocketResult() { Data = buffers, Time = DateTime.Now }; Seq = 0; } } } } }