Perl - 第二十一章 | Perl Socket 編程
Socket又稱”套接字”,應用程序通常通過”套接字”向網路發出請求或者應答網路請求,使主機間或者一台計算機上的進程間可以通訊。
創建服務端
- 使用 socket 函數來創建 socket服務。
- 使用 bind 函數綁定端口。
- 使用 listen 函數監聽端口。
- 使用 accept 函數接收客戶端請求。
創建客戶端
- 使用 socket 函數來創建 socket 服務。
- 使用 connect 函數連接到 socket 服務端。
下圖顯示了客戶端和服務器用於相互通信的調用的完整序列:
服務端 socket 函數
socket 函數
Perl 中,我們用 socket()函數來創建套接字,語法格式如下:
1 | socket( SOCKET, DOMAIN, TYPE, PROTOCOL ); |
參數解析:
- DOMAIN:創建的套接字指定協議集。例如:
AF_INET
:表示IPv4網路協議AF_INET6
:表示IPv6AF_UNIX
:表示本地套接字(使用一個文件)
- TYPE:套接字類型可以根據是面向連接的還是非連接分為SOCK_STREAM或SOCK_DGRAM
- PROTOCOL:應該是 (getprotobyname(‘tcp’))[2]。指定實際使用的傳輸協議。
所以 socket 函數調用方式如下:
1 | use Socket # 定義了 PF_INET 和 SOCK_STREAM |
bind() 函數
使用 bind() 為套接字分配一個地址:
1 | bind( SOCKET, ADDRESS ); |
SOCKET 一個socket的描述符。 ADDRESS 是 socket 地址 ( TCP/IP ) 包含了三個元素:
- 地址族(對於 TCP/IP,即 AF_INET,在你的系統上可能為 2)。
- 端口號(例如 21)。
- 計算機的 Internet 地址(例如 10.12.12.168)。
使用socket()創建套接字後,只賦予其所使用的協議,並未分配地址。在接受其它主機的連接前,必須先調用bind()為套接字分配一個地址。
簡單範例如下:
1 | use Socket # 定義了 PF_INET 和 SOCK_STREAM |
or die在綁定地址失敗後執行。
通過設置 setsockopt() 可選項 SO_REUSEADDR 設置端口可立即重複使用。
pack_sockaddr_in()函數將地址轉換為二進制格式。
listen() 函數
當socket和一個地址綁定之後,listen()函數會開始監聽可能的連接請求。然而,這只能在有可靠資料流保證的時候使用:
1 | listen( SOCKET, QUEUESIZE ); |
SOCKET : 一個socket的描述符。
QUEUESIZE : 是一個決定監聽隊列大小的整數,當有一個連接請求到來,就會進入此監聽隊列;當一個連接請求被accept()接受,則從監聽隊列中移出;當隊列滿後,新的連接請求會返回錯誤。
一旦連接被接受,返回0表示成功,錯誤返回-1。
accept() 函數
accept() 函數接受請求的socket連接。如果成功則返回壓縮形式的網路地址,否則返回FALSE:
1 | accept( NEW_SOCKET, SOCKET ); |
SOCKET : 一個socket的描述符。
ADDRESS : ADDRESS 是 socket 地址 ( TCP/IP ) 包含了三個元素:
- 地址族(對於 TCP/IP,即 AF_INET,在你的系統上可能為 2)。
- 端口號(例如 21)。
- 計算機的 Internet 地址(例如 10.12.12.168)。
accept() 通常應用在無限循環當中:
1 | while(1) { |
以上範例可以實時監聽客戶端的請求。
客戶端函數
connect() 函數
connect()系統調用為一個套接字設置連接,參數有文件描述符和主機地址。
1 | connect( SOCKET, ADDRESS ); |
以下創建一個連接到服務端 socket 的範例:
1 | $port = 21; # ftp 端口 |
完整範例
接下來我們通過一個完整範例來了解下所有 socket 函數的應用:
- 服務端 server.pl 程式碼:
1 | #!/usr/bin/perl -w |
打開一個終端,執行以下程式碼:
1 | perl sever.pl |
- 客戶端 client.pl 程式碼:
1 | #!/usr/bin/perl -w |
打開另外一個終端,執行以下程式碼:
1 | perl client.pl |