• C# Socket UDP 案例 4 异步


    View Code
     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 }

    摘自:http://www.diybl.com/course/3_program/cshapo/csharpjs/20100714/442092.html

  • 相关阅读:
    jQuery 遍历 table
    jQuery下拉框三级联动
    C# 读取Excel模板 修改某行某列的值 另存为新的Excel
    jQuery iframe之间相互调用
    设计模式
    Rookey.Frame企业级快速开发框架(学习笔记)
    在Gridview中实现多选
    Gridview改变单元格颜色
    SQLserver函数编写和使用方法
    SVN服务器搭建和使用(转载)
  • 原文地址:https://www.cnblogs.com/graypigeon/p/2438424.html
Copyright © 2020-2023  润新知