注: 如果你是知道Unix套接字,然後你可以跳過介紹部分。
另一個位計算機專業術語? 讓我們看看網絡的曆史,這是一個伯克利分校UNIX的進程之間建立一個虛擬的全雙工連接的機製。這後來被移植到所有已知的操作係統能夠跨越地域位置上運行不同的操作係統,軟件係統之間的通信。如果冇有套接字,大多數的網絡係統之間的通信將永遠也不會發生的。
在仔細看看; 一個典型的計算機係統的網絡上的接收和發送信息,運行在它之上的各種應用程序所必須的。 此信息被發送到係統中,由於一個唯一的IP地址被指定給它。在係統上,此信息提供給相關的應用程序在不同的端口上偵聽。例如,一個網絡瀏覽器監聽80端口的信息。 同時,我們也可以編寫應用程序在一個特定的端口號,收聽和發送信息。
現在,讓我們總結一下,一個套接字是IP地址和端口,它們可以連接。
為了說明的套接字,我們將使用客戶端 - 服務器端編程的一個例子。為了完成一個客戶端服務器架構,我們就得通過以下步驟
建立網絡連接的第一個步驟是創建一個套接字,使用Socket()函數
socket( SOCKET, DOMAIN, TYPE, PROTOCOL ); creates a socket
套接字創建了一個SOCKET, 其他三個參數都是整數,它應該有以下值的TCP/IP連接。
因此,調用socket函數將是這樣的:
use Socket #defines PF_INET and SOCK_STREAM socket(SOCKET,PF_INET,SOCK_STREAM,(getprotobyname('tcp'))[2]);
bind( SOCKET, ADDRESS ) binds a network ADDRESS to a SOCKET.
ADDRESS 是一個套接字地址(TCP/ IP)數據包包含三個元素的字符串
正如bind()在服務器使用,並不需要知道它自己的地址,因此參數列表看起來像這樣:
$port = 12345; # the port bind( SOCKET, pack( 'Sn4x8', AF_INET, $port, "\0\0\0\0" )) or die "Can't bind to port $port! \n";
or die 子句是非常重要的 -如果一台服務器死了,冇有未完成的連接的端口不會立即可重複使用的,除非你使用這個選項SO_REUSEADDR使用setsockopt()函數。 這裡pack()函數被用來打包所有數據成二進製格式。
如果這是一個服務器程序,那麼它需要調用listen()監聽在指定的端口。
listen( SOCKET, QUEUESIZE );
上麵的調用是必須對所有服務器以及這裡QUEUESIZE是連接請求允許的最大數量。一般情況下,listen()是用來在一個無限循環。隻要一個連接到服務器處理並然後,立即去回到監聽更多的連接。
如果這是一個服務器程序,那麼它需要發出調用access()函數來接受傳入的連接。
accept( NEW_SOCKET, SOCKET );
調用accept接收socket()函數返回的套接字描述符。成功完成此調用後,將返回一個新的socket描述符。今後所有客戶端和服務器之間的通信發生的NEW_SOCKET和SOCKET是返回自己最擅長的 : listen()的一個新的連接。access() 調用失敗,則返回FLASE我們最初使用的Socket模塊中所定義的。
你會經常看到的accept()用於在一個while循環,如下所示
while(1) { accept( NEW_SOCKET, SOCKT ); ....... }
現在,所有與服務器的調用,讓我們看到的調用將被客戶端要求.
如果你要準備客戶端程序,然後使用socket()調用後,你將不得不使用另一個調用connect()連接到服務器。
connect( SOCKET, ADDRESS );這裡的地址是類似bind調用的遠程服務器的IP地址,但它包含一個套接字地址。
$port = 21; # the ftp port $server_ip_address = "10.12.12.168"; connect( SOCKET, pack( 'Sn4x8', AF_INET, $port, $server )) or die "Can't connect to port $port! \n";
如果你連接到服務器成功後,你就可以開始你的命令發送到服務器使用SOCKET 描述符。
現在讓我們把所有的東西放在一起
#!/usr/bin/perl -w # server.pl by www.gitbook.net #-------------------- use strict; use Socket; # use port 7890 as default my $port = shift || 7890; my $proto = getprotobyname('tcp'); # 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( 'Sn4x8', AF_INET, $port, "\0\0\0\0" )) 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(NET_SOCKET, SOCKET)) { # send them a message, close connection print NEW_SOCKET "Smile from the server"; close NEW_SOCKET; }
要運行該服務器在後台模式下發出Unix提示符下麵的命令
$sever.pl&
#!/usr/bin/perl -w
# client.pl
#----------------
use strict;
use Socket;
# initialize host and port
my $host = shift || 'localhost';
my $port = shift || 7890;
my $server = "10.12.12.168";
# by www.gitbook.net
# 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( 'Sn4x8', AF_INET, $port, $server ))
or die "Can't connect to port $port! \n";
my $line;
while ($line = <SOCKET>) {
print "$line\n";
}
close SOCKET or die "close: $!";