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)
{
}
}
}
}