基于C#的socket编程的TCP异步的实现代码

2019-12-30 14:24:36刘景俊

 

3.3 程序阻塞与异步中的同步问题

.Net里提供了EventWaitHandle类来表示一个线程的同步事件。EventWaitHandle即事件等待句柄,他允许线程通过操作系统互发信号和等待彼此的信号来达到线程同步的目的。这个类有2个子类,分别为AutoRestEevnt(自动重置)和ManualRestEvent(手动重置)。下面是线程同步的几个方法:

(1)Rset方法:将事件状态设为非终止状态,导致线程阻塞。这里的线程阻塞是指允许其他需要等待的线程进行阻塞即让含WaitOne()方法的线程阻塞;

(2)Set方法:将事件状态设为终止状态,允许一个或多个等待线程继续。该方法发送一个信号给操作系统,让处于等待的某个线程从阻塞状态转换为继续运行,即WaitOne方法的线程不在阻塞;

(3)WaitOne方法:阻塞当前线程,直到当前的等待句柄收到信号。此方法将一直使本线程处于阻塞状态直到收到信号为止,即当其他非阻塞进程调用set方法时可以继续执行。


public static void StartListening()
{
 // Data buffer for incoming data.  
 byte[] bytes = new Byte[1024];
 // Establish the local endpoint for the socket.  
 // The DNS name of the computer  
 // running the listener is "host.contoso.com".  
 //IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName());
 //IPAddress ipAddress = ipHostInfo.AddressList[0];
 IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
 IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 11000);
 // Create a TCP/IP socket.  
 Socket listener = new Socket(AddressFamily.InterNetwork,SocketType.Stream, ProtocolType.Tcp);
 // Bind the socket to the local  
 //endpoint and listen for incoming connections.  
 try
 {
  listener.Bind(localEndPoint);
  listener.Listen(100);
  while (true)
  {
   // Set the event to nonsignaled state.  
   allDone.Reset();
   // Start an asynchronous socket to listen for connections.  
   Console.WriteLine("Waiting for a connection...");
   listener.BeginAccept(new AsyncCallback(AcceptCallback),listener);
   // Wait until a connection is made before continuing.  
   allDone.WaitOne();
  }
 }
 catch (Exception e)
 {
  Console.WriteLine(e.ToString());
 }
 Console.WriteLine("nPress ENTER to continue...");
 Console.Read();
}

上述代码的逻辑为:

(1)试用了ManualRestEvent对象创建一个等待句柄,在调用BeginAccept方法前使用Rest方法允许其他线程阻塞;

(2)为了防止在连接完成之前对套接字进行读写操作,务必要在BeginAccept方法后调用WaitOne来让线程进入阻塞状态。

当有连接接入后系统会自动调用会调用回调函数,所以当代码执行到回调函数时说明连接已经成功,并在函数的第一句就调用Set方法让处于等待的线程可以继续执行。

四、实例

下面是一个实例,客户端请求连接,服务器端侦听端口,当连接建立之后,服务器发送字符串给客户端,客户端收到后并回发给服务器端。