VisualC#2005中編寫Socket網(wǎng)絡(luò)程序

字號:

在網(wǎng)絡(luò)環(huán)境下,我們最感興趣的兩個命名空間是System.net和System.Net.Sockets。System.Net命名空間通常與較高程的操作有關(guān),例如download或upload,試用HTTP和其他協(xié)議進(jìn)行Web請求等等,而System.Net.Sockets命名空間所包含的類通常與較低程的操作有關(guān)。如果要直接使用Sockets或者TCP/IP之類的協(xié)議,這個命名空間的類是非常有用的。
    在.Net中,System.Net.Sockets 命名空間為需要嚴(yán)密控制網(wǎng)絡(luò)訪問的開發(fā)人員提供了 Windows Sockets (Winsock) 接口的托管實現(xiàn)。System.Net 命名空間中的所有其他網(wǎng)絡(luò)訪問類都建立在該套接字Socket實現(xiàn)之上,如TCPClient、TCPListener 和 UDPClient 類封裝有關(guān)創(chuàng)建到 Internet 的 TCP 和 UDP 連接的詳細(xì)信息;NetworkStream類則提供用于網(wǎng)絡(luò)訪問的基礎(chǔ)數(shù)據(jù)流等,常見的許多Internet服務(wù)都可以見到Socket的蹤影,如Telnet、Http、Email、Echo等,這些服務(wù)盡管通訊協(xié)議Protocol的定義不同,但是其基礎(chǔ)的傳輸都是采用的Socket。
    其實,Socket可以象流Stream一樣被視為一個數(shù)據(jù)通道,這個通道架設(shè)在應(yīng)用程序端(客戶端)和遠(yuǎn)程服務(wù)器端之間,而后,數(shù)據(jù)的讀?。ń邮眨┖蛯懭耄òl(fā)送)均針對這個通道來進(jìn)行。
    可見,在應(yīng)用程序端或者服務(wù)器端創(chuàng)建了Socket對象之后,就可以使用Send/SentTo方法將數(shù)據(jù)發(fā)送到連接的Socket,或者使用Receive/ReceiveFrom方法接收來自連接Socket的數(shù)據(jù)。
    針對Socket編程,.NET 框架的 Socket 類是 Winsock32 API 提供的套接字服務(wù)的托管代碼版本。其中為實現(xiàn)網(wǎng)絡(luò)編程提供了大量的方法,大多數(shù)情況下,Socket 類方法只是將數(shù)據(jù)封送到它們的本機 Win32 副本中并處理任何必要的安全檢查。如果你熟悉Winsock API函數(shù),那么用Socket類編寫網(wǎng)絡(luò)程序會非常容易,當(dāng)然,如果你不曾接觸過,也不會太困難,跟隨下面的解說,你會發(fā)覺使用Socket類開發(fā)windows 網(wǎng)絡(luò)應(yīng)用程序原來有規(guī)可尋,它們在大多數(shù)情況下遵循大致相同的步驟。
    在使用之前,你需要首先創(chuàng)建Socket對象的實例,這可以通過Socket類的構(gòu)造方法來實現(xiàn):
    public Socket(AddressFamily addressFamily,SocketType socketType,ProtocolType protocolType);
    其中,addressFamily 參數(shù)指定 Socket 使用的尋址方案,socketType 參數(shù)指定 Socket 的類型,protocolType 參數(shù)指定 Socket 使用的協(xié)議。
    下面的示例語句創(chuàng)建一個 Socket,它可用于在基于 TCP/IP 的網(wǎng)絡(luò)(如 Internet)上通訊。
    Socket temp = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    若要使用 UDP 而不是 TCP,需要更改協(xié)議類型,如下面的示例所示:
    Socket temp = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
    一旦創(chuàng)建 Socket,在客戶端,你將可以通過Connect方法連接到指定的服務(wù)器,并通過Send/SendTo方法向遠(yuǎn)程服務(wù)器發(fā)送數(shù)據(jù),而后可以通過Receive/ReceiveFrom從服務(wù)端接收數(shù)據(jù);而在服務(wù)器端,你需要使用Bind方法綁定所指定的接口使Socket與一個本地終結(jié)點相聯(lián),并通過Listen方法偵聽該接口上的請求,當(dāng)偵聽到用戶端的連接時,調(diào)用Accept完成連接的操作,創(chuàng)建新的Socket以處理傳入的連接請求。使用完 Socket 后,記住使用 Shutdown 方法禁用 Socket,并使用 Close 方法關(guān)閉 Socket。
    可以看出,以上許多方法包含EndPoint類型的參數(shù),在Internet中,TCP/IP 使用一個網(wǎng)絡(luò)地址和一個服務(wù)端口號來標(biāo)識設(shè)備。網(wǎng)絡(luò)地址標(biāo)識網(wǎng)絡(luò)上的特定設(shè)備;端口號標(biāo)識要連接到的該設(shè)備上的特定服務(wù)。網(wǎng)絡(luò)地址和服務(wù)端口的組合稱為終結(jié)點,在 .NET 框架中正是由 EndPoint 類表示這個終結(jié)點,它提供表示網(wǎng)絡(luò)資源或服務(wù)的抽象,用以標(biāo)志網(wǎng)絡(luò)地址等信息。.Net同時也為每個受支持的地址族定義了 EndPoint 的子代;對于 IP 地址族,該類為 IPEndPoint。IPEndPoint 類包含應(yīng)用程序連接到主機上的服務(wù)所需的主機和端口信息,通過組合服務(wù)的主機IP地址和端口號,IPEndPoint 類形成到服務(wù)的連接點。
    用到IPEndPoint類的時候就不可避免地涉及到計算機IP地址,System.Net命名空間中有兩種類可以得到IP地址實例:
    IPAddress類:IPAddress 類包含計算機在 IP 網(wǎng)絡(luò)上的地址。其Parse方法可將 IP 地址字符串轉(zhuǎn)換為 IPAddress 實例。下面的語句創(chuàng)建一個 IPAddress 實例:
    IPAddress myIP = IPAddress.Parse("192.168.0.1");
    Dns 類:向使用 TCP/IP Internet 服務(wù)的應(yīng)用程序提供域名服務(wù)。其Resolve 方法查詢 DNS 服務(wù)器以將用戶友好的域名(如"host.mydomain.com")映射到數(shù)字形式的 Internet 地址(如 192.168.0.1)。Resolve方法 返回一個 IPHostEnty 實例,該實例包含所請求名稱的地址和別名的列表。大多數(shù)情況下,可以使用 AddressList 數(shù)組中返回的第一個地址。下面的代碼獲取一個 IPAddress 實例,該實例包含服務(wù)器 host.mydomain.com 的 IP 地址。
    IPHostEntry ipHostInfo = Dns.Resolve("host.mydomain.com ");
    IPAddress ipAddress = ipHostInfo.AddressList[0];
    你也可以使用GetHostName方法得到IPHostEntry實例:
    IPHosntEntry hostInfo=Dns.GetHostByName("host.mydomain.com ")
    在使用以上方法時,你將可能需要處理以下幾種異常:
    SocketException異常:訪問Socket時操作系統(tǒng)發(fā)生錯誤引發(fā)
    ArgumentNullException異常:參數(shù)為空引用引發(fā)
    ObjectDisposedException異常:Socket已經(jīng)關(guān)閉引發(fā)
    在掌握上面得知識后,下面的代碼將該服務(wù)器主機( host.mydomain.com的 IP 地址與端口號組合,以便為連接創(chuàng)建遠(yuǎn)程終結(jié)點:
    IPEndPoint ipe = new IPEndPoint(ipAddress,11000);
    確定了遠(yuǎn)程設(shè)備的地址并選擇了用于連接的端口后,應(yīng)用程序可以嘗試建立與遠(yuǎn)程設(shè)備的連接。下面的示例使用現(xiàn)有的 IPEndPoint 實例與遠(yuǎn)程設(shè)備連接,并捕獲可能引發(fā)的異常:
    try
    {
    temp.Connect(ipe);//嘗試連接
    }
    //處理參數(shù)為空引用異常
    catch(ArgumentNullException ae)
    {
    Console.WriteLine("ArgumentNullException : {0}", ae.ToString());
    }
    //處理操作系統(tǒng)異常
    catch(SocketException se)
    {
    Console.WriteLine("SocketException : {0}", se.ToString());
    }
    需要知道的是:Socket 類支持兩種基本模式:同步和異步。其區(qū)別在于:在同步模式中,對執(zhí)行網(wǎng)絡(luò)操作的函數(shù)(如 Send 和 Receive)的調(diào)用一直等到操作完成后才將控制返回給調(diào)用程序。在異步模式中,這些調(diào)用立即返回。