Ruby Socket 程式設計

Ruby Socket 程式設計

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 詞彙解析:

選項描述
domain指明所使用的協議族,通常為 PF_INET, PF_UNIX, PF_X25, 等等。
type指定socket的型別:SOCK_STREAM 或SOCK_DGRAM,Socket介面還定義了原始Socket(SOCK_RAW),允許程式使用低層協議
protocol通常賦值0。
hostname網路介面的識別符號:
  • 字串, 可以是主機名或IP地址
  • 字串 "<broadcast>", 指定 INADDR_BROADCAST 地址。
  • 0 長度的字串, 指定INADDR_ANY
  • 一個整數,解釋為主機位元組順序的二進位制地址。
portport是埠的編號,每個伺服器都會監聽客戶端連線的一個或多個埠號,一個埠號可以是 Fixnum 的埠號, 包含了伺服器名和埠。

簡單的客戶端

以下我們通過給定的主機和埠編寫了一個簡單的客戶端例項,Ruby TCPSocket 類提供了 open 方法來開啟一個 socket。

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 # 列印到終端 end s.close # 關閉 socket

簡單的服務

Ruby 中可以使用 TCPServer 類來寫個簡單的服務。TCPServer 物件是 TCPSocket 的工廠物件。

現在我們使用 TCPServer.open(hostname, port) 來建立一個 TCPServer 物件。

接下來呼叫 TCPServer 的 accept 方法,該方法會等到一個客戶端連線到指定的埠,然後返回一個的TCPSocket物件,表示連線到該客戶端。

例項

require 'socket' # 獲取socket標準庫 server = TCPServer.open(2000) # Socket 監聽埠為 2000 loop { # 永久執行服務 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 監聽埠為 2000 loop { # 永久執行服務 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庫來實現任何的 Internet 協議。以下程式碼展示瞭如何獲取網頁的內容:

例項

require 'socket' host = 'www.w3cschool.cc' # 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 body headers,body = response.split("\r\n\r\n", 2) print body # 輸出結果

要實現一個類似 web 的客戶端,你可以使用為 HTTP 預先構建的庫如Net::HTTP。

以下程式碼與先前程式碼是等效的:

例項

require 'net/http' # 我們需要的庫 host = 'www.w3cschool.cc' # web 伺服器 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

以上我們只是簡單的為大家介紹 Ruby 中socket的應用,更多文件請檢視:Ruby Socket 庫和類方法