old_flsystem/类库/Chat.Framework/WXSdk/IPAD/SocketClient.cs

454 lines
16 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
{
/// <summary>
/// Socket管理
/// </summary>
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<int, SocketResult> mPackDic = new Dictionary<int, SocketResult>();
private object mPackDicLock = new object();
public Func<byte[], bool> 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<WXSocketClientError,SocketClient, bool> 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);
}
/// <summary>
/// 发送vx socket消息
/// </summary>
/// <param name="socket"></param>
/// <param name="message"></param>
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);
}
}
}
/// <summary>
/// 通过seq取微信服务器返回的socket包数据
/// </summary>
/// <param name="Seq"></param>
/// <returns></returns>
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;
}
}
/// <summary>
/// 接收微信socket返回的数据
/// </summary>
/// <param name="socket"></param>
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;
}
}
}
}
}