Ruby提供了兩個層級訪問網路的服務,在底層你可以訪問作業系統,它可以讓你實現用戶端和伺服器為連線導向和無連線協定的基本通訊端支援。
Ruby 統一支援應用程的網路通訊協定,如FTP、HTTP等。
不管是高層的還是底層的。ruby提供了一些基本類,讓你可以使用TCP,UDP,SOCKS等很多協議互動,而不必拘泥在網路層。這些類也提供了輔助類,讓你可以輕鬆的對伺服器進行讀寫。
接下來就讓我們來學習如何進行 Ruby Socket 編程
什麼是 Sockets
應用程式層通過傳輸層進行資料通訊時,TCP和UDP會遇到同時為多個應用程式進程提供並發服務的問題。多個TCP串連或多個應用程式進程可能需要 通過同一個TCP協議連接埠傳輸資料。為了區別不同的應用程式進程和串連,許多電腦作業系統為應用程式與TCP/IP協議互動提供了稱為通訊端 (Socket)的介面,區分不同應用程式進程間的網路通訊和串連。
產生通訊端,主要有3個參數:通訊的目的IP地址、使用的傳輸 層協議(TCP或UDP)和使用的連接埠號碼。Socket原意是"插座"。通過將這3個參數結合起來,與一個"插座"Socket綁定,應用程式層就可以和傳輸 層通過通訊端介面,區分來自不同應用程式進程或網路連接的通訊,實現資料轉送的並發服務。
Sockets 詞彙解析:
簡單的用戶端
以下我們通過給定的主機和連接埠編寫了一個簡單的用戶端執行個體,Ruby TCPSocket 類提供了 open 方法來開啟一個 socke。
TCPSocket.open(hosname, port ) 開啟一個 TCP 串連。
一旦你開啟一個 Socket 串連,你可以像 IO 對象一樣讀取它,完成後,你需要像關閉檔案一樣關閉該串連。
以下執行個體示範了如何串連到一個指定的主機,並從 socket 中讀取資料,最後關閉socket:
require 'socket' # Sockets 是標準庫 hostname = 'localhost'port = 2000 s = TCPSocket.open(hostname, port) while line = s.gets # 從 socket 中讀取每行資料 puts line.chop # 列印到終端ends.close # 關閉 socket
簡單的服務
Ruby 中可以使用 TCPServer 類來寫個簡單的服務。TCPServer 對象是 TCPSocket 的工廠對象。
現在我們使用 TCPServer.open(hostname, port) 來建立一個 TCPServer 對象。
接下來調用 TCPServer 的 accept 方法,該方法會等到一個用戶端串連到指定的連接埠,然後返回一個的TCPSocket對象,表示串連到該用戶端。
require 'socket' # 擷取socket標準庫 server = TCPServer.open(2000) # Socket 監聽連接埠為 2000loop { # 永久運行服務 client = server.accept # 等待用戶端串連 client.puts(Time.now.ctime) # 發送時間到用戶端 client.puts "Closing the connection. Bye!" client.close # 關閉用戶端串連}
現在,在伺服器上運行以上代碼,查看效果。
多用戶端TCP服務
互連網上,大多服務都有大量的用戶端串連。
Ruby的Thread類可以很容易地建立多線程服務,一個線程執行用戶端的串連,而主線程在等待更多的串連。
require 'socket' # 擷取socket標準庫 server = TCPServer.open(2000) # Socket 監聽連接埠為 2000loop { # 永久運行服務 Thread.start(server.accept) do |client| client.puts(Time.now.ctime) # 發送時間到用戶端 client.puts "Closing the connection. Bye!" client.close # 關閉用戶端串連 end}
在這個例子中,socket永久運行,而當server.accept接收到用戶端的串連時,一個新的線程被建立並立即開始處理請求。而主程式立即迴圈回,並等待新的串連。
微小的Web瀏覽器
我們可以使用socket庫來實現任何的 網際網路通訊協定 (IP)。以下代碼展示了如何擷取網頁的內容:
require 'socket' host = 'www.ziqiangxuetang.com' # web伺服器port = 80 # 預設 HTTP 連接埠path = "/index.htm" # 想要擷取的檔案地址 # 這是個 HTTP 要求request = "GET #{path} HTTP/1.0\r\n\r\n" socket = TCPSocket.open(host,port) # 串連伺服器socket.print(request) # 發送請求response = socket.read # 讀取完整的響應# Split response at first blank line into headers and bodyheaders,body = response.split("\r\n\r\n", 2)print body # 輸出結果
要實現一個類似 web 的用戶端,你可以使用為 HTTP 預先構建的庫如Net::HTTP。
以下代碼與先前代碼是等效的:
require 'net/http' # 我們需要的庫host = 'www.ziqiangxuetang.com' # 網頁伺服器path = '/index.htm' # 我們想要的檔案 http = Net::HTTP.new(host) # 建立串連headers, body = http.get(path) # 請求檔案if headers.code == "200" # 檢測狀態代碼 print body else puts "#{headers.code} #{headers.message}"end