UDP
internal class IocpUdpServer {
private Socket _listen;
private bool _isRun;
private readonly int _bufferLength;
//Sae池
private readonly SaeQueuePool _saeQueue = new SaeQueuePool(256);
/// <summary>
/// 获取SEA池中的可用项数量
/// </summary>
public int SeaCount => _saeQueue.Count;
/// <summary>
/// 获取当前运行的IP
/// </summary>
public string Ip { get; }
/// <summary>
/// 获取系统分配的UDP端口号
/// </summary>
public int Port { get; }
/// <summary>
///
/// </summary>
public long ReceivedBytesCount { get; private set; }
/// <summary>
///
/// </summary>
public long SendBytesCount { get; private set; }
/// <summary>
/// 收到的报文数量
/// </summary>
public int ReceivedCount { get; private set; }
/// <summary>
/// 发送的报文数量
/// </summary>
public int SendCount { get; private set; }
/// <summary>
///
/// </summary>
public bool IsRunning => _isRun;
//报文接收处理队列
private readonly IUdpRequestHandler _handlerQueue;
/// <summary>
/// 实例化UDP服务器,并直接启动监听
/// </summary>
/// <param name="handlerQueue">报文接收处理队列</param>
/// <param name="bufferLength">缓冲区大小</param>
/// <param name="port">监听的端口号</param>
public IocpUdpServer(IUdpRequestHandler handlerQueue, string ip, int port, int bufferLength = 1024) {
_handlerQueue = handlerQueue;
_bufferLength = bufferLength;
Ip = ip;
Port = port;
}
/// <summary>
/// 收到数据事件
/// </summary>
public event EventHandler<ReceiveDataEventArgs> ReceiveData;
/// <summary>
/// 启动UPD监听,接收来自网络上的UDP消息
/// </summary>
public void Start() {
//var local = new IPEndPoint(IPAddress.Any, Port);
var local = new IPEndPoint(IPAddress.Any, Port);
_listen = new Socket(local.AddressFamily, SocketType.Dgram, ProtocolType.Udp);
_listen.Bind(local);
var socketAsync = new SocketAsyncEventArgs();
socketAsync.SetBuffer(new byte[_bufferLength], 0, _bufferLength);
socketAsync.Completed += SocketAsync_Completed;
socketAsync.RemoteEndPoint = local;
_isRun = true;
StartReceive(socketAsync);
}
public void Stop() {
Close();
}
/// <summary>
/// 开始异步接收UDP消息
/// </summary>
private void StartReceive(SocketAsyncEventArgs socketAsync) {
if (!_isRun) return;
if (!_listen.ReceiveFromAsync(socketAsync))
SocketAsync_Completed(_listen, socketAsync);
}
private void SocketAsync_Completed(object sender, SocketAsyncEventArgs e) {
if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success) {
if (e.LastOperation == SocketAsyncOperation.ReceiveFrom) {
var data = new byte[e.BytesTransferred];
Buffer.BlockCopy(e.Buffer, e.Offset, data, 0, data.Length);
if (Settings.DebugUdpPacket)
LogConsole.Debug($"UDP Rcv:{data.ToHexString()},长度={data.Length}");
ReceivedBytesCount += e.BytesTransferred;
ReceivedCount++;
StartReceive(e);
//Console.WriteLine($"{DateTime.Now}\t{e.RemoteEndPoint}\t{buffer.Length}");
OnReceive((IPEndPoint)e.RemoteEndPoint, data);
return;
}
}
StartReceive(e);
}
/// <summary>
/// 远程端点收到消息处理
/// </summary>
private void OnReceive(IPEndPoint iPEndPoint, byte[] data) {
if (!_isRun) return;
if (iPEndPoint == null) return;
//小于8字节的报文不处理
if (data.Length < 8 + 4) {
LogConsole.Debug("报文过短,抛弃:" + data.ToHexString());
return;
}
//UDP的到达顺序不确定性可能导致问题
//TODO:拆包
var prefix = data[0];
var subfix = data.Last();
if (prefix != G.FrameHeader || subfix != G.FrameTail) {
LogConsole.Debug("收尾错误,抛弃:" + data.ToHexString());
return;
}
//Debug.WriteLine($"收到端点:{args.IpEndPoint},报文=> {data.ToHexString()}");
_handlerQueue.Enqueue(new UdpRequestWrapper(data, iPEndPoint));
//抛出收到数据事件
ReceiveData?.Invoke(this, new ReceiveDataEventArgs {
Data = data,
IpEndPoint = iPEndPoint
});
}
/// <summary>
/// 向远程网络端点发送数据
/// </summary>
public void SendAsync(EndPoint endPoint, byte[] bytes) {
if (!_isRun || _listen == null)
return;
//优先从可复用队列中取
var socketSendAsync = _saeQueue.Dequeue();
socketSendAsync.SetBuffer(bytes, 0, bytes.Length);
socketSendAsync.RemoteEndPoint = endPoint;
SendCount++;
SendBytesCount += bytes.Length;
if (Settings.DebugUdpPacket)
LogConsole.Debug($"UDP Send:{endPoint},Data={bytes.ToHexString()}");
//如果发送失败,则强制归队
if (!_listen.SendToAsync(socketSendAsync))
_saeQueue.Enqueue(socketSendAsync);
}
/// <summary>
/// 关闭服务
/// </summary>
public void Close() {
_isRun = false;
_listen?.Close();
_listen = null;
}
}
本文来自博客园,作者:willamyao,转载请注明原文链接:https://www.cnblogs.com/robertyao/p/12713496.html
代码改变世界

浙公网安备 33010602011771号