Perl Socket 編程
Socket又稱"套接字",應(yīng)用程序通常通過"套接字"向網(wǎng)絡(luò)發(fā)出請求或者應(yīng)答網(wǎng)絡(luò)請求,使主機(jī)間或者一臺計算機(jī)上的進(jìn)程間可以通訊。
本章節(jié)我們?yōu)榇蠹医邮?Perl 語言中如何使用 Socket 服務(wù)。
創(chuàng)建服務(wù)端
使用 socket 函數(shù)來創(chuàng)建 socket服務(wù)。
使用 bind 函數(shù)綁定端口。
使用 listen 函數(shù)監(jiān)聽端口。
使用 accept 函數(shù)接收客戶端請求。
創(chuàng)建客戶端
使用 socket 函數(shù)來創(chuàng)建 socket 服務(wù)。
使用 connect 函數(shù)連接到 socket 服務(wù)端。
以下圖表演示了客戶端與服務(wù)端之間的通信流程:
服務(wù)端 socket 函數(shù)
socket 函數(shù)
Perl 中,我們用 socket()函數(shù)來創(chuàng)建套接字,語法格式如下:
socket( SOCKET, DOMAIN, TYPE, PROTOCOL );
參數(shù)解析:
DOMAIN 創(chuàng)建的套接字指定協(xié)議集。 例如:
AF_INET
表示IPv4網(wǎng)絡(luò)協(xié)議AF_INET6
表示IPv6AF_UNIX
表示本地套接字(使用一個文件)
TYPE 套接字類型可以根據(jù)是面向連接的還是非連接分為SOCK_STREAM或SOCK_DGRAM
PROTOCOL 應(yīng)該是 (getprotobyname('tcp'))[2]。指定實(shí)際使用的傳輸協(xié)議。
所以 socket 函數(shù)調(diào)用方式如下:
use Socket # 定義了 PF_INET 和 SOCK_STREAM socket(SOCKET,PF_INET,SOCK_STREAM,(getprotobyname('tcp'))[2]);
bind() 函數(shù)
使用 bind() 為套接字分配一個地址:
bind( SOCKET, ADDRESS );
SOCKET 一個socket的描述符。 ADDRESS 是 socket 地址 ( TCP/IP ) 包含了三個元素:
地址簇 (TCP/IP, 是 AF_INET, 在你系統(tǒng)上可能是 2)
端口號 (例如 21)
網(wǎng)絡(luò)地址 (例如 10.12.12.168)
使用socket()創(chuàng)建套接字后,只賦予其所使用的協(xié)議,并未分配地址。在接受其它主機(jī)的連接前,必須先調(diào)用bind()為套接字分配一個地址。
簡單實(shí)例如下:
use Socket # 定義了 PF_INET 和 SOCK_STREAM $port = 12345; # 監(jiān)聽的端口 $server_ip_address = "10.12.12.168"; bind( SOCKET, pack_sockaddr_in($port, inet_aton($server_ip_address))) or die "無法綁定端口! \n";
or die 在綁定地址失敗后執(zhí)行。
通過設(shè)置 setsockopt() 可選項 SO_REUSEADDR 設(shè)置端口可立即重復(fù)使用。
pack_sockaddr_in() 函數(shù)將地址轉(zhuǎn)換為二進(jìn)制格式。
listen() 函數(shù)
當(dāng)socket和一個地址綁定之后,listen()函數(shù)會開始監(jiān)聽可能的連接請求。然而,這只能在有可靠數(shù)據(jù)流保證的時候使用:
listen( SOCKET, QUEUESIZE );
SOCKET : 一個socket的描述符。
QUEUESIZE : 是 一個決定監(jiān)聽隊列大小的整數(shù),當(dāng)有一個連接請求到來,就會進(jìn)入此監(jiān)聽隊列;當(dāng)一個連接請求被accept()接受,則從監(jiān)聽隊列中移出;當(dāng)隊列滿后,新的連接請求會返回錯誤。
一旦連接被接受,返回0表示成功,錯誤返回-1。
accept() 函數(shù)
accept() 函數(shù)接受請求的socket連接。如果成功則返回壓縮形式的網(wǎng)絡(luò)地址,否則返回FALSE:
accept( NEW_SOCKET, SOCKET );
SOCKET : 一個socket的描述符。
ADDRESS : ADDRESS 是 socket 地址 ( TCP/IP ) 包含了三個元素:
地址簇 (TCP/IP, 是 AF_INET, 在你系統(tǒng)上可能是 2)
端口號 (例如 21)
網(wǎng)絡(luò)地址 (例如 10.12.12.168)
accept() 通常應(yīng)用在無限循環(huán)當(dāng)中:
while(1) { accept( NEW_SOCKET, SOCKT ); ....... }
以上實(shí)例可以實(shí)時監(jiān)聽客戶端的請求。
客戶端函數(shù)
connect() 函數(shù)
connect()系統(tǒng)調(diào)用為一個套接字設(shè)置連接,參數(shù)有文件描述符和主機(jī)地址。
connect( SOCKET, ADDRESS );
以下創(chuàng)建一個連接到服務(wù)端 socket 的實(shí)例:
$port = 21; # ftp 端口 $server_ip_address = "10.12.12.168"; connect( SOCKET, pack_sockaddr_in($port, inet_aton($server_ip_address))) or die "無法綁定端口! \n";
完整實(shí)例
接下來我們通過一個完整實(shí)例來了解下所有 socket 函數(shù)的應(yīng)用:
服務(wù)端 server.pl 代碼:
#!/usr/bin/perl -w # Filename : server.pl use strict; use Socket; # 使用端口 7890 作為默認(rèn)值 my $port = shift || 7890; my $proto = getprotobyname('tcp'); my $server = "localhost"; # 設(shè)置本地地址 # 創(chuàng)建 socket, 端口可重復(fù)使用,創(chuàng)建多個連接 socket(SOCKET, PF_INET, SOCK_STREAM, $proto) or die "無法打開 socket $!\n"; setsockopt(SOCKET, SOL_SOCKET, SO_REUSEADDR, 1) or die "無法設(shè)置 SO_REUSEADDR $!\n"; # 綁定端口并監(jiān)聽 bind( SOCKET, pack_sockaddr_in($port, inet_aton($server))) or die "無法綁定端口 $port! \n"; listen(SOCKET, 5) or die "listen: $!"; print "訪問啟動:$port\n"; # 接收請求 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 "我是來自服務(wù)端的信息"; print "Connection recieved from $name\n"; close NEW_SOCKET; }
打開一個終端,執(zhí)行以下代碼:
$ perl sever.pl 訪問啟動:7890
客戶端 client.pl 代碼:
#!/usr/bin/perl -w # Filename : client.pl use strict; use Socket; # 初始化地址與端口 my $host = shift || 'localhost'; my $port = shift || 7890; my $server = "localhost"; # 主機(jī)地址 # 創(chuàng)建 socket 并連接 socket(SOCKET,PF_INET,SOCK_STREAM,(getprotobyname('tcp'))[2]) or die "無法創(chuàng)建 socket $!\n"; connect( SOCKET, pack_sockaddr_in($port, inet_aton($server))) or die "無法連接:port $port! \n"; my $line; while ($line = <SOCKET>) { print "$line\n"; } close SOCKET or die "close: $!";
打開另外一個終端,執(zhí)行以下代碼:
$ perl client.pl 我是來自服務(wù)端的信息
更多建議: