- ASP.NET本質論
- 郝冠軍
- 1658字
- 2018-12-31 19:25:13
1.2 最簡單的Web服務器
1.2.1 網絡插座Socket
在遙遠的Unix時代,為了解決傳輸層的編程問題,從4.2 BSD Unix開始,Unix提供了類似于文件操作的網絡操作方式-Socket。通過Socket,程序員可以像操作文件一樣通過打開、寫入、讀取、關閉等操作完成網絡編程。這使得網絡編程可以統(tǒng)一到文件操作之下。通過Socket幫助程序員解決網絡傳輸層的問題,而系統(tǒng)中的網絡系統(tǒng)負責處理網絡內部的復雜操作,這樣程序員就可以比較容易地編寫網絡應用程序。需要注意的是,應用層的協(xié)議需要針對網絡程序專門處理,Socket不負責應用層的協(xié)議,僅僅負責傳輸層的協(xié)議。
當然,網絡畢竟不是簡單的文件,所以,在使用Socket的時候,程序員還是需要設置一些網絡相關的細節(jié)問題參數(shù)。
當通過Socket開發(fā)網絡應用程序的時候,首先需要考慮所使用的網絡類型,主要包括以下三個方面:
1)Socket類型,使用網絡協(xié)議的類別,IPv4的類型為PF_INET。
2)數(shù)據(jù)通信的類型,常見的數(shù)據(jù)報(SOCK_DGRAM )、數(shù)據(jù)流(SOCK_STREAM)。
3)使用的網絡協(xié)議,比如:TCP協(xié)議。
在同一個網絡地址上,為了區(qū)分使用相同協(xié)議的不同應用程序,可以為不同的應用程序分配一個數(shù)字編號,這個編號稱為網絡端口號(port)。端口號是一個兩字節(jié)的整數(shù),取值范圍從0~65535。 IANA (Internet Assigned Number Authority,互聯(lián)網地址分配機構)維護了一個端口分配列表,這些端口分為三類,第一類的范圍是0~1023,稱為眾所周知的端口,由IANA進行控制和分配,由特定的網絡程序使用,例如,TCP協(xié)議使用80號端口來完成HTTP協(xié)議的傳輸。第二類的范圍是1024~49151,稱為登記端口,這些端口不由IANA控制,但是IANA維護了一個登記的列表,如果沒有在IANA登記的話,也不應該在程序中使用。但是,大多數(shù)的系統(tǒng)中,在沒有沖突的情況下,也可以由用戶程序使用。第三類的范圍是49152~65535,稱為動態(tài)或者私有端口,這些端口可以由普通用戶程序使用。
對于一個網絡應用程序來說,通過地址、協(xié)議和端口號可以唯一地確定網絡上的一個應用程序。其中地址和端口的組合稱為端點(EndPoint)。每個Socket需要綁定到一個端點上與其他端點進行通信。
在.NET中,System.Net命名空間提供了網絡編程的大多數(shù)數(shù)據(jù)類型以及常用操作,其中常用的類型如下:
□IPAddress類用來表示一個IP地址。
□IPEndPoint類用來表示一個IP地址和一個端口號的組合,稱為網絡的端點。
□System.Net.Sockets命名空間中提供了基于Socket編程的數(shù)據(jù)類型。
□Socket類封裝了Socket的操作。
常用操作如下:
□Listen:設置基于連接通信的Socket 進入監(jiān)聽狀態(tài),并設置等待隊列的長度。
□Accept:等待一個新的連接,當新連接到達的時候,返回一個針對新連接的Socket對象。通過這個新的Socket對象,可以與新連接通信。
□Receive:通過Socket接受字節(jié)數(shù)據(jù),保存到一個字節(jié)數(shù)組中,返回實際接收的字節(jié)數(shù)。
□Send:通過Socket發(fā)送預先保存在字節(jié)數(shù)組中的數(shù)據(jù)。
下面的示例代碼演示了如何通過Socket編程創(chuàng)建一個簡單的Web服務器。這個服務器通過49152 號端口提供訪問,向瀏覽器返回一個固定的靜態(tài)網頁。在這個示例中,請求的消息由瀏覽器生成,并發(fā)送到服務器,這個程序將簡單地顯示請求的消息。回應的消息由服務器程序生成,通過Socket傳輸層返回給瀏覽器。
// 取得本機的loopback網絡地址,即 127.0.0.1 IPAddress address = IPAddress.Loopback; // 創(chuàng)建可以訪問的端點,49152表示端口號,如果設置為0,表示使用一個空閑的端口號 IPEndPoint endPoint = new IPEndPoint(address, 49152); // 創(chuàng)建socket,使用IPv4地址,傳輸控制協(xié)議 TCP,雙向、可靠、基于連接的字節(jié)流 Socket socket = new Socket( AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); // 將socket 綁定到一個端點上 socket.Bind(endPoint); //設置連接隊列的長度 socket.Listen(10); Console.WriteLine("開始監(jiān)聽, 端口號:{0}.", endPoint.Port); while (true) { // 開始監(jiān)聽,這個方法會阻塞線程的執(zhí)行,直到接收到一個客戶端的連接請求 Socket client = socket.Accept(); // 輸出客戶端的地址 Console.WriteLine(client.RemoteEndPoint); // 準備讀取客戶端請求的數(shù)據(jù),讀取的數(shù)據(jù)將保存在一個數(shù)組中 byte[]buffer = new byte[4096]; // 接收數(shù)據(jù) int length = client.Receive(buffer, 4096, SocketFlags.None); // 將請求的數(shù)據(jù)翻譯為 UTF-8 System.Text.Encoding utf8 = System.Text.Encoding.UTF8; string requestString = utf8.GetString(buffer, 0, length); // 顯示請求的消息 Console.WriteLine(requestString); // 回應的狀態(tài)行 string statusLine = "HTTP/1.1 200 OK\r\n"; byte[]statusLineBytes = utf8.GetBytes(statusLine); // 準備發(fā)送到客戶端的網頁 string responseBody ="<html><head><title>From Socket Server</title></ head><body><h1>Hello,world.</h1></body></html>"; byte[]responseBodyBytes = utf8.GetBytes(responseBody); // 回應的頭部 string responseHeader = string.Format( "Content-Type: text/html; charset = UTF-8\r\nContent - Length:{0}\r\n", responseBody.Length ); byte[]responseHeaderBytes = utf8.GetBytes(responseHeader); // 向客戶端發(fā)送狀態(tài)信息 client.Send(statusLineBytes); // 向客戶端發(fā)送回應頭 client.Send(responseHeaderBytes); //頭部與內容的分隔行 client.Send(new byte[]{13, 10}); // 向客戶端發(fā)送內容部分 client.Send(responseHeaderBytes); // 斷開與客戶端的連接 client.Close(); if (Console.KeyAvailable) break; } //關閉服務器 socket.Close();
運行后,在瀏覽器的窗口中輸入服務器的地址:http://localhost.:49152/,則瀏覽器中可以看到如圖1-5所示的結果。

圖1-5 通過瀏覽器訪問自定義的Web服務器
在命令行窗口可以看到如圖1-6所示的輸出。

圖1-6 自定義Web服務器的輸出
- Mastering Concurrency in Go
- MongoDB for Java Developers
- Essential Angular
- MySQL數(shù)據(jù)庫管理與開發(fā)實踐教程 (清華電腦學堂)
- GeoServer Beginner's Guide(Second Edition)
- Mastering ServiceNow(Second Edition)
- Web Development with MongoDB and Node(Third Edition)
- Java語言程序設計教程
- Raspberry Pi Robotic Blueprints
- OpenMP核心技術指南
- AMP:Building Accelerated Mobile Pages
- 高效使用Greenplum:入門、進階與數(shù)據(jù)中臺
- Hack與HHVM權威指南
- Drupal 8 Development:Beginner's Guide(Second Edition)
- Monitoring Docker