- Perl 基礎
- Perl - 首頁
- Perl - 簡介
- Perl - 環境
- Perl - 語法概述
- Perl - 資料型別
- Perl - 變數
- Perl - 標量
- Perl - 陣列
- Perl - 雜湊
- Perl - IF...ELSE
- Perl - 迴圈
- Perl - 運算子
- Perl - 日期和時間
- Perl - 子程式
- Perl - 引用
- Perl - 格式
- Perl - 檔案 I/O
- Perl - 目錄
- Perl - 錯誤處理
- Perl - 特殊變數
- Perl - 編碼規範
- Perl - 正則表示式
- Perl - 傳送郵件
- Perl 高階
- Perl - 套接字程式設計
- Perl - 面向物件
- Perl - 資料庫訪問
- Perl - CGI 程式設計
- Perl - 包和模組
- Perl - 程序管理
- Perl - 嵌入式文件
- Perl - 函式引用
- Perl 有用資源
- Perl - 問答
- Perl - 快速指南
- Perl - 有用資源
- Perl - 討論
Perl - 套接字程式設計
什麼是套接字?
套接字是 Berkeley UNIX 建立不同程序之間虛擬雙工連線的機制。後來移植到每個已知的作業系統上,從而能夠在執行不同作業系統軟體的不同地理位置的系統之間進行通訊。如果沒有套接字,系統之間的大部分網路通訊將永遠不會發生。
仔細觀察;網路上的典型計算機系統根據其上執行的各種應用程式的需要接收和傳送資訊。此資訊被路由到系統,因為為其指定了一個唯一的 IP 地址。在系統上,此資訊被提供給相關的應用程式,這些應用程式偵聽不同的埠。例如,Internet 瀏覽器偵聽埠 80 以接收來自 Web 伺服器的資訊。我們還可以編寫自定義應用程式,這些應用程式可以偵聽並在特定埠號上傳送/接收資訊。
現在,讓我們總結一下,套接字是 IP 地址和埠,使能夠透過網路傳送和接收資料。
為了解釋上面提到的套接字概念,我們將以使用 Perl 的客戶端-伺服器程式設計為例。要完成客戶端伺服器架構,我們將需要執行以下步驟:
建立伺服器
使用socket呼叫建立套接字。
使用bind呼叫將套接字繫結到埠地址。
使用listen呼叫偵聽埠地址上的套接字。
使用accept呼叫接受客戶端連線。
建立客戶端
使用socket呼叫建立套接字。
使用connect呼叫連線(套接字)到伺服器。
下圖顯示了客戶端和伺服器用於相互通訊的呼叫的完整順序:
伺服器端套接字呼叫
socket() 呼叫
socket()呼叫是建立網路連線的第一個呼叫,即建立套接字。此呼叫的語法如下:
socket( SOCKET, DOMAIN, TYPE, PROTOCOL );
上述呼叫建立一個 SOCKET,其他三個引數是整數,對於 TCP/IP 連線應具有以下值。
DOMAIN 應為 PF_INET。在您的計算機上可能是 2。
TYPE 對於 TCP/IP 連線應為 SOCK_STREAM。
PROTOCOL 應為(getprotobyname('tcp'))[2]。它是透過套接字使用的特定協議,例如 TCP。
因此,伺服器發出的 socket 函式呼叫將類似於以下內容:
use Socket # This defines PF_INET and SOCK_STREAM
socket(SOCKET,PF_INET,SOCK_STREAM,(getprotobyname('tcp'))[2]);
bind() 呼叫
由 socket() 呼叫建立的套接字在繫結到主機名和埠號之前是無用的。伺服器使用以下bind()函式指定將從中接受客戶端連線的埠。
bind( SOCKET, ADDRESS );
這裡 SOCKET 是 socket() 呼叫返回的描述符,ADDRESS 是套接字地址(對於 TCP/IP),包含三個元素:
地址族(對於 TCP/IP,即 AF_INET,在您的系統上可能是 2)。
埠號(例如 21)。
計算機的 Internet 地址(例如 10.12.12.168)。
由於 bind() 由伺服器使用,伺服器不需要知道自己的地址,因此引數列表如下所示:
use Socket # This defines PF_INET and SOCK_STREAM $port = 12345; # The unique port used by the sever to listen requests $server_ip_address = "10.12.12.168"; bind( SOCKET, pack_sockaddr_in($port, inet_aton($server_ip_address))) or die "Can't bind to port $port! \n";
or die子句非常重要,因為如果伺服器在沒有未完成連線的情況下死亡,除非您使用setsockopt()函式使用選項 SO_REUSEADDR,否則埠不會立即可重用。這裡pack_sockaddr_in()函式用於將埠和 IP 地址打包成二進位制格式。
listen() 呼叫
如果這是一個伺服器程式,則需要在指定的埠上發出對listen()的呼叫以進行偵聽,即等待傳入請求。此呼叫的語法如下:
listen( SOCKET, QUEUESIZE );
上述呼叫使用 socket() 呼叫返回的 SOCKET 描述符,QUEUESIZE 是允許同時存在的最大未完成連線請求數。
accept() 呼叫
如果這是一個伺服器程式,則需要發出對access()函式的呼叫以接受傳入連線。此呼叫的語法如下:
accept( NEW_SOCKET, SOCKET );
accept 呼叫接收 socket() 函式返回的 SOCKET 描述符,並在成功完成時,返回一個新的套接字描述符 NEW_SOCKET,用於客戶端和伺服器之間所有未來的通訊。如果 access() 呼叫失敗,則返回 FLASE,它在最初使用的 Socket 模組中定義。
通常,accept() 用於無限迴圈中。一旦一個連線到達,伺服器要麼建立一個子程序來處理它,要麼自己服務它,然後返回去偵聽更多連線。
while(1) {
accept( NEW_SOCKET, SOCKT );
.......
}
現在所有與伺服器相關的呼叫都已結束,讓我們看看客戶端將需要的呼叫。
客戶端套接字呼叫
connect() 呼叫
如果您要準備客戶端程式,那麼首先您將使用socket()呼叫建立套接字,然後您必須使用connect()呼叫連線到伺服器。您已經看到了 socket() 呼叫的語法,它將與伺服器 socket() 呼叫類似,但這是connect()呼叫的語法:
connect( SOCKET, ADDRESS );
這裡 SCOKET 是客戶端發出的 socket() 呼叫返回的套接字描述符,ADDRESS 是與bind呼叫類似的套接字地址,但它包含遠端伺服器的 IP 地址。
$port = 21; # For example, the ftp port $server_ip_address = "10.12.12.168"; connect( SOCKET, pack_sockaddr_in($port, inet_aton($server_ip_address))) or die "Can't connect to port $port! \n";
如果您成功連線到伺服器,則可以使用 SOCKET 描述符開始向伺服器傳送命令,否則您的客戶端將透過顯示錯誤訊息退出。
客戶端-伺服器示例
以下是使用 Perl 套接字實現簡單的客戶端-伺服器程式的 Perl 程式碼。這裡伺服器偵聽傳入請求,一旦建立連線,它就簡單地回覆來自伺服器的問候。客戶端讀取該訊息並在螢幕上列印。讓我們看看它是如何完成的,假設我們的伺服器和客戶端在同一臺機器上。
建立伺服器的指令碼
#!/usr/bin/perl -w
# Filename : server.pl
use strict;
use Socket;
# use port 7890 as default
my $port = shift || 7890;
my $proto = getprotobyname('tcp');
my $server = "localhost"; # Host IP running the server
# create a socket, make it reusable
socket(SOCKET, PF_INET, SOCK_STREAM, $proto)
or die "Can't open socket $!\n";
setsockopt(SOCKET, SOL_SOCKET, SO_REUSEADDR, 1)
or die "Can't set socket option to SO_REUSEADDR $!\n";
# bind to a port, then listen
bind( SOCKET, pack_sockaddr_in($port, inet_aton($server)))
or die "Can't bind to port $port! \n";
listen(SOCKET, 5) or die "listen: $!";
print "SERVER started on port $port\n";
# accepting a connection
my $client_addr;
while ($client_addr = accept(NEW_SOCKET, SOCKET)) {
# send them a message, close connection
my $name = gethostbyaddr($client_addr, AF_INET );
print NEW_SOCKET "Smile from the server";
print "Connection recieved from $name\n";
close NEW_SOCKET;
}
要在後臺模式下執行伺服器,請在 Unix 提示符下發出以下命令:
$perl sever.pl&
建立客戶端的指令碼
!/usr/bin/perl -w
# Filename : client.pl
use strict;
use Socket;
# initialize host and port
my $host = shift || 'localhost';
my $port = shift || 7890;
my $server = "localhost"; # Host IP running the server
# create the socket, connect to the port
socket(SOCKET,PF_INET,SOCK_STREAM,(getprotobyname('tcp'))[2])
or die "Can't create a socket $!\n";
connect( SOCKET, pack_sockaddr_in($port, inet_aton($server)))
or die "Can't connect to port $port! \n";
my $line;
while ($line = <SOCKET>) {
print "$line\n";
}
close SOCKET or die "close: $!";
現在讓我們在命令提示符下啟動我們的客戶端,它將連線到伺服器並讀取伺服器傳送的訊息,並在螢幕上顯示如下:
$perl client.pl Smile from the server
注意 - 如果您以點分十進位制格式提供實際的 IP 地址,則建議在客戶端和伺服器中都以相同的格式提供 IP 地址,以避免任何混淆。