NetFlowService.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447
  1. //************************************************************************
  2. // https://github.com/yuzhengyang
  3. // author: yuzhengyang
  4. // date: 2016.5.1 - 2017.6.16
  5. // desc: 网络流量监测工具
  6. // Copyright (c) yuzhengyang. All rights reserved.
  7. //************************************************************************
  8. using Azylee.Core.AppUtils;
  9. using Azylee.Core.DataUtils.CollectionUtils;
  10. using Azylee.Core.ProcessUtils;
  11. using Azylee.Core.WindowsUtils.InfoUtils;
  12. using System;
  13. using System.Collections.Generic;
  14. using System.Diagnostics;
  15. using System.Linq;
  16. using System.Net;
  17. using static Azylee.Core.NetUtils.NetProcessTool;
  18. namespace Azylee.Core.NetUtils
  19. {
  20. public class NetFlowService
  21. {
  22. public bool IsNetFlowRun { get { return _IsNetFlowRun; } }
  23. private bool _IsNetFlowRun = false;
  24. public bool IsNetPacketRun { get { return _IsNetPacketRun; } }
  25. private bool _IsNetPacketRun = false;
  26. /// <summary>
  27. /// 程序联网信息列表
  28. /// </summary>
  29. public List<NetProcessInfo> NetProcessInfoList { get { return _NetProcessInfoList; } }
  30. List<NetProcessInfo> _NetProcessInfoList = new List<NetProcessInfo>();
  31. /// <summary>
  32. /// 网络流量计数器
  33. /// </summary>
  34. public NetFlowTool NetFlow { get { return _NetFlow; } }
  35. NetFlowTool _NetFlow = new NetFlowTool();
  36. List<NetPacketTool> NetPacketList = new List<NetPacketTool>();
  37. NetProcessTool.TcpRow[] TcpConnection;
  38. NetProcessTool.UdpRow[] UdpConnection;
  39. Process[] NowProcess;
  40. List<string> AllIPv4Address = new List<string>();
  41. public long LostPacketCount { get; set; }
  42. /// <summary>
  43. /// 开启网络流量监控
  44. /// </summary>
  45. public void Start()
  46. {
  47. #region 启动系统性能计数器统计
  48. try
  49. {
  50. _NetFlow.Start();
  51. _NetFlow.DataMonitorEvent += DataMonitorEvent;
  52. _IsNetFlowRun = true;
  53. }
  54. catch { }
  55. #endregion
  56. #region 启动Socket包统计
  57. if (PermissionTool.IsAdmin())
  58. {
  59. List<IPAddress> hosts = NetCardInfoTool.GetIPv4Address();
  60. AllIPv4Address = NetCardInfoTool.GetAllIPv4Address();
  61. foreach (var host in hosts)
  62. {
  63. try
  64. {
  65. NetPacketTool p = new NetPacketTool(host);
  66. p.NewPacket += new NewPacketEventHandler(NewPacketEvent);
  67. p.Start();
  68. NetPacketList.Add(p);
  69. }
  70. catch { }
  71. }
  72. if (ListTool.HasElements(NetPacketList)) _IsNetPacketRun = true;
  73. }
  74. #endregion
  75. }
  76. /// <summary>
  77. /// 关闭网络流量监控
  78. /// </summary>
  79. public void Stop()
  80. {
  81. if (_IsNetFlowRun)
  82. {
  83. _NetFlow.Stop();
  84. _IsNetFlowRun = false;
  85. }
  86. if (_IsNetPacketRun)
  87. {
  88. NetPacketList.ForEach(x => { x.Stop(); });
  89. _IsNetPacketRun = false;
  90. }
  91. }
  92. /// <summary>
  93. /// 系统性能计数器每秒统计事件
  94. /// </summary>
  95. /// <param name="n"></param>
  96. public void DataMonitorEvent(NetFlowTool n)
  97. {
  98. NowProcess = Process.GetProcesses();
  99. GetConnection();
  100. SetNetProcess();
  101. CalcNetProcessInfo();
  102. CheckRestart();
  103. }
  104. /// <summary>
  105. /// 整理数据包到所属的进程
  106. /// </summary>
  107. /// <param name="tool"></param>
  108. /// <param name="packet"></param>
  109. private void NewPacketEvent(NetPacketTool tool, Packet packet)
  110. {
  111. bool isGather = false;
  112. #region 整理TCP包
  113. if (packet.Protocol == Protocol.Tcp && ListTool.HasElements(TcpConnection) && ListTool.HasElements(NowProcess))
  114. {
  115. lock (TcpConnection)
  116. {
  117. // tcp 下载
  118. if (TcpConnection.Any(x => x.RemoteIP.ToString() == packet.DestinationAddress.ToString() && x.RemotePort == packet.DestinationPort))
  119. {
  120. var tcpDownload = TcpConnection.FirstOrDefault(x => x.RemoteIP.ToString() == packet.DestinationAddress.ToString() && x.RemotePort == packet.DestinationPort);
  121. var process = NowProcess.FirstOrDefault(x => x.Id == tcpDownload.ProcessId);
  122. if (process != null)
  123. {
  124. var info = _NetProcessInfoList.FirstOrDefault(x => x.ProcessName == process.ProcessName);
  125. if (info != null)
  126. {
  127. isGather = true;
  128. info.DownloadBag += packet.TotalLength;
  129. info.DownloadBagCount += packet.TotalLength;
  130. }
  131. }
  132. }
  133. // tcp 上传
  134. if (TcpConnection.Any(x => x.LocalIP.ToString() == packet.SourceAddress.ToString() && x.LocalPort == packet.SourcePort))
  135. {
  136. var tcUpload = TcpConnection.FirstOrDefault(x => x.LocalIP.ToString() == packet.SourceAddress.ToString() && x.LocalPort == packet.SourcePort);
  137. var process = NowProcess.FirstOrDefault(x => x.Id == tcUpload.ProcessId);
  138. if (process != null)
  139. {
  140. var info = _NetProcessInfoList.FirstOrDefault(x => x.ProcessName == process.ProcessName);
  141. if (info != null)
  142. {
  143. isGather = true;
  144. info.UploadBag += packet.TotalLength;
  145. info.UploadBagCount += packet.TotalLength;
  146. }
  147. }
  148. }
  149. }
  150. }
  151. #endregion
  152. #region 整理UDP包
  153. if (packet.Protocol == Protocol.Udp && ListTool.HasElements(UdpConnection) && ListTool.HasElements(NowProcess))
  154. {
  155. lock (UdpConnection)
  156. {
  157. // tcp 下载
  158. if (UdpConnection.Any(x => x.LocalPort == packet.DestinationPort) && AllIPv4Address.Contains(packet.DestinationAddress.ToString()))
  159. {
  160. var udpDownload = UdpConnection.FirstOrDefault(x => AllIPv4Address.Contains(x.LocalIP.ToString()) && x.LocalPort == packet.DestinationPort);
  161. var process = NowProcess.FirstOrDefault(x => x.Id == udpDownload.ProcessId);
  162. if (process != null)
  163. {
  164. var info = _NetProcessInfoList.FirstOrDefault(x => x.ProcessName == process.ProcessName);
  165. if (info != null)
  166. {
  167. isGather = true;
  168. info.DownloadBag += packet.TotalLength;
  169. info.DownloadBagCount += packet.TotalLength;
  170. if (info.ProcessName == "Idle")
  171. {
  172. }
  173. }
  174. }
  175. }
  176. // udp 上传
  177. if (UdpConnection.Any(x => x.LocalPort == packet.SourcePort) && AllIPv4Address.Contains(packet.SourceAddress.ToString()))
  178. {
  179. var udpIp = AllIPv4Address.FirstOrDefault(x => x == packet.SourceAddress.ToString());
  180. var ucUpload = UdpConnection.FirstOrDefault(x => AllIPv4Address.Contains(x.LocalIP.ToString()) && x.LocalPort == packet.SourcePort);
  181. var process = NowProcess.FirstOrDefault(x => x.Id == ucUpload.ProcessId);
  182. if (process != null)
  183. {
  184. var info = _NetProcessInfoList.FirstOrDefault(x => x.ProcessName == process.ProcessName);
  185. if (info != null)
  186. {
  187. isGather = true;
  188. info.UploadBag += packet.TotalLength;
  189. info.UploadBagCount += packet.TotalLength;
  190. if (info.ProcessName == "Idle")
  191. {
  192. }
  193. }
  194. }
  195. }
  196. }
  197. }
  198. #endregion
  199. if (!isGather)
  200. {
  201. LostPacketCount++;
  202. }
  203. }
  204. #region 获取所有网络连接
  205. /// <summary>
  206. /// 获取所有网络连接并整理列表
  207. /// </summary>
  208. void GetConnection()
  209. {
  210. TcpConnection = NetProcessTool.GetTcpConnection();
  211. UdpConnection = NetProcessTool.GetUdpConnection();
  212. }
  213. #endregion
  214. #region 设置程序流量及连接数统计列表
  215. /// <summary>
  216. /// 清空并重置当前所有程序的连接数
  217. /// </summary>
  218. void SetNetProcess()
  219. {
  220. // 清空已有连接数
  221. if (ListTool.HasElements(_NetProcessInfoList))
  222. _NetProcessInfoList.ForEach(x =>
  223. {
  224. x.NetConnectionInfoList = new List<NetConnectionInfo>();
  225. });
  226. // 统计TCP连接数
  227. if (ListTool.HasElements(TcpConnection))
  228. {
  229. foreach (var t in TcpConnection)
  230. {
  231. SetNetProcessConnection(t);
  232. }
  233. }
  234. // 统计UDP连接数
  235. if (ListTool.HasElements(UdpConnection))
  236. {
  237. foreach (var u in UdpConnection)
  238. {
  239. SetNetProcessConnection(u);
  240. }
  241. }
  242. }
  243. /// <summary>
  244. /// 整理TCP连接到所属的进程
  245. /// </summary>
  246. /// <param name="t"></param>
  247. void SetNetProcessConnection(TcpRow t)
  248. {
  249. try
  250. {
  251. Process p = NowProcess.FirstOrDefault(x => x.Id == t.ProcessId);
  252. if (p != null)
  253. {
  254. var ppl = _NetProcessInfoList.FirstOrDefault(x => x.ProcessName == p.ProcessName);
  255. if (ppl == null)
  256. {
  257. _NetProcessInfoList.Add(
  258. new NetProcessInfo()
  259. {
  260. ProcessId = p.Id,
  261. ProcessIcon = ProcessInfoTool.GetIcon(p, false),
  262. ProcessName = p.ProcessName,
  263. LastUpdateTime = DateTime.Now,
  264. NetConnectionInfoList = new List<NetConnectionInfo>() {
  265. new NetConnectionInfo() {
  266. LocalIP = t.LocalIP.ToString(),
  267. LocalPort = t.LocalPort,
  268. RemoteIP = t.RemoteIP.ToString(),
  269. RemotePort = t.RemotePort,
  270. ProtocolName = "TCP",
  271. Status = t.State,
  272. LastUpdateTime = DateTime.Now,
  273. }
  274. },
  275. });
  276. }
  277. else
  278. {
  279. ppl.LastUpdateTime = DateTime.Now;
  280. var conn = ppl.NetConnectionInfoList.FirstOrDefault(x => x.LocalIP == t.LocalIP.ToString() && x.LocalPort == t.LocalPort && x.RemoteIP == t.RemoteIP.ToString() && x.RemotePort == t.RemotePort);
  281. if (conn == null)
  282. {
  283. ppl.NetConnectionInfoList.Add(new NetConnectionInfo()
  284. {
  285. LocalIP = t.LocalIP.ToString(),
  286. LocalPort = t.LocalPort,
  287. RemoteIP = t.RemoteIP.ToString(),
  288. RemotePort = t.RemotePort,
  289. ProtocolName = "TCP",
  290. Status = t.State,
  291. LastUpdateTime = DateTime.Now,
  292. });
  293. }
  294. }
  295. }
  296. }
  297. catch (Exception e)
  298. { }
  299. }
  300. /// <summary>
  301. /// 整理UDP连接到所属的进程
  302. /// </summary>
  303. /// <param name="u"></param>
  304. void SetNetProcessConnection(UdpRow u)
  305. {
  306. try
  307. {
  308. Process p = NowProcess.FirstOrDefault(x => x.Id == u.ProcessId);
  309. if (p != null)
  310. {
  311. var ppl = _NetProcessInfoList.FirstOrDefault(x => x.ProcessName == p.ProcessName);
  312. if (ppl == null)
  313. {
  314. _NetProcessInfoList.Add(
  315. new NetProcessInfo()
  316. {
  317. ProcessId = p.Id,
  318. ProcessIcon = ProcessInfoTool.GetIcon(p, false),
  319. ProcessName = p.ProcessName,
  320. LastUpdateTime = DateTime.Now,
  321. NetConnectionInfoList = new List<NetConnectionInfo>() {
  322. new NetConnectionInfo() {
  323. LocalIP = u.LocalIP.ToString(),
  324. LocalPort = u.LocalPort,
  325. ProtocolName = "UDP",
  326. LastUpdateTime = DateTime.Now,
  327. }
  328. },
  329. });
  330. }
  331. else
  332. {
  333. ppl.LastUpdateTime = DateTime.Now;
  334. var conn = ppl.NetConnectionInfoList.FirstOrDefault(x => x.LocalIP == u.LocalIP.ToString() && x.LocalPort == u.LocalPort);
  335. if (conn == null)
  336. {
  337. ppl.NetConnectionInfoList.Add(new NetConnectionInfo()
  338. {
  339. LocalIP = u.LocalIP.ToString(),
  340. LocalPort = u.LocalPort,
  341. ProtocolName = "UDP",
  342. LastUpdateTime = DateTime.Now,
  343. });
  344. }
  345. }
  346. }
  347. }
  348. catch (Exception e)
  349. { }
  350. }
  351. #endregion
  352. #region 整理程序流量汇总信息
  353. /// <summary>
  354. /// 整理计算程序网络流量
  355. /// </summary>
  356. void CalcNetProcessInfo()
  357. {
  358. if (ListTool.HasElements(_NetProcessInfoList))
  359. {
  360. _NetProcessInfoList.ForEach(p =>
  361. {
  362. p.UploadDataCount += p.UploadData;
  363. p.DownloadDataCount += p.DownloadData;
  364. });
  365. int allupbag = _NetProcessInfoList.Sum(x => x.UploadBag);
  366. int alldownbag = _NetProcessInfoList.Sum(x => x.DownloadBag);
  367. _NetProcessInfoList.ForEach(p =>
  368. {
  369. if (allupbag > 0 && _NetFlow.UploadData > 0)
  370. {
  371. float uprate = (float)p.UploadBag / allupbag;
  372. p.UploadData = (int)(uprate * _NetFlow.UploadData);
  373. }
  374. if (alldownbag > 0 && _NetFlow.DownloadData > 0)
  375. {
  376. float downrate = (float)p.DownloadBag / alldownbag;
  377. p.DownloadData = (int)(downrate * _NetFlow.DownloadData);
  378. }
  379. p.UploadBag = 0;
  380. p.DownloadBag = 0;
  381. p.LastUpdateTime = DateTime.Now;
  382. });
  383. }
  384. }
  385. #endregion
  386. #region 联网断网重启计划
  387. /// <summary>
  388. /// 联网断网重启计划(应对断网或重连后网卡抓包报错造成的不准确)
  389. /// </summary>
  390. private void CheckRestart()
  391. {
  392. bool rest = false;
  393. string[] ints = NetCardInfoTool.GetInstanceNames();
  394. if (ListTool.IsNullOrEmpty(_NetFlow.Instances) && ListTool.HasElements(ints))
  395. {
  396. rest = true;
  397. }
  398. if (ListTool.HasElements(_NetFlow.Instances) && ListTool.HasElements(ints) &&
  399. string.Join("-", _NetFlow.Instances) != string.Join("-", ints))
  400. {
  401. rest = true;
  402. }
  403. if (rest)
  404. {
  405. //重启 系统性能计数器
  406. _NetFlow.Restart();
  407. //重启 抓包监听
  408. List<IPAddress> hosts = NetCardInfoTool.GetIPv4Address();
  409. AllIPv4Address = NetCardInfoTool.GetAllIPv4Address();
  410. foreach (var host in hosts)
  411. {
  412. try
  413. {
  414. if (!NetPacketList.Any(x => x.IP.ToString() == host.ToString()))
  415. {
  416. NetPacketTool p = new NetPacketTool(host);
  417. p.NewPacket += new NewPacketEventHandler(NewPacketEvent);
  418. p.Start();
  419. NetPacketList.Add(p);
  420. }
  421. }
  422. catch { }
  423. }
  424. }
  425. }
  426. #endregion
  427. }
  428. }