Perl套接字程式設計



什麼是套接字?

套接字是伯克利UNIX中的一種機制,用於在不同的程序之間建立虛擬雙向連線。後來它被移植到所有已知的作業系統上,從而實現了在執行不同作業系統軟體的不同地理位置的系統之間進行通訊。如果沒有套接字,大多數系統之間的網路通訊將永遠無法實現。

仔細觀察;網路上的典型計算機系統會根據其上執行的各種應用程式的要求接收和傳送資訊。此資訊被路由到系統,因為為此係統指定了一個唯一的IP地址。在系統上,此資訊將提供給在不同埠上偵聽的相關應用程式。例如,網際網路瀏覽器在埠80上偵聽從Web伺服器接收到的資訊。我們還可以編寫自定義應用程式,這些應用程式可以在特定埠號上偵聽和傳送/接收資訊。

現在,讓我們總結一下,套接字是一個IP地址和一個埠,它可以連線到網路上傳送和接收資料。

為了解釋上述套接字概念,我們將以使用Perl的客戶端-伺服器程式設計為例。為了完成客戶端伺服器架構,我們將必須執行以下步驟:

建立伺服器

  • 使用socket呼叫建立套接字。

  • 使用bind呼叫將套接字繫結到埠地址。

  • 使用listen呼叫偵聽埠地址上的套接字。

  • 使用accept呼叫接受客戶端連線。

建立客戶端

  • 使用socket呼叫建立套接字。

  • 使用connect呼叫連線(套接字)到伺服器。

下圖顯示了客戶端和伺服器用於相互通訊的呼叫的完整序列:

Perl Socket

伺服器端套接字呼叫

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)

  • 計算機的網際網路地址(例如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()呼叫失敗,則返回我們在初始階段使用的Socket模組中定義的FLASE。

通常,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套接字的簡單客戶端-伺服器程式的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地址,以避免任何混淆。

perl_function_references.htm
廣告
© . All rights reserved.