167 lines
5.6 KiB
C#
167 lines
5.6 KiB
C#
|
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)
|
|||
|
{
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|