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; 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 MultiUserHandle();//new MapRecordRankingHander(); //mapRecordRankingHander = new MultiUserHandle(); Log.Information($"初始化连接,当前地址:{ IPAddress.Any }:{ConfigHelp.UdpPort}"); new TcpService1().RunServer(ReceivedData); //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, MsgModel 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, //ShowVirtual = msg.ShowVirtual V = msg.V, Service = service }); } if (msg.CommandType == 0) { var client = Clients.FirstOrDefault(n => n.Equals(remoteIpEndPoint)); client.LastActiveTime = DateTime.Now; //client.ShowVirtual = msg.ShowVirtual; } else if (msg.CommandType == 1) { receiveMes.Add(msg); } }); } 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 list = 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(list)}"); //\r\n虚拟人:{Newtonsoft.Json.JsonConvert.SerializeObject(virtualData)} #endif list.AddRange(virtualData); SendMessage(Clients, list); dispatcher.Invoke(() => { Customers.Clear(); foreach (var item in list) { if (Customers.Any(c => c.MemberId == item.MemberId)) { continue; } Customers.Add(item); } //移除下线的客户端 for (int i = 0; i < list.Count; i++) { if (list[i].exit && list[i].MemberId >0)//客户端退出,并且不是虚拟的人物 { //这个地方有严重的逻辑错误(虚拟的人物不能和真实的人用同一个名字) var info = Clients.FirstOrDefault(n => n.MemberId == list[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()) { 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 += "|"; } //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.ASCII.GetBytes(strV1); var dataV1ForUdp = strV1.Last() == '|' ? Encoding.ASCII.GetBytes(strV1.Substring(0, strV1.Length - 1)) : dataV1; SendDataSize = $"\t单客户端数据包V1:{ (strV1.Length/1000D) }KB,一共占用带宽:{ strV1.Length / 1000D * clients1.Count }KB"; foreach (var item in clients1) { try { if(item == null) { continue; } if((item.Service is UdpService) ==false) { continue; } if (item.V == 1) { item.Service.Send(dataV1ForUdp, dataV1ForUdp.Length, item.IPEndPoint); } else { item.Service.Send(data, data.Length, item.IPEndPoint); } } catch (Exception e) { Debug.WriteLine(e.Message); Log.Error($"{ item.IPEndPoint.ToString() }:{ e.Message }\r\n{ e.StackTrace }"); } } var tcpClient = clients1.Where(c => c.Service is TcpService1).FirstOrDefault(); if(tcpClient != null) { tcpClient.Service.Send(dataV1, dataV1.Length, null); } } 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); } } }