1. 程式人生 > >C#學習筆記(1):中斷被Socket.Accept阻塞的執行緒

C#學習筆記(1):中斷被Socket.Accept阻塞的執行緒

剛剛學習C#,在編寫一個網路通訊的程式的時候,遇到了點麻煩。監聽程式碼是放在一個執行緒中,當線上程中呼叫Socket.Accept()函式時,倘若這時需要中止該執行緒,C#似乎沒有提供現成的辦法,使用了Thread.Abort()和Thread.Interrupt()函式,都沒有用。有人說用非同步Accept方法避免阻塞,可是用這種方法就得線上程中不停地輪詢Socket的狀態,會導致CPU負荷增加。還有人提出可以現在程式內部建立一個對偵聽Socket的連線,然後傳送特定的推出資料序列,當監聽程式收到這個特殊序列後就主動結束執行緒。這個方法雖然可以解決問題,但是未免複雜了些。

想來想去,突然想到如果將監聽socket關閉掉,引發socket異常,然後在監聽執行緒中捕獲這個異常不就可以中止監聽執行緒了嗎,試驗了一下,果然可以。監聽執行緒的程式碼如下:

using System;
using System.IO;
using System.Net.Sockets;
using System.Net;

public class ListenThread
{
   public void run()
   {
      Console.Write("creating listen socket ...");
      listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
      listenSocket.Bind(new IPEndPoint(IPAddress.Any, 65365));
      listenSocket.Listen(0);
      Console.Write("    done.\n");

      try
      {
         Console.Write("listening ...");
         ioSocket = listenSocket.Accept();
         Console.Write("    accepted.\n");

         Console.Write("creating I/O thread ...");
         // new Thread(new ThreadStart(this.networkIOThreadProc)).Start();
         Console.Write("    done.\n");
      }
      catch (Exception e)
      {
         Console.WriteLine("Thread aborted.");
      }
      finally
      {
         Console.WriteLine("Thread resource released.");
      }
   }

   public void stop()
   {
      if (listenSocket != null)
      {
         listenSocket.Close();
      }
   }

   private Socket listenSocket = null;
   private Socket ioSocket = null;

}

建立執行緒的程式碼如下:
      ListenThread listener = new ListenThread();
      Thread listenThread = new Thread(new ThreadStart(listener.run));
      listenThread.Start();

中止執行緒的程式碼如下:
      listener.stop();

呼叫執行緒類的stop函式之後,會將處於監聽遠端連線的listenSocket關閉掉,這時會導致引發System.Net.Sockets.SocketException,線上程程式碼中捕獲並處理這個異常就行了。這種方法實現簡單,也不會產生額外的CPU資源。