zoukankan      html  css  js  c++  java
  • UDP 异步 收发 服务端例子 【转载】

    采用异步模式设计的UDP服务器,源码如下:

    1 using System;
    2  using System.Net;
    3  using System.Net.Sockets;
    4 using System.ServiceProcess;
    5 using System.Threading;
    6
    7 namespace TestUdpServer
    8 {
    9 // this class encapsulates a single packet that
    10 // is either sent or received by a UDP socket
    11 public class UDPPacketBuffer
    12 {
    13 // size of the buffer
    14 public const int BUFFER_SIZE = 4096;
    15
    16 // the buffer itself
    17 public byte[] Data;
    18
    19 // length of data to transmit
    20 public int DataLength;
    21
    22 // the (IP)Endpoint of the remote host
    23 public EndPoint RemoteEndPoint;
    24
    25 public UDPPacketBuffer()
    26 {
    27 this.Data = new byte[BUFFER_SIZE];
    28
    29 // this will be filled in by the call to udpSocket.BeginReceiveFrom
    30 RemoteEndPoint = (EndPoint)new IPEndPoint(IPAddress.Any, 0);
    31 }
    32
    33 public UDPPacketBuffer(byte[] data, EndPoint remoteEndPoint)
    34 {
    35 this.Data = data;
    36 this.DataLength = data.Length;
    37 this.RemoteEndPoint = remoteEndPoint;
    38 }
    39 }
    40
    41 public abstract class UDPServer
    42 {
    43 // the port to listen on
    44 private int udpPort;
    45
    46 // the UDP socket
    47 private Socket udpSocket;
    48
    49 // the ReaderWriterLock is used solely for the purposes of shutdown (Stop()).
    50 // since there are potentially many "reader" threads in the internal .NET IOCP
    51 // thread pool, this is a cheaper synchronization primitive than using
    52 // a Mutex object. This allows many UDP socket "reads" concurrently - when
    53 // Stop() is called, it attempts to obtain a writer lock which will then
    54 // wait until all outstanding operations are completed before shutting down.
    55 // this avoids the problem of closing the socket with outstanding operations
    56 // and trying to catch the inevitable ObjectDisposedException.
    57 private ReaderWriterLock rwLock = new ReaderWriterLock();
    58
    59 // number of outstanding operations. This is a reference count
    60 // which we use to ensure that the threads exit cleanly. Note that
    61 // we need this because the threads will potentially still need to process
    62 // data even after the socket is closed.
    63 private int rwOperationCount = 0;
    64
    65 // the all important shutdownFlag. This is synchronized through the ReaderWriterLock.
    66 private bool shutdownFlag = true;
    67
    68 // these abstract methods must be implemented in a derived class to actually do
    69 // something with the packets that are sent and received.
    70 protected abstract void PacketReceived(UDPPacketBuffer buffer);
    71 protected abstract void PacketSent(UDPPacketBuffer buffer, int bytesSent);
    72
    73 // ServiceName
    74 String ServiceName = "test";
    75
    76 public UDPServer(int port)
    77 {
    78 this.udpPort = port;
    79 }
    80
    81 public void Start()
    82 {
    83 if (shutdownFlag)
    84 {
    85 // create and bind the socket
    86 IPEndPoint ipep = new IPEndPoint(IPAddress.Any, udpPort);
    87 udpSocket = new Socket(
    88 AddressFamily.InterNetwork,
    89 SocketType.Dgram,
    90 ProtocolType.Udp);
    91 udpSocket.Bind(ipep);
    92 // we're not shutting down, we're starting up
    93 shutdownFlag = false;
    94
    95 // kick off an async receive. The Start() method will return, the
    96 // actual receives will occur asynchronously and will be caught in
    97 // AsyncEndRecieve().
    98 // I experimented with posting multiple AsyncBeginReceives() here in an attempt
    99 // to "queue up" reads, however I found that it negatively impacted performance.
    100 AsyncBeginReceive();
    101 }
    102 }
    103
    104 protected void Stop()
    105 {
    106 if (!shutdownFlag)
    107 {
    108 // wait indefinitely for a writer lock. Once this is called, the .NET runtime
    109 // will deny any more reader locks, in effect blocking all other send/receive
    110 // threads. Once we have the lock, we set shutdownFlag to inform the other
    111 // threads that the socket is closed.
    112 rwLock.AcquireWriterLock(-1);
    113 shutdownFlag = true;
    114 udpSocket.Close();
    115 rwLock.ReleaseWriterLock();
    116
    117 // wait for any pending operations to complete on other
    118 // threads before exiting.
    119 while (rwOperationCount > 0)
    120 Thread.Sleep(1);
    121 }
    122 }
    123
    124 public bool IsRunning
    125 {
    126 // self-explanitory
    127 get { return !shutdownFlag; }
    128 }
    129
    130 private void AsyncBeginReceive()
    131 {
    132 // this method actually kicks off the async read on the socket.
    133 // we aquire a reader lock here to ensure that no other thread
    134 // is trying to set shutdownFlag and close the socket.
    135 rwLock.AcquireReaderLock(-1);
    136
    137 if (!shutdownFlag)
    138 {
    139 // increment the count of pending operations
    140 Interlocked.Increment(ref rwOperationCount);
    141
    142 // allocate a packet buffer
    143 UDPPacketBuffer buf = new UDPPacketBuffer();
    144
    145 try
    146 {
    147 // kick off an async read
    148 udpSocket.BeginReceiveFrom(
    149 buf.Data,
    150 0,
    151 UDPPacketBuffer.BUFFER_SIZE,
    152 SocketFlags.None,
    153 ref buf.RemoteEndPoint,
    154 new AsyncCallback(AsyncEndReceive),
    155 buf);
    156 }
    157 catch (SocketException se)
    158 {
    159 // something bad happened
    160 System.Diagnostics.EventLog.WriteEntry(ServiceName,
    161 "A SocketException occurred in UDPServer.AsyncBeginReceive():\n\n" + se.Message,
    162 System.Diagnostics.EventLogEntryType.Error);
    163
    164 // an error occurred, therefore the operation is void. Decrement the reference count.
    165 Interlocked.Decrement(ref rwOperationCount);
    166 }
    167 }
    168
    169 // we're done with the socket for now, release the reader lock.
    170 rwLock.ReleaseReaderLock();
    171 }
    172
    173 private void AsyncEndReceive(IAsyncResult iar)
    174 {
    175 // Asynchronous receive operations will complete here through the call
    176 // to AsyncBeginReceive
    177
    178 // aquire a reader lock
    179 rwLock.AcquireReaderLock(-1);
    180
    181 if (!shutdownFlag)
    182 {
    183 // start another receive - this keeps the server going!
    184 AsyncBeginReceive();
    185
    186 // get the buffer that was created in AsyncBeginReceive
    187 // this is the received data
    188 UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState;
    189
    190 try
    191 {
    192 // get the length of data actually read from the socket, store it with the
    193 // buffer
    194 buffer.DataLength = udpSocket.EndReceiveFrom(iar, ref buffer.RemoteEndPoint);
    195
    196 // this operation is now complete, decrement the reference count
    197 Interlocked.Decrement(ref rwOperationCount);
    198
    199 // we're done with the socket, release the reader lock
    200 rwLock.ReleaseReaderLock();
    201
    202 // call the abstract method PacketReceived(), passing the buffer that
    203 // has just been filled from the socket read.
    204 PacketReceived(buffer);
    205 }
    206 catch (SocketException se)
    207 {
    208 // something bad happened
    209 System.Diagnostics.EventLog.WriteEntry(ServiceName,
    210 "A SocketException occurred in UDPServer.AsyncEndReceive():\n\n" + se.Message,
    211 System.Diagnostics.EventLogEntryType.Error);
    212
    213 // an error occurred, therefore the operation is void. Decrement the reference count.
    214 Interlocked.Decrement(ref rwOperationCount);
    215
    216 // we're done with the socket for now, release the reader lock.
    217 rwLock.ReleaseReaderLock();
    218 }
    219 }
    220 else
    221 {
    222 // nothing bad happened, but we are done with the operation
    223 // decrement the reference count and release the reader lock
    224 Interlocked.Decrement(ref rwOperationCount);
    225 rwLock.ReleaseReaderLock();
    226 }
    227 }
    228
    229 public void AsyncBeginSend(UDPPacketBuffer buf)
    230 {
    231 // by now you should you get the idea - no further explanation necessary
    232
    233 rwLock.AcquireReaderLock(-1);
    234
    235 if (!shutdownFlag)
    236 {
    237 try
    238 {
    239 Interlocked.Increment(ref rwOperationCount);
    240 udpSocket.BeginSendTo(
    241 buf.Data,
    242 0,
    243 buf.DataLength,
    244 SocketFlags.None,
    245 buf.RemoteEndPoint,
    246 new AsyncCallback(AsyncEndSend),
    247 buf);
    248 }
    249 catch (SocketException se)
    250 {
    251 System.Diagnostics.EventLog.WriteEntry(ServiceName,
    252 "A SocketException occurred in UDPServer.AsyncBeginSend():\n\n" + se.Message,
    253 System.Diagnostics.EventLogEntryType.Error);
    254 }
    255 }
    256
    257 rwLock.ReleaseReaderLock();
    258 }
    259
    260 private void AsyncEndSend(IAsyncResult iar)
    261 {
    262 // by now you should you get the idea - no further explanation necessary
    263
    264 rwLock.AcquireReaderLock(-1);
    265
    266 if (!shutdownFlag)
    267 {
    268 UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState;
    269
    270 try
    271 {
    272 int bytesSent = udpSocket.EndSendTo(iar);
    273
    274 // note that call to the abstract PacketSent() method - we are passing the number
    275 // of bytes sent in a separate parameter, since we can't use buffer.DataLength which
    276 // is the number of bytes to send (or bytes received depending upon whether this
    277 // buffer was part of a send or a receive).
    278 PacketSent(buffer, bytesSent);
    279 }
    280 catch (SocketException se)
    281 {
    282 System.Diagnostics.EventLog.WriteEntry(ServiceName,
    283 "A SocketException occurred in UDPServer.AsyncEndSend():\n\n" + se.Message,
    284 System.Diagnostics.EventLogEntryType.Error);
    285 }
    286 }
    287
    288 Interlocked.Decrement(ref rwOperationCount);
    289 rwLock.ReleaseReaderLock();
    290 }
    291
    292 }
    293 }

    实际使用时需继承抽象类UDPServer,并实现异步处理数据的相关方案,示例如下:

    1 using System;
    2 using System.Collections.Generic;
    3 using System.Text;
    4 using System.Runtime.InteropServices;
    5
    6 namespace TestUdpServer
    7 {
    8 public class TUdpServer : UDPServer
    9 {
    10
    11 public TUdpServer(int port)
    12 : base(port)
    13 {
    14 Console.WriteLine("Server Start...@" + port.ToString());
    15 }
    16
    17 protected override void PacketReceived(UDPPacketBuffer buffer)
    18 {
    19 AsyncBeginSend(buffer);
    20 }
    21
    22 protected override void PacketSent(UDPPacketBuffer buffer, int bytesSent)
    23 {
    24
    25 }
    26
    27 }
    28 }
    29
  • 相关阅读:
    [Codechef Coders' Legacy 2018 CLSUMG]Sum of Primes
    [HDU4630]No Pain No Game
    [Luogu4329][COCI2006]Bond
    [数论]Gcd/ExGcd欧几里得学习笔记
    [数论]线性基学习笔记
    [Luogu5190][COCI2010]PROGRAM
    IIS7 HTTPS 绑定主机头,嘿嘿,转
    React
    ios
    iOS10 权限配置
  • 原文地址:https://www.cnblogs.com/niuniu502/p/2335240.html
Copyright © 2011-2022 走看看