C#2.0 Socket通訊端編程之執行個體初探 200

來源:互聯網
上載者:User

標籤:綁定   開頭   str   大致   線程   種類   另一個   重要   bsp   

 首先從原理上解釋一下採用Socket介面的網路通訊,這裡以最常用的C/S模式作為範例,首先,服務端有一個進程(或多個進程)在指定的連接埠等待客戶來串連,服務程式等待客戶的串連資訊,一旦串連上之後,就可以按設計的資料交換方法和格式進行資料轉送。用戶端在需要的時刻發出向服務端的串連請求。這裡為了便於理解,提到了一些調用及其大致的功能。使用socket調用後,僅產生了一個可以使用的socket描述符,這時還不能進行通訊,還要使用其他的調用,以使得socket所指的結構中使用的資訊被填寫完。

  在使用TCP協議時,一般服務端進程先使用socket調用得到一個描述符,然後使用bind調用將一個名字與socket描述符串連起來,對於Internet域就是將Internet地址聯編到socket。之後,服務端使用listen調用指出等待服務要求隊列的長度。然後就可以使用accept調用等待用戶端發起串連,一般是阻塞等待串連,一旦有用戶端發出串連,accept返回客戶的地址資訊,並返回一個新的socket描述符,該描述符與原先的socket有相同的特性,這時服務端就可以使用這個新的socket進行讀寫操作了。一般服務端可能在accept返回後建立一個新的進程進行與客戶的通訊,父進程則再到accept調用處等待另一個串連。用戶端進程一般先使用socket調用得到一個socket描述符,然後使用connect向指定的伺服器上的指定連接埠發起串連,一旦串連成功返回,就說明已經建立了與伺服器的串連,這時就可以通過socket描述符進行讀寫操作了。

  .NetFrameWork為Socket通訊提供了System.Net.Socket命名空間,在這個命名空間裡面有以下幾個常用的重要類分別是:

  ·Socket類 這個低層的類用於管理串連,WebRequest,TcpClient和UdpClient在內部使用這個類。

  ·NetworkStream類 這個類是從Stream派生出來的,它表示來自網路的資料流

  ·TcpClient類 允許建立和使用TCP串連

  ·TcpListener類 允許監聽傳入的TCP串連請求

  ·UdpClient類 用於UDP客戶建立串連(UDP是另外一種TCP協議,但沒有得到廣泛的使用,主要用於本網)

  下面我們來看一個基於Socket的雙機通訊代碼的C#版本

  首先建立Socket對象的執行個體,這可以通過Socket類的構造方法來實現:

public Socket(AddressFamily addressFamily,SocketType socketType,ProtocolType protocolType);

  其中,addressFamily 參數指定 Socket 使用的定址方案,socketType 參數指定 Socket 的類型,protocolType 參數指定 Socket 使用的協議。

  下面的樣本語句建立一個 Socket,它可用於在基於 TCP/IP 的網路(如 Internet)上通訊。

Socket temp = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

  若要使用 UDP 而不是 TCP,需要更改協議類型,如下面的樣本所示: 

Socket temp = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);

  一旦建立 Socket,在用戶端,你將可以通過Connect方法串連到指定的伺服器(你可以在Connect方法前Bind連接埠,就是以指定的連接埠發起串連,如果不事先Bind連接埠號碼的話,系統會預設在1024到5000隨機綁定一個連接埠號碼),並通過Send方法向遠程伺服器發送資料,而後可以通過Receive從服務端接收資料;而在伺服器端,你需要使用Bind方法綁定所指定的介面使Socket與一個本地終結點相聯,並通過Listen方法偵聽該介面上的請求,當偵聽到使用者端的串連時,調用Accept完成串連的操作,建立新的Socket以處理傳入的串連請求。使用完 Socket 後,使用 Close 方法關閉 Socket。 

  可以看出,以上許多方法包含EndPoint類型的參數,在Internet中,TCP/IP 使用一個網路地址和一個服務連接埠號碼來唯一標識裝置。網路地址標識網路上的特定裝置;連接埠號碼標識要串連到的該裝置上的特定服務。網路地址和服務連接埠的組合稱為終結點,在 .NET 架構中正是由 EndPoint 類表示這個終結點,它提供表示網路資源或服務的抽象,用以標誌網路地址等資訊。.Net同時也為每個受支援的地址族定義了 EndPoint 的子代;對於 IP 位址族,該類為 IPEndPoint。IPEndPoint 類包含應用程式串連到主機上的服務所需的主機和連接埠資訊,通過組合服務的主機IP地址和連接埠號碼,IPEndPoint 類形成到服務的連接點。

 

    用到IPEndPoint類的時候就不可避免地涉及到電腦IP地址,System.Net命名空間中有兩種類可以得到IP地址執行個體: 

  ·IPAddress類:IPAddress 類包含電腦在 IP 網路上的地址。其Parse方法可將 IP 位址字串轉換為 IPAddress 執行個體。下面的語句建立一個 IPAddress 執行個體: 

IPAddress myIP = IPAddress.Parse("192.168.0.1");

  需要知道的是:Socket 類支援兩種基本模式:同步和非同步。其區別在於:在同步模式中,按塊傳輸,對執行網路操作的函數(如 Send 和 Receive)的調用一直等到所有內容傳送操作完成後才將控制返回給調用程式。在非同步模式中,是按位傳輸,需要指定發送的開始和結束。同步模式是最常用的模式,我們這裡的例子也是使用同步模式。

  下面看一個完整的例子,client向server發送一段測試字串,server接收並顯示出來,給予client成功響應。

//client端
using System;
using System.Text;
using System.IO;
using System.Net;
using System.Net.Sockets;
namespace socketsample
{
 class Class1
 {
  static void Main()
  {
   try
   {
    int port = 2000;
    string host = "127.0.0.1";
    IPAddress ip = IPAddress.Parse(host);
    IPEndPoint ipe = new IPEndPoint(ip, port);//把ip和連接埠轉化為IPEndPoint執行個體
    Socket c = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//建立一個Socket
    Console.WriteLine("Conneting...");
    c.Connect(ipe);//串連到伺服器
    string sendStr = "hello!This is a socket test";
    byte[] bs = Encoding.ASCII.GetBytes(sendStr);
    Console.WriteLine("Send Message");
    c.Send(bs, bs.Length, 0);//發送測試資訊
    string recvStr = "";
    byte[] recvBytes = new byte[1024];
    int bytes;
    bytes = c.Receive(recvBytes, recvBytes.Length, 0);//從伺服器端接受返回資訊
    recvStr += Encoding.ASCII.GetString(recvBytes, 0, bytes);
    Console.WriteLine("Client Get Message:{0}", recvStr);//顯示伺服器返回資訊
    c.Close();
   }
   catch (ArgumentNullException e)
   {
    Console.WriteLine("ArgumentNullException: {0}", e);
   }
   catch (SocketException e)
   {
    Console.WriteLine("SocketException: {0}", e);
   }
   Console.WriteLine("Press Enter to Exit");
   Console.ReadLine();
  }
 }

//server端
using System;
using System.Text;
using System.IO;
using System.Net;
using System.Net.Sockets;
namespace Project1
{
 class Class2
 {
  static void Main()
  {
   try
   {
    int port = 2000;
    string host = "127.0.0.1";
    IPAddress ip = IPAddress.Parse(host);
    IPEndPoint ipe = new IPEndPoint(ip, port);
    Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//建立一個Socket類
    s.Bind(ipe);//綁定2000連接埠
    s.Listen(0);//開始監聽
    Console.WriteLine("Wait for connect");
    Socket temp = s.Accept();//為建立串連建立新的Socket。
    Console.WriteLine("Get a connect");
    string recvStr = "";
    byte[] recvBytes = new byte[1024];
    int bytes;
    bytes = temp.Receive(recvBytes, recvBytes.Length, 0);//從用戶端接受資訊
    recvStr += Encoding.ASCII.GetString(recvBytes, 0, bytes);
    Console.WriteLine("Server Get Message:{0}",recvStr);//把用戶端傳來的資訊顯示出來
    string sendStr = "Ok!Client Send Message Sucessful!";
    byte[] bs = Encoding.ASCII.GetBytes(sendStr);
    temp.Send(bs, bs.Length, 0);//返回用戶端成功資訊
    temp.Close();
    s.Close();
   }
   catch (ArgumentNullException e)
   {
    Console.WriteLine("ArgumentNullException: {0}", e);
   }
   catch (SocketException e)
   {
    Console.WriteLine("SocketException: {0}", e);
   }
   Console.WriteLine("Press Enter to Exit");
   Console.ReadLine();
  }
 }
}

  上面的例子是用的Socket類,System.Net.Socket命名空間還提供了兩個抽象進階類TCPClient和UDPClient和用於通訊流處理的NetWorkStream,讓我們看下例子

  用戶端

TcpClient tcpClient=new TcpCLient(主機IP,連接埠號碼);
NetworkStream ns=tcp.Client.GetStream();

  服務端

TcpListener tcpListener=new TcpListener(監聽連接埠);
tcpListener.Start();
TcpClient tcpClient=tcpListener.AcceptTcpClient();
NetworkStream ns=tcpClient.GetStream();

  服務端用TcpListener監聽,然後把串連的對象執行個體化為一個TcpClient,調用TcpClient.GetStream()方法,返回網路流執行個體化為一個NetworlStream流,下面就是用流的方法進行Send,Receive

  如果是UdpClient的話,就直接UdpClient執行個體化,然後調用UdpClient的Send和Receive方法,需要注意的事,UdpClient沒有返回網路流的方法,就是說沒有GetStream方法,所以無法流化,而且使用Udp通訊的時候,不要伺服器監聽。

  現在我們大致瞭解了.Net Socket通訊的流程,下面我們來作一個稍微複雜點的程式,一個廣播式的C/S聊天程式。

  用戶端設計需要一個1個ListBox,用於顯示聊天內容,一個TextBox輸入你要說的話,一個Button發送留言,一個Button建立串連。

  點擊建立串連的Button後出來一個對話方塊,提示輸入串連伺服器的IP,連接埠,和你的暱稱,啟動一個接受線程,負責接受從伺服器傳來的資訊並顯示在ListBox上面。

  伺服器端2個Button,一個啟動服務,一個T掉已建立串連的用戶端,一個ListBox顯示串連上的用戶端的Ip和連接埠。

  比較重要的地方是字串編碼的問題,需要先把需要傳送的字串按照UTF8編碼,然後接受的時候再還原成為GB2312,不然中文顯示會是亂碼。

  還有一個就是接收線程,我這裡簡單寫成一個While(ture)迴圈,不斷判斷是否有資訊流入,有就接收,並顯示在ListBox上,這裡有問題,在.Net2.0裡面,交錯線程修改表單空間屬性的時候會引發一個異常,不可以直接修改,需要定義一個委託來修改。 

  當用戶端需要中斷連線的時候,比如點擊表單右上方的XX,就需要定義一個this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Closing);(.Net2.0是FormClosing系統事件),在Closing()函數裡面,發送Close字元給服務端,伺服器判斷迴圈判斷所有的串連上的用戶端傳來的資訊,如果是以Close開頭,斷開與其的串連。看到這裡,讀者就會問了,如果我在聊天視窗輸入Close是不是也中斷連線呢?不是的,在聊天視窗輸入的資訊傳給伺服器的時候開頭都要加上Ip資訊和暱稱,所以不會衝突。

 

 

C#2.0 Socket通訊端編程之執行個體初探 200

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.