Visual C#中P2P應用程式的實現

iDotNetSpace發表於2009-02-04
一.前言

  P2P,即英文Peer-to-Peer的縮寫,中譯為對等互聯或點對點技術。講到P2P,人們就會想起Napster,Napster讓人們認識到了P2P技術的威力,P2P技術也就通過Napster進入了大多數使用者的視野,Napster的音樂檔案交換功能是P2P的一個主要應用。P2P技術可以讓使用者可以直接連線到其他使用者的計算機,進行檔案共享與交換。同時P2P在深度搜尋、分佈計算、協同工作等方面也大有用途。

  簡單地說,P2P就是一種用於不同PC使用者之間,不經過中繼裝置直接交換資料或服務的技術,它允許Internet使用者直接使用對方的檔案。每個人可以直接連線到其他使用者的計算機,並進行檔案的交換,而不需要連線到伺服器上再進行瀏覽與下載。因為消除了中間環節,P2P技術使得網路上的溝通變得更容易、更直接。P2P改變了Internet現在的以大網站為中心的狀態、重返"非中心化",並把權力交還給使用者。從某種意義上講,P2P體現了Internet的本質。在網路尚未發展成為現在的Web之前,網民就是利用所謂的"佈告板"等渠道彼此直接交換資訊和檔案。

  目前Internet的儲存模式是"內容位於中心",而P2P技術的運用將使Internet上的內容向邊緣移動。這將帶來以下改變:首先,客戶不再需要將檔案上傳到伺服器,而只需要使用P2P與其他計算機進行共享;其次,使用P2P技術的計算機不需要固定的IP地址和永久的Internet連線,這使得佔有極大比例的撥號上網使用者也可以享受P2P帶來的變革。

  理解P2P技術方面的最好方法是仔細觀察並理解一個實際的P2P應用程式。C#作為微軟.Net戰略的重要棋子,對網路程式設計提供了很好的支援和優化。本文就通過一個程式,向大家介紹一下C#下的P2P程式設計的方法和實現機理。本文的這個程式雖然不是很有用,但卻很直觀地給出了P2P(點對點)程式設計以及套介面程式設計的一些基本知識和概念。它是建立在TcpListener以及TcpClient這兩個類基礎上的,除外還有相應的輸入和輸出控制。實現的原理也比較簡單,但是用到了P2P技術重返"非中心化"的基本原則。簡言之,用這個程式可以在網路中傳送、接受資訊,任何一臺計算機既可以作為伺服器端,又可以作為客戶端。程式共用到了四個類:一個Listener類(用來監聽新的連線)、一個Sender類(用來傳送資訊)、一個Inputhandler類(用來控制輸入)、一個Initialize類(用來完成初始化工作)。下面,我先給大家介紹一下這四個類,最後再給出程式的具體實現方法。

  二.基本類介紹

  1.Listener類:

  Listener類是用來監聽新的連線。當它的一個物件被建立並開啟後,該物件就開始不斷監聽來自網路中的連線請求。一旦有了一個連線請求,該物件就設法建立連線並取得它的位元組流進而轉化成字串顯示在控制檯中。當一個連線結束後,該物件就繼續進行監聽來自網路中的連線請求。

程式碼以及註釋如下:

namespace P2PTest{
  using System; using System.Net.Sockets;
  using System.Threading; public class Listener
  {
    private Thread th;
    private TcpListener tcpl;
    public bool listenerRun = true;//listenerRun為true,表示可以接受連線請求,false則為結束程式
    public Listener()//建構函式
    {
      th = new Thread(new ThreadStart(Listen));//新建一個用於監聽的執行緒
      th.Start();//開啟新執行緒
    }
    public void Stop(){
      tcpl.Stop();
      th.Abort();//終止執行緒
    }
    private void Listen(){
      try
      {
        tcpl = new TcpListener(5656);//在5656埠新建一個TcpListener物件
        tcpl.Start();
        Console.WriteLine("started listening..");
        while(listenerRun)//開始監聽
        {
          Socket s = tcpl.AcceptSocket();
          string remote = s.RemoteEndPoint.ToString();
          Byte[] stream = new Byte[80];
          int i=s.Receive(stream);//接受連線請求的位元組流
          string msg = "" + System.Text.Encoding.UTF8.GetString(stream);
          Console.WriteLine(msg);//在控制檯顯示字串
        }
      }
      catch(System.Security.SecurityException)
      {
        Console.WriteLine("firewall says no no to application - application cries..");
      }
      catch(Exception)
      {
        Console.WriteLine("stoped listening..");
      }
    }
  }

  對Listen()函式的補充說明:

  這個函式是Listener類的核心部分。該函式首先被建構函式呼叫。只要布林值listenerRun為true,我們就可以在埠5656建立並開始一個Tcp監聽物件TcpListener進行監聽網路中的連線請求,而一旦listenerRun被置為false,則表示程式結束了。在迴圈體內部,我們先接受一個連線,用s.RemoteEndPoint獲得它的IP地址並獲得其位元組流。根據獲得的位元組流,我們用UTF8編碼將它轉化為字串。最後,我們就在控制檯中顯示獲得的字串。

  對於catch語句,第一個塊捕獲一個可能由防火牆引起的例外。因為對於防火牆而言,它可能認為這是一個特洛依木馬或是儒蟲病毒什麼的,所以就會拒絕通過。解決辦法就是重新配置防火牆。第二個塊用於捕獲一般的例外,比如當我們呼叫了stop()函式後,我們銷燬了TcpListener物件,那就自然不可能再進行監聽了。

  2.Sender類:

  Sender類就一個函式,所以是相當簡單的。

程式碼以及註釋如下:

namespace P2PTest {
  using System;
  using System.IO;
  using System.Net.Sockets;
  public class Sender
  {
    public void Send(string[] aInput)
    {
      string stream = "";  //獲得要傳送的資訊
      for(int i=2; i {
        stream += aInput[i] + " ";
      }
      try
      {
        TcpClient tcpc = new TcpClient(aInput[1], 5656);  //在5656埠新建一個TcpClient物件
        NetworkStream tcpStream = tcpc.GetStream();
        StreamWriter reqStreamW = new StreamWriter(tcpStream);
        reqStreamW.Write(stream);
        reqStreamW.Flush();//傳送資訊
        tcpStream.Close();
        tcpc.Close();
      }
      catch(Exception)
      {
        Console.WriteLine("connection refused by target computer");
      }
    }  
  }
}

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/12639172/viewspace-545262/,如需轉載,請註明出處,否則將追究法律責任。

相關文章