using Windows.Storage.Streams; using Windows.Networking; using Windows.Networking.Sockets; using System; using System.Threading.Tasks; using System.Threading; namespace Plane.Communication { public partial class UdpThroughDtuServiceConnection { #region Fields private IOutputStream _outputStream; private DatagramSocket _socket; private DataWriter _writer; private readonly AutoResetEvent _loginResultSignal = new AutoResetEvent(false); private bool _isLogined; //是否已登录成功 private byte[] loginResultDatagram; //记录登陆时返回的报文数据 #endregion /// /// 初始化 的实例。 /// /// /// public UdpThroughDtuServiceConnection(string ip, int port) { DtuServiceIP = ip; DtuServicePort = port; } /// /// 登陆到Dtu服务端。 /// 登陆方式极其简单,只需发送一个数据包(内含希望连接到的飞机ID) /// /// public virtual async Task OpenAsync() { if (IsOpen) { return; } await Task.Run(async () => { var bytes = ConstructHandShakeDatagramToDTUService(); if (_socket == null) { var hostName = new HostName(DtuServiceIP); _socket = new DatagramSocket(); //对于WP平台,若没有打开网络连接(比如WIFI),下面语句会报: //“No such host is known.(Exception from HRESULT:0x80072AF9)” try { await _socket.ConnectAsync(hostName, DtuServicePort.ToString()); } catch (Exception ex) { _socket = null; if ((uint)ex.HResult == 0x80072AF9) { throw new Exception("请检查是否已打开网络连接。"); } else { throw ex; } } _socket.MessageReceived += _socket_MessageReceived; _outputStream = await _socket.GetOutputStreamAsync(hostName, DtuServicePort.ToString()); _writer = new DataWriter(_outputStream); } _writer.WriteBytes(bytes); await _writer.StoreAsync(); //等待服务端的应答,获取是否连接成功飞机的结果 if (_loginResultSignal.WaitOne(10000)) { var ret = AnalyzeHandShakeDatagramFromDTUService(loginResultDatagram); if (ret == DTUHandShakeResult.Successful) { IsOpen = true; _isLogined = true; } else if (ret == DTUHandShakeResult.Occupied) { throw new Exception("飞机已被占用!"); } else if (ret == DTUHandShakeResult.NotExisted) { throw new Exception("飞机不存在!"); } else { throw new Exception("未知状态!"); } } else { IsOpen = false; throw new Exception("连接超时!"); } }).ConfigureAwait(false); } public virtual void Close() { IsOpen = false; _outputStream?.Dispose(); _writer?.Dispose(); if (_socket != null) { try { _socket.MessageReceived -= _socket_MessageReceived; _socket?.Dispose(); _socket = null; } catch (Exception) { } } } private async Task SendAsync(byte[] datagram, int bytes) { if (datagram.Length != bytes) { Array.Resize(ref datagram, bytes); } try { _writer.WriteBytes(datagram); await _writer.StoreAsync(); } catch { //发送异常可以内部消化之,因为Udp发送失败也无办法,同时也不用冒泡异常 } } private void _socket_MessageReceived(DatagramSocket sender, DatagramSocketMessageReceivedEventArgs args) { try { var reader = args.GetDataReader(); if (!_isLogined) { loginResultDatagram = new byte[reader.UnconsumedBufferLength]; reader.ReadBytes(loginResultDatagram); _loginResultSignal.Set(); } else { //以后收到的直接透传 var data = new byte[reader.UnconsumedBufferLength]; reader.ReadBytes(data); EnqueueDatagram(data); } } catch (Exception) { } } } }