C#網路編程初步之TCP

來源:互聯網
上載者:User

標籤:style   blog   http   io   ar   color   os   使用   sp   

原文:http://blog.csdn.net/mymonkey110/article/details/6841347

   閱讀背景:本文針對有C#的初學者而寫的,主要講解如何利用C#進行網路編程。如果你已經有一些網路編程的經驗(只需要懂得網路編程的基本常識即可),並且理解C#的基本文法,那麼這篇文章可以很快地帶你進入C#網路編程的世界。如果你的基礎不好,也不要緊,我相信這篇文章也會有你需要的內容。

網路編程基礎複習:

 

 

      圖1. TCP編程基本模型

        相信很多人看到圖1應該不會陌生,這是一個利用TCP進行通訊的經典模型圖。我想大家都應該把這張圖記在心中。在此我就不講述中每個API的意思了,百度一下,你就知道。我想說的是,難道你不覺得這麼編程很累嗎? 我們需要去調用每個API函數,然後每個判斷傳回值是多少,如果你忘記了哪個API的參數形式還得去查MSDN,這種時間花費是巨大的,尤其當你做應用程式層的快速開發時。

        圖2是利用UDP通訊時的編程基本模型,這個模型較為簡單,但是應用極為廣泛,相比TCP而言,我本人覺得利用UDP通訊是一門更為高深的技術,因為它是不需連線的,換言之,它的效率與靈活度就更高些。

 

圖2. UDP編程基本模型

        在此我補充一點,關於何時利用TCP通訊、何時利用UDP通訊的問題。他們的特性其實已經決定了他們的適用範圍。在進行大資料量、持續串連時,我們使用TCP,例如FTP協議;而在進行小規模資料、突發性高的通訊時,我們使用UDP,例如聊天程式。但是,這並不是絕對的事情。例如流媒體通訊,它是大數量、持續的通訊,但是使用的是UDP協議,為什麼呢?——因為我們不關心丟失的幀,人的肉眼是無法識別出少量的幀丟失的。那麼使用UDP通訊就可以大幅度提高效率,降低網路負載。

C#之TCP編程

  • 如何建立一個通訊端?

我們先來看看利用Winsock2是如何建立一個通訊端的:

首先,我們要載入通訊端庫,然後再建立通訊端。大致代碼如下:

  1. WORD wVersion=MAKEWORD(2,2);  
  2. WSADATA wsaData;  
  3. if(WSAStartup(wVersion,&wsaData))  
  4. {  
  5. WSACleanup();  
  6. returnFALSE;  
  7. }  
  8.    
  9. m_sock=WSASocket(AF_INET,SOCK_DGRAM,IPPROTO_UDP,NULL,0,0);  
  10. if(m_sock==INVALID_SOCKET)  
  11. {  
  12.         MessageBox("建立通訊端失敗!");  
  13.         return FALSE;  

        難道你不覺得利用Winsock2建立一個通訊端很費勁嗎?如果你在Linux環境中變成倒是可以省掉載入通訊端的部分,但是卻只能反覆的調用API,這樣也是很費時的事情。那我們再看看看利用C#是如何幫你簡化工作的。這裡我會介紹TCPClient類。

        以上是從MSDN上截取的一段話,可見我們利用TCPClient還處理與TCP通訊相關的操作。TCPClient有四個建構函式,每個建構函式的用法是有不同的。這裡我補充一個知識,那就是端地址在C#中描述。我們知道,我們用一個IP地址和一個連接埠號碼就可以表示一個端地址。在C#中我們利用IPEndPoint類來表示一個端地址,本人經常利用如下的建構函式來建立一個IPEndPoint類。

  1. IPEndPoint localEP = new IPEndPoint(IPAddress.Parse("127.0.0.1"),6666);   
這樣來表示一個端地址是不是比建立一個struct sockaddr_in的結構體來的快呢?
  • 如何綁定一個端地址?

       我們已經建立了一個端地址,也構造了通訊端(TCPClient類),那麼如何將二者綁定起來呢?也許你已經發現了,在建立TCPClient的時候我們其實就可以綁定端地址了。如果你使用的TCPClient tcp_Client=new TCPClient()的建構函式來建立的TCPClient,那麼系統會認為你沒有人為的制定端地址,而會自動幫你制定端地址,在建立用戶端的TCPClient時我們常常這樣做,因為我們不關心用戶端的端地址。如果是伺服器監聽呢?在伺服器監聽時我們會使用例外一個類,叫做TCPListener,接下來我會講到。我們可以利用TCPClient(IPEndPoint)來構造一個綁定到固定端地址的TCPClient類。例如:

  1. TcpClient tcp_Client = new TcpClient(localEP); 
  • 如何監聽通訊端?

       到現在為此我們還沒討論如何監聽一個通訊端。在傳統的socket編程中,我們建立一個通訊端,然後把它綁定到一個端地址,而後調用Listen()來監聽通訊端。而在C#中,我們利用TCPListener來幫我們完成這些工作。讓我們先來看看如何在C#監聽通訊端。

  1. IPEndPointlocalEP = new IPEndPoint(IPAddress.Parse("127.0.0.1"),6666);  
  2. TcpListenerListener = new TcpListener(localEP);  
  3. Listener.Start(10);  

        我們首先建立需要綁定的端地址,而後建立監聽類,並利用其建構函式將其綁定到端地址,然後調用Start(int number)方法來真正實施監聽。這與我們傳統的socket編程不同。以前我們都是先建立一個socket,然後再建立一個sockaddr_in的結構體。我想你應該開始感受到了C#的優勢了,它幫我們省去了很多低級、繁瑣的工作,讓我們能夠真正專註於我們的軟體架構和設計思想。

  • 如何接受用戶端串連?

接聽通訊端後面自然就是接受TCP串連了。我們利用下面一句話來完成此工作:

  1. TcpClient remoteClient =Listener.AcceptTcpClient();  

        類似於accept函數來返回一個socket,利用TCPListener類的AcceptTcpClient方法我們可以得到一個與用戶端建立了串連的TCPClient類,而由TCPClient類來處理以後與用戶端的通訊工作。我想你應該開始理解為什麼會存在TCPClient和TCPListener兩個類了。這兩個類的存在有著更加明細的區分,讓監聽和後續的通訊真正分開,讓程式員也更加容易理解和使用了。

這裡我還得補充一點:監聽是一個非阻塞的操作(Listener.Start()),而接受串連是一個阻塞操作(Listener.AcceptTcpClient)。

說了這麼多,還不如來個執行個體來的明確。接下來,我會通過一個簡單的控制台聊天程式來如何使用這些。先貼代碼吧!

伺服器端:

  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Text;  
  5. using System.Net;  
  6. using System.Net.Sockets;  
  7.    
  8. namespace Demo  
  9. {  
  10.     class Program  
  11.     {  
  12.         static void Main(string[]args)  
  13.         {  
  14.             byte[]SendBuf = Encoding.UTF8.GetBytes("Hello,Client!"); //發給用戶端的訊息;  
  15.             IPEndPointlocalEP = new IPEndPoint(IPAddress.Parse("127.0.0.1"),6666); //本地端地址  
  16.             TcpListenerListener = new TcpListener(localEP);  //建立監聽類,並綁定到指定的端地址  
  17.             Listener.Start(10);  //開始監聽                                                              
  18.             Console.WriteLine("Server is listening...");                             
  19.             TcpClientremoteClient = Listener.AcceptTcpClient();  //等待串連(阻塞)  
  20.             Console.WriteLine("Client:{0} connected!",remoteClient.Client.RemoteEndPoint.ToString()) ;//列印用戶端串連資訊;  
  21.             remoteClient.Client.Send(SendBuf);//發送歡迎資訊;  
  22.             remoteClient.Close();   //關閉串連;  
  23.         }  
  24.     }  
  25. }

用戶端:

  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Text;  
  5. using System.Net;  
  6. using System.Net.Sockets;  
  7.   
  8. namespace Demo_Client  
  9. {  
  10.     class Program  
  11.     {  
  12.         static void Main(string[] args)  
  13.         {  
  14.             byte[] RecvBuf=new byte[1024];  //申請接收緩衝;  
  15.             int RecvBytes = 0; //接收位元組數;  
  16.             string recvmsg=null; //接收訊息;  
  17.   
  18.             IPEndPoint remoteEP = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 6666);  //遠程伺服器端地址;  
  19.             TcpClient remoteServer = new TcpClient(); //建立TCPClient類來與伺服器通訊;  
  20.             remoteServer.Connect(remoteEP);  //調用connect方法串連遠端伺服器;  
  21.             Console.WriteLine("I‘m using {0}.", remoteServer.Client.LocalEndPoint);//列印自己使用的端地址;  
  22.             RecvBytes=remoteServer.Client.Receive(RecvBuf);//接受伺服器發送過來的訊息;  
  23.             recvmsg=Encoding.UTF8.GetString(RecvBuf,0,RecvBytes); //將接受到的位元組碼轉化為string類型;  
  24.             Console.WriteLine("Server says:{0}.", recvmsg);  //列印歡迎資訊;  
  25.         }  
  26.     }  
  27. }

      在C#網路編程中,我們要用到兩個名空間,分別是System.Net和System.Net.Socket。可能有人會有這樣的疑惑,幹嘛要申請一個Byte數組。我們知道,在傳統socket編程中,我們都是用char*來發送或者接受訊息的,其實char*和Byte[]是同源的。他們都是一個Byte,而使用Byte[]能更易於人們理解和轉化為其他類型。我們知道網路間傳輸的位元組流,而Byte[]剛好符合了這個思想。如果對以上類的用法不理解或者不熟悉的話,建議查看MSDN,上面講解的很詳細。

現在看看運行效果:

 

圖3 運行效果(左為伺服器,右為用戶端)

       好啦,到這裡我們C#網路編程初步之TCP基本上算告一段落了,我只講解了最為基礎的部分,僅做拋磚引玉的作用。每個類的使用千變萬化,希望你能找到最適合自己使用方法。現在你可以對比以前類似程式的代碼了,看看我前面有沒有說錯。而且,越到後來你會越來越體會到C#人性化的一面。

      後期的博文中,我會更新C#網路編程初步之UDP.本人更喜歡利用UDP來進行通訊,至於為什麼我已經說過了。以後,我會逐步寫一些網路編程的進階內容,例如非同步通訊、多線程編程,並關注程式員經常遇到的一些棘手問題,比如TCP邊界的確定等等。有機會,我也會同大家討論網路編程中常用的軟體設計思想與架構。

C#網路編程初步之TCP

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.