使用PERL SOCKET API首先需要載入SOCKET模塊。
use Socket;
======================================================================
socket(文件句柄,AF_INET,數(shù)據(jù)類型,協(xié)議類型);
#建立套接字
文件句柄隨便找個詞就可以了。
AF_INET為域類型,也可以寫為PF_INET。
數(shù)據(jù)類型,通常用有兩種:SOCK_STREAM、SOCK_DGRAM。
協(xié)議類型,可以用協(xié)議號代替,EGP---8、HMP---20、ICMP---1、
RAW---255、RDP---27、RVD---66、TCP---6、UDP---17、XNS-IDP---22、
其他---22、ALL---0;也可以用getprotobyname()函數(shù)作此參數(shù)。
例子:socket(SOCK,AF_INET,SOCK_STREAM,getprotobyname('tcp'));
語柄為SOCK,套接字以TCP方式傳輸。
socket(SS,AF_INET,SOCK_DGRAM,17);
語柄為SS,套接字以UDP方式傳輸。
=======================================================================
connect(文件句柄,sockaddr_in結(jié)構(gòu)體);
#連接主機
-----------------------------------------------
sockaddr_in結(jié)構(gòu)體:
$address=inet_aton(地址);
$port=端口號;
$result=sockaddr_in($port,$address);
#上面的$result就是sockaddr_in結(jié)構(gòu)體,實例:
$address=inet_aton(127.0.0.1);
$port=80;
$result=sockaddr_in($port,$address);
-----------------------------------------------
例子:connect(SOCK,$result);
=======================================================================
bind(套接字,sockaddr_in結(jié)構(gòu)體);
#綁定服務(wù)器主機地址與端口(用于服務(wù)端)
例子:bind(SOCK,$result);
=======================================================================
listen(套接字,等待連接最大隊列數(shù));
#設(shè)置端口狀態(tài)為監(jiān)聽(用于服務(wù)端)
例子:listen(SOCK,10);
=======================================================================
accept(遠程套接字,服務(wù)端監(jiān)聽套接字)
#接收遠程數(shù)據(jù)請求,建立連接(用于服務(wù)端)
例子:accept(SESSION,SOCK);
=======================================================================
close(文件句柄);
或
close 文件句柄;
#關(guān)閉套接字
例子:close(SOCK);
close SS;
●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●
說說TCP的網(wǎng)絡(luò)活動順序:
=======================================================================
Client(客戶端):
建立套接字socket()->連接到目標主機connect()->打開autoflush模式autoflush()->
I/O操作->關(guān)閉套接字close()
Server(服務(wù)器):
建立套接字socket()->綁定服務(wù)器地址與端口bind()->設(shè)置監(jiān)聽狀態(tài)listen()->接受遠程套接字accept()->
打開autoflush模式autoflush()->I/O操作->關(guān)閉套接字close()
●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●
◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎
PERL SOCKET API編程實例:
附:I/O操作暫時只使用print()與<>符號。
=======================================================================
#!usr/bin/perl
#客戶端
use IO::Handle; #掛起IO::Handle
use Socket; #調(diào)用SOCKET
$port=80; #連接遠程主機的80端口
$host='localhost'; #使用環(huán)回地址
$packhost=inet_aton($host); #壓縮IP地址
$address=sockaddr_in($port,$packhost); #壓成sockaddr_in格式
socket(CLIENT,AF_INET,SOCK_STREAM,6); #套接字為CLIENT,使用TCP協(xié)議
connect(CLIENT,$address); #連接
CLIENT->autoflush(1); #開啟AUTOFLUSH模式
$msg_in= #INPUT
print "IN:$msg_in/n"; #OUTPUT
close CLIENT; #關(guān)閉套接字
exit 1; #退出程序
=======================================================================
#!usr/bin/perl
#服務(wù)端
use IO::Handle; #掛起IO::Handle
use Socket; #調(diào)用SOCKET
$port=80; #綁定的服務(wù)器主機端口為80
$address=sockaddr_in($port,INADDR_ANY); #壓成sockaddr_in格式,使用INADDR_ANY通配符
socket(SERVER,AF_INET,SOCK_STREAM,getprotobyname('tcp')); #套接字為SERVER,使用TCP協(xié)議
bind(SERVER,$address); #綁定
listen(SERVER,10); #設(shè)置監(jiān)聽狀態(tài)
while(1){ #進入I/O交換循環(huán)體
next unless (accept(CLIENT,SERVER));
CLIENT->autoflush(1);
print CLIENT "WHAT DO YOU WANT?/n";
close CLIENT;}
close SERVER; #關(guān)閉套接字
exit 1; #退出程序
=======================================================================
實例注解:
1)TCP的client與server代碼中有一行'SOCK->autoflush(1);',正常情況下下面的I/O代碼是會先進入緩存,
再輸出的,但加了上面的代碼就可以跳過這一步直接輸出了。此代碼需要預(yù)先加載IO::Handle。
2)INADDR_ANY通配符的值在Socket模塊中已經(jīng)定義了,其值為本地網(wǎng)絡(luò)適配的所有網(wǎng)絡(luò)接口(包括環(huán)回地址、
廣播地址、多播地址等)。
◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎
頭有點痛,寫到這里,下回介紹send()與recv()........:P
[日記文]'send()' and 'recv'[perl_sock 2]
writer:demonalex
email:demonalex_at_dark2s.org
附接上文的某些內(nèi)容,最后使用的兩個C/S程序中的數(shù)據(jù)交換部分使用了PERL I/O,
現(xiàn)在介紹一下PERL語言分配給套接字的‘原裝’網(wǎng)絡(luò)數(shù)據(jù)交換函數(shù):send()、recv()。
(這兩個函數(shù)對UDP協(xié)議的作用很大,但對TCP來說其實只能說是等于syswrite()、sysread()。)
======================================================================
字節(jié)變量=send(套接字,傳送數(shù)據(jù)變量,標志參數(shù));
send()函數(shù)用于在套接字進程中發(fā)送數(shù)據(jù)。
send()返回的值是儲存所發(fā)送的字節(jié)大小值的變量;傳送數(shù)據(jù)變量為傳輸數(shù)據(jù)的內(nèi)容;
標志參數(shù)為0(默認值就可以了)。
例子:$bytes=send(SOCK,$data,0);
======================================================================
地址變量=recv(套接字,接收后的數(shù)據(jù)所儲存的變量,接收數(shù)據(jù)的長度,標志參數(shù));
recv()函數(shù)用于在套接字進程中接收數(shù)據(jù)。
recv()返回遠程主機的地址變量;第二個參數(shù)為接收后的數(shù)據(jù)所儲存的變量;第三個
參數(shù)為所接收數(shù)據(jù)的長度;標志參數(shù)同樣為默認值0就可以了。
例子:$address=recv(SOCK,$buffer,$length,0);
======================================================================
實驗1
#!usr/bin/perl
#客戶端
use IO::Handle;
use Socket;
$port=80;
$host='localhost';
$packhost=inet_aton($host);
$address=sockaddr_in($port,$packhost);
socket(CLIENT,AF_INET,SOCK_STREAM,6);
connect(CLIENT,$address);
CLIENT->autoflush(1);
recv(CLIENT,$msg_in,length($msg_in),0);
print "IN:$msg_in/n";
close CLIENT;
exit 1;
=======================================================================
#!usr/bin/perl
#服務(wù)端
use IO::Handle;
use Socket;
$port=80;
$host='localhost';
$packhost=inet_aton($host);
$address=sockaddr_in($port,$packhost);
socket(SERVER,AF_INET,SOCK_STREAM,getprotobyname('tcp'));
bind(SERVER,$address);
listen(SERVER,10);
while(1){
next unless (accept(CLIENT,SERVER));
CLIENT->autoflush(1);
$msg_out="WHAT DO YOU WANT?/n";
send(CLIENT,$msg_out,0);
close CLIENT;}
close SERVER;
exit 1;
[日記文]udp of perl socket[perl_sock 3]
writer:demonalex
email:demonalex_at_dark2s.org
繼續(xù)上文談到的send()與recv(),這次談一下它們在udp socket中的應(yīng)用以及如果使用
perl socket API來調(diào)用UDP。
先看看在UDP中的send()、recv()應(yīng)用:
==========================================================================
字節(jié)變量=send(套接字,傳送數(shù)據(jù)變量,標志參數(shù),發(fā)送地址);
send()函數(shù)用于在套接字進程中發(fā)送數(shù)據(jù)。
send()返回的值是儲存所發(fā)送的字節(jié)大小值的變量;傳送數(shù)據(jù)變量為傳輸數(shù)據(jù)的內(nèi)容;
標志參數(shù)為0(默認值就可以了);send()在udp中就多了最后一個參數(shù),‘發(fā)送地址’,
此地址的數(shù)據(jù)形式為sockaddr_in格式,表示把第二參數(shù)‘傳送數(shù)據(jù)變量’發(fā)送到此地址中。
例子:$bytes=send(SOCK,$data,0,$address);
樓上例子中的$address為sockaddr_in格式。
==========================================================================
地址變量=recv(套接字,接收后的數(shù)據(jù)所儲存的變量,接收數(shù)據(jù)的長度,標志參數(shù));
recv()函數(shù)用于在套接字進程中接收數(shù)據(jù)。
recv()返回遠程主機的地址變量;第二個參數(shù)為接收后的數(shù)據(jù)所儲存的變量;第三個
參數(shù)為所接收數(shù)據(jù)的長度;標志參數(shù)同樣為默認值0就可以了。
例子:$address=recv(SOCK,$buffer,$length,0);
==========================================================================
從樓上的講解可以知道,在UDP調(diào)用中send()比TCP調(diào)用時多了一個參數(shù),而recv()與在TCP調(diào)用時的
使用方法完全一致。
------------------------------------------------------------------------
UDP網(wǎng)絡(luò)活動順序:
Client(客戶端):
建立套接字socket()->發(fā)送數(shù)據(jù)send()->接受數(shù)據(jù)recv()->關(guān)閉套接字close()
Server(服務(wù)端):
建立套接字socket()->綁定地址bind()->接受數(shù)據(jù)recv()->發(fā)送數(shù)據(jù)send()->關(guān)閉套接字close()
------------------------------------------------------------------------
從樓上的流程不難發(fā)現(xiàn)UDP中的客戶端與服務(wù)端的不同之處有兩點:1)服務(wù)端在建立套接字后多添了一個
綁定bind()程序,用于使客戶端能分辨出服務(wù)端的網(wǎng)絡(luò)地址與端口;2)在send()與recv()步驟上順序倒過
來了。
〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓
最后可以看看例子,琢磨琢磨:
━━━━━━━━━━━━━━━━━━━━━━━━━━━
#!use/bin/perl -w
#udp client
use Socket; #導(dǎo)入Socket庫
$host=$ARGV[0]; #第一參數(shù)為主機變量
$port=$ARGV[1]; #第二參數(shù)為端口變量
$packhost=inet_aton($host); #壓縮主機地址
$address=sockaddr_in($port,$packhost); #壓為sockaddr_in模式
socket(CLIENT,AF_INET,SOCK_DGRAM,17); #建立UDP套接字
send(CLIENT,"hi,body!/n",0,$address); #向套接字發(fā)送字符串變量
recv(CLIENT,$buff,100,0); #接收數(shù)據(jù)
print"$buff/n"; #把接收后的數(shù)據(jù)打入STDOUT
close CLIENT; #關(guān)閉套接字
exit 1; #退出程序
¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
#!use/bin/perl -w
#udp server
use Socket; #導(dǎo)入Socket庫
$localhost=sockaddr_in(4000,INADDR_ANY);#壓入sockaddr_in模式,使用了全局本地壓縮地址INADDR_ANY保留字
socket(SERVER,AF_INET,SOCK_DGRAM,17); #建立UDP套接字
bind(SERVER,$localhost); #綁定套接字
while(1){ #進入服務(wù)器循環(huán)體
next unless $client=recv(SERVER,$buff,100,0); #如果接收到數(shù)據(jù)就把數(shù)據(jù)壓入$buff,保留遠程地址在$client
chop($buff); #減去$buff最后的輸入符號
print "$buff/n"; #在$buff變量打入STDOUT
send(SERVER,"$buff/n",0,$client); #把$buff發(fā)送給客戶端
}
close SERVER; #關(guān)閉套接字
exit 1; #退出程序
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[日記文]Summary[perl_sock 4]
writer:demonalex
email:demonalex_at_dark2s.org
此文為前三篇文章的總結(jié)文。
tcp的服務(wù)端I/O結(jié)構(gòu)體:
-----------------------------------------------
while(1){
next unless (accept(CLIENT,SERVER));
CLIENT->autoflush(1);
print CLIENT "WHAT DO YOU WANT?/n";
close CLIENT;}
-----------------------------------------------
udp的服務(wù)端I/O結(jié)構(gòu)體:
-----------------------------------------------
while(1){
next unless $client=recv(SERVER,$buff,100,0);
chop($buff);
print "$buff/n";
send(SERVER,"$buff/n",0,$client);
}
-----------------------------------------------
從上面的實例可以看出SERVER的I/O體都是循環(huán)體,有一特定條件進行循環(huán)
(我們這里用了死循環(huán)while(1)),為了就是使服務(wù)端能不停的在監(jiān)聽。
TCP I/O的特征就是在accept()中生成一個客戶端的套接字,所有I/O操作都
在此套接字中進行,當(dāng)I/O完成后,先把客戶端的套接字關(guān)閉,最后才在程序
的末端部分關(guān)閉服務(wù)端的套接字。
UDP I/O的特征就是recv()部分,由于在介紹UDP的那篇文中的實例為通過UDP
把輸入的數(shù)據(jù)返回到客戶端的程序,在服務(wù)端中的下一步就應(yīng)該調(diào)用send()了,
在send()中的最后一個參數(shù)為sockaddr_in形式地址,又因為在UDP中不能調(diào)用
accept(),所以無法得知對方的對象在哪里,只能通過recv()的返回值。recv()
的返回值剛好為對方發(fā)送數(shù)據(jù)的sockaddr_in形式地址。
聯(lián)系客服