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