Plane.Sdk3/PlaneGcsSdk_UWP/Communication/UdpThroughDtuServiceConnection.UWP.cs
2017-02-27 02:02:19 +08:00

167 lines
5.6 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
/// <summary>
/// 初始化 <see cref="UdpThroughDtuServiceConnection"/> 的实例。
/// </summary>
/// <param name="ip"></param>
/// <param name="port"></param>
public UdpThroughDtuServiceConnection(string ip, int port)
{
DtuServiceIP = ip;
DtuServicePort = port;
}
/// <summary>
/// 登陆到Dtu服务端。
/// 登陆方式极其简单只需发送一个数据包内含希望连接到的飞机ID
/// </summary>
/// <returns></returns>
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)
{
}
}
}
}