參數含義如下: SOC_VARIABLE是用於建立套接的控制代碼,相當於c裡面的sockid號;DOMAIN_FLAG叫域標記,在C裡相當於af--address family,地址族。地址族和域是一個概念,其實就是平常所說的域。UNIX支援的域類型有 AF-UNIX; UNIX內部地址 AF-INET; TCP/IP地址 AF-NS; Xerox NS地址 AF-APPLETALK; Apple的Appletalk地址 而dos/windows支援的域地址族只有AF-INET.所以大部分的socket編程都只用到它。 connectType(c裡的type)就是前面所說的三種socket類型。num相當於c裡面的protocol那大家一看就明白了這是協議號,用來指定SOCKET請求所希望的協議,這個參數不一定起作用,當前兩個參數可以確定協議時可以取值為零。 所以,一個完整的PERL的建立socket如下 socket(THESCK,AF-INET,SOCKET_STREAM,getprotocolbyname('tcp')); #c語言: int sockid; # sockid = socket(AF-INET,SOCKET_STREAM,0); 第二步了:bind()--綁定到本地地址。 第一步socket()調用只是指定了相關五元組的協議元。其他四元需要別的調用來補充。socket的建立可以認為建立了一個名字空間(地址族),但他沒有被命名。bind()將通訊端地址與本機建立的通訊端控制代碼(c裡面的通訊端號)綁定,即將名字賦予通訊端(控制代碼),以指定本地半相關。按照標準的socket來說(在UNIX世界裡所謂編程的"標準介面"就和說"c的編程介面"沒啥區別),通訊端地址是一個描述socket地址的資料結構。其中描述TCP/IP協議地址(AF_INET)的結構為: struct sockaddr_in{ short sin_family; //AF_INET u_short sin_port; //16位連接埠號碼,網路位元組順序 struct in_addr sin_addr; //32位IP地址,網路位元組順序 char sin_zero[8]; //保留 } 其他的結構還有 sockaddr_ns,sockaddr_un等,是用在其他協議地址的。基本上我們用不到。於是一個標準綁定為: bind(SOCKET sockid,struct * localaddr_name,int addrlen); //sockid是一個未命名通訊端的socket號 //localaddr_name是用來命名sockid的指向sockaddr_in結構的指標 //addrlen是localaddr_name的位元組長度 使用perl的bind()時先要調用inet_aton('localhost');或函數 INADDR_ANY 取得ip地址字串,然後調用 $localaddr_port = sockaddr_in($port,inet_aton('localhost')); #$port是連接埠號碼 或者是 $localaddr_port = sockaddr_in($port,INADDR_ANY); 獲得TCP/IP的地址,最後bind(SERVER,$localaddr_port); 完成綁定!在這裡不用指定$localaddr_port的位元組長度,這就是perl的好處。 這兩個系統調用用於完成一個全相關的建立,其中connect()用於建立串連。accept()使伺服器等待來自某客戶進程的實際串連。其調用格式如下 connect(SOCKET sockid,struct sockaddr* destaddr,int addrlen); //sockid是欲建立串連的本地socket號 //destaddr是一個指向對方socket地址(信宿地址)結構的指標 //addrlen是對方socket地址長度 perl語言的connect()調用格式為: connect(SOC_VARIABLE,NAME_VARIABLE) 具體的調用過程如下 $remoteaddr_port = sockaddr_in($port,inet_aton('abc.efg.com')); connect(CLIENT,$remoteaddr_port); #半相關三元組(協議,遠地地址,遠地連接埠號碼)。 可以發現connect()和bind()調用如出一轍,只是SERVER換成CLIENT,local換成remote,沒錯,他們的道理是一樣的,作用是互補的。他們各自建立了伺服器和客戶機方面的半相關。這時就要accept()來摻和一下一個完整的網間進程通訊的全相關就可以建立啦!(其實標準connect()還可以用於不需連線的socket調用。但這個用法比較左道,常把人搞暈點,所以就不說了) 標準accept()調用: SOCKET newsock = accept(SOCKET sockid,struct sockaddr* clientaddr,int addlen) //sockid ,伺服器本地的socket號 //clientaddr ,指向客戶socket結構的指標。它的初始值為空白 //addlen ,客戶socket結構的位元組長度,它的初始值為0 //newsock ,accept()的傳回值,為一個新的socket號,可用於伺服器 //處理並發請求。伺服器fork一個子伺服器處理序,利用此socket號回 //答accept()所接收的客戶請求 可以看出,accept()是連線導向的伺服器端的調用。他還將用戶端的socket地址及其位元組長度放在clientaddr和addlen以便為其他不需連線的調用指定信宿地址。但是,那些比較靈活但沒有原則的無串連用法在perl裡是沒有的,perl的用法認為socket必須是連線導向的,請看perl裡的accept(): accept(NEW_SOC_VARIABLE,CURRENT_SOC_VARIABLE); 可以看到accept()從當前的socket控制代碼上串連出一個用戶端到新的socket控制代碼。而它的傳回值用戶端的地址(信宿地址)。其實串連一旦建立,服務方無須知道信宿地址,只要向套口裡灌輸位元流就行了。這樣做的好處是使協議對於應用程式更加透明,易於理解。 在調用accept()之前還應該先調用listen(),listen()的作用是偵聽連接埠,接收串連。如果不調用listen()的話,accept()將無法從當前socket"接"回與用戶端的串連。標準listen(): listen(sockid,quelen); //socket號,伺服器願意從它上面接收請求 //quelen,請求隊列長度,listen()以此限制排隊請求的個數 perl的listen(): listen(SOC_VARIABLE,num);#和C語言的版本很像哦 SOC_VARIABLE是socket控制代碼,num是請求隊列長度. 到這裡為止,一個串連的五元組都齊了。 |