using Prism.Mvvm; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Text; using OnlineUserPool.Hander; using OnlineUserPool.Model; using OnlineUserPool.Unility; using Serilog; using System.Linq; using System.Net; using System.Net.Sockets; using System.Threading.Tasks; using System.Windows.Threading; using System.Diagnostics; using OnlineUserPool.Services; using Newtonsoft.Json; using System.Collections.Concurrent; using System.IO.Compression; using System.IO; namespace OnlineUserPool.ViewModels { public class MainWindowViewModel : BindableBase { public ObservableCollection Clients { get; private set; } = new ObservableCollection(); private static ConcurrentBag receiveMes = new ConcurrentBag(); private static object locker = new object(); public static System.Timers.Timer timer; private static IHandle mapRecordRankingHander; private Dispatcher dispatcher; public ObservableCollection Customers { get; private set; } = new ObservableCollection(); private string _Title = ""; public string Title { get { return _Title; } set { SetProperty(ref _Title, value); } } private string _SendDataSize = ""; public string SendDataSize { get { return _SendDataSize; } set { SetProperty(ref _SendDataSize, value); } } //private IService _udpService; public MainWindowViewModel() { Title = $"{ IPAddress.Any }:{ ConfigHelp.UdpPort }"; dispatcher = Dispatcher.CurrentDispatcher; //Customers.Add("suntao"); WriteLine(DateTime.Now.ToShortDateString()); LogHelper.Init(); mapRecordRankingHander = new MapRecordRankingHander();//new MultiUserHandle();// //mapRecordRankingHander = new MultiUserHandle(); Log.Information($"初始化连接,当前地址:{ IPAddress.Any }:{ConfigHelp.UdpPort}"); new TcpService1().RunServer(ReceivedData, CientDisconnected); //var tet = new System.Collections.Concurrent.ConcurrentBag(); var _udpService = new UdpService(); _udpService.RunServer(ReceivedData); Log.Information("服务启动成功"); timer = new System.Timers.Timer(1000); timer.Elapsed += Timer_Elapsed; timer.AutoReset = true; timer.Start(); Log.Information("等待连接"); //Console.ReadKey(); } private void ReceivedData(IPEndPoint remoteIpEndPoint, ReceiveModel msg, IService service) { dispatcher.Invoke(() => { if (!Clients.Any(c => c.Equals(remoteIpEndPoint))) { Clients.Add(new HostModel { IPEndPoint = remoteIpEndPoint, LastActiveTime = DateTime.Now, //RouteId = msg.RouteId, //MemberId = msg.MemberId, //V = msg.V, //Encoding = msg.Encoding, //Client = msg.Client, Service = service }); } switch (msg.CommandType) { //ping命令 case 0: { var client = Clients.FirstOrDefault(n => n.Equals(remoteIpEndPoint)); client.LastActiveTime = DateTime.Now; if(msg.V > 0) { client.V = msg.V; } } break; //消息 case 1: { var client = Clients.FirstOrDefault(n => n.Equals(remoteIpEndPoint)); var msg1 = (msg as MsgModel); client.Competitionid = msg1.Competitionid; if (msg1.V > 0) { client.V = msg1.V; } receiveMes.Add(msg1); } break; //设置客户端 case 2: { var client = Clients.FirstOrDefault(n => n.Equals(remoteIpEndPoint)); var msg1 = (msg as SetClientCommand); client.Encoding = msg1.Encoding; client.Client = msg1.Client; client.V = msg1.V; client.MemberId = msg1.MemberId; client.Competitionid = msg1.Competitionid; client.IsWatch = msg1.IsWatch; } break; //case 3: // { // var client = Clients.FirstOrDefault(n => n.Equals(remoteIpEndPoint)); // var msg1 = (msg as SetWatchCommand); // client.Competitionid = msg1.Competitionid; // client.IsWatch = true; // } // break; default: break; } if (msg.CommandType == 0) { //client.ShowVirtual = msg.ShowVirtual; } else if (msg.CommandType == 1) { } }); } private void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { NotifyClient(); } private void NotifyClient() { try { if(!receiveMes.Any()) { dispatcher.Invoke(() => { //Customers.Clear(); //删除已经发送的数据 //receiveMes.Clear(); //移除5钟内连接不上的客户端 Clients.ToList().ForEach(item => { if (item.Expire) { Clients.Remove(item); } }); }); return; } lock (locker) { var msgs = CloneJson(receiveMes).ToList(); receiveMes.Clear(); //加入虚拟人物消息 var virtualData = mapRecordRankingHander.GetVirtualUserData(); WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "-当前在线人数:" + Clients.Count + "-当前虚拟人数:" + virtualData.Count); #if DEBUG WriteLine($"在线人:{Newtonsoft.Json.JsonConvert.SerializeObject(msgs)}"); //\r\n虚拟人:{Newtonsoft.Json.JsonConvert.SerializeObject(virtualData)} #endif msgs.AddRange(virtualData); SendMessage(Clients, msgs); dispatcher.Invoke(() => { Customers.Clear(); foreach (var item in msgs) { if (Customers.Any(c => c.MemberId == item.MemberId)) { continue; } Customers.Add(item); } //移除下线的客户端 for (int i = 0; i < msgs.Count; i++) { if (msgs[i].exit && msgs[i].MemberId >0)//客户端退出,并且不是虚拟的人物 { //这个地方有严重的逻辑错误(虚拟的人物不能和真实的人用同一个名字) var info = Clients.FirstOrDefault(n => n.MemberId == msgs[i].MemberId); if (info != null) { Clients.Remove(info); } } } //删除已经发送的数据 //receiveMes.Clear(); //移除5钟内连接不上的客户端 Clients.ToList().ForEach(item => { if (item.Expire) { Clients.Remove(item); } }); }); } //更新虚拟人物信息 mapRecordRankingHander.RemoveEndAndAddNewVirtualUser(Customers.Count); } catch (Exception e) { Log.Error($"NotifyClient:{ e.Message }\r\n{ e.StackTrace }"); } } private void SendMessage(Collection clients, List msgModels) { if (!clients.Any() || !msgModels.Any()) { return; } var clients1 = clients.ToList(); var list = CloneJson>(msgModels); foreach (var item in list) { item.PreDistance = Math.Round(item.PreDistance, 5); item.EndDistance = Math.Round(item.EndDistance, 5); item.WeightKg = Math.Round(item.WeightKg, 2); } string jsonString = Newtonsoft.Json.JsonConvert.SerializeObject(list.Select(m=> new { m.RouteId, m.MemberId, m.Point, m.IsCompleted, m.exit, m.Speed, m.PreDistance, m.EndDistance, //m.IsVirtual,//后面要把这个字段过滤掉 m.WeightKg, m.Competitionid, m.Saved, })); var data = Encoding.ASCII.GetBytes(jsonString); //SendDataSize = (data.Length/1000D).ToString() +"KB"; var strV1 = string.Join("|", list.Select(m => m.ToString(1))); if (!string.IsNullOrWhiteSpace(strV1)) { strV1 += "|"; } //strV1 = "abcdefghijklmnopqrstuvwxyz"; //System.IO.File.AppendAllText(System.Environment.CurrentDirectory + "要发送的数据.txt", strV1.Trim().Replace("\0", "") + "\r\n", Encoding.UTF8); WriteLine(strV1); WriteLine(strV1.Length.ToString()); //var dataV1 = Encoding.UTF8.GetBytes(strV1); //var dataV1ForUdp = strV1.Last() == '|' ? Encoding.ASCII.GetBytes(strV1.Substring(0, strV1.Length - 1)) : dataV1; //var dataCompressV1 = Encoding.UTF8.GetBytes($"*{ Convert.ToBase64String(CommonHelper.Compress(strV1)) }#"); var data1 = new Data1(strV1); var data1ForUdp = new Data1(strV1.Last() == '|' ? strV1.Substring(0, strV1.Length - 1) : strV1); //var watchList = string.Join('|', clients1.Where(c => c.IsWatch).Select(c => c.MemberId)); //var strV2 = $"*l{{{ strV1 }}};w{{{ watchList }}}#"; ////var dataCompressV2 = Encoding.UTF8.GetBytes($"{ Convert.ToBase64String(CommonHelper.Compress(strV2)) }"); //var data2 = new Data1(strV2); SendDataSize = $"\t单客户端数据包V1:{ data1.GetBytes().Length/1000D }KB,一共占用带宽:{ data1.GetBytes().Length / 1000D * clients1.Count }KB,压缩以后{ data1.GetBytes(true).Length/1000D * clients1.Count }KB"; #region udp发送数据 foreach (var item in clients1) { try { if(item == null) { continue; } //if((item.Service is UdpService) ==false) //{ // continue; //} if (item.V != 1 && item.V != 2) { item.Service.Send(data, data.Length, item.IPEndPoint); continue; } if (item.V == 1 && item.Service is UdpService) { item.Service.Send(data1ForUdp.GetBytes(), data1ForUdp.GetBytes().Length, item.IPEndPoint); } else { Data1 ddd = null;// = item.V == 1 ? ; if (item.V == 1) { ddd = data1; } else if (item.V == 2) { //ddd = data2; var temp = string.Join("|", list.Where(m => m.Competitionid == item.Competitionid).Select(m => m.ToString(2))) + "|"; var watchList1 = string.Join('|', clients1.Where(c => c.IsWatch && c.Competitionid == item.Competitionid).Select(c => c.MemberId)); var strV21 = $"*l{{{ temp }}};w{{{ watchList1 }}}#"; ddd = new Data1(strV21); } else { continue; } bool isZip = item.Encoding == "gzip"; item.Service.Send(ddd.GetBytes(isZip), ddd.GetBytes(isZip).Length, item.IPEndPoint); } } catch (Exception e) { Debug.WriteLine(e.Message); Log.Error($"{ item.IPEndPoint.ToString() }:{ e.Message }\r\n{ e.StackTrace }"); } } #endregion //#region tcp发送数据 //var tcpClient = clients1.Where(c => c.Service is TcpService1).FirstOrDefault(); //if(tcpClient != null) //{ // tcpClient.Service.Send(dataV1, dataV1.Length, null); //} //#endregion } void WriteLine(string str) { //Debug.WriteLine(str); } T CloneJson(T source) { // Don't serialize a null object, simply return the default for that object if (Object.ReferenceEquals(source, null)) { return default(T); } // initialize inner objects individually // for example in default constructor some list property initialized with some values, // but in 'source' these items are cleaned - // without ObjectCreationHandling.Replace default constructor values will be added to result var deserializeSettings = new JsonSerializerSettings { ObjectCreationHandling = ObjectCreationHandling.Replace }; return JsonConvert.DeserializeObject(JsonConvert.SerializeObject(source), deserializeSettings); } private void CientDisconnected(EndPoint point) { dispatcher.Invoke(() => { try { var client = Clients.FirstOrDefault(f => f.IPEndPoint.ToString() == point.ToString()); if (client != null) { Clients.Remove(client); } } catch(Exception ex) { Log.Information("在CientDisconnected触发以后,删除client时报错了,"+ ex.Message +", " + ex.StackTrace); } }); } } public class Data1 { private string _txt = ""; public Data1(string txt) { this._txt = txt; } public byte[] GetBytes(bool compress = false) { if (compress) { return GetCompressBytes(); } return Encoding.UTF8.GetBytes(this._txt); } private byte[] GetCompressBytes() { var temp = this._txt; if(temp[0] == '*') { temp = temp.Substring(1); } if(temp.Last() == '#') { temp = temp.Substring(0, temp.Length - 1); } return Encoding.UTF8.GetBytes($"*{ Convert.ToBase64String(CommonHelper.Compress(temp)) }#"); } } }