語(yǔ)言socket編程指南Socket讓你沮喪嗎從manpages中很難得到有用的_第1頁(yè)
語(yǔ)言socket編程指南Socket讓你沮喪嗎從manpages中很難得到有用的_第2頁(yè)
語(yǔ)言socket編程指南Socket讓你沮喪嗎從manpages中很難得到有用的_第3頁(yè)
語(yǔ)言socket編程指南Socket讓你沮喪嗎從manpages中很難得到有用的_第4頁(yè)
語(yǔ)言socket編程指南Socket讓你沮喪嗎從manpages中很難得到有用的_第5頁(yè)
已閱讀5頁(yè),還剩16頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

csocket-SocketmanpagesInternet相關(guān)的程序,但是為你在調(diào)用connect()bind()的結(jié)構(gòu)而不知所措?等等…C語(yǔ)言并想這個(gè)文檔是一個(gè)指南,而不是參考書(shū)。如果你剛開(kāi)始socket編程并想找一本入門(mén)書(shū),那么你是我的讀者。但這不是一本完全的socket編程書(shū)。LinuxPCGNUgccHPUXgcc:InternetIPbind()什么是socketUnix文件描述符(filedescriptor)和其它程序通訊的方式。什么?你也許聽(tīng)到一些Unix高手(hacker)這樣“呀,Unix中的一切就是文件那個(gè)家伙也許正在說(shuō)到一個(gè)事實(shí):Unix程序在執(zhí)行的I/O的時(shí)候程序是在讀或者寫(xiě)一個(gè)文件描述符。FIFO,管道,終端,磁盤(pán)上的文件或者什么其它的東西。Unix中所有的Internet上別的程序通訊的時(shí)候,你將要使用到文件描述符。socket(),它返回套接字(socketdescriptor)send()recv()...read()和write()來(lái)進(jìn)行send()和recv()DARPAInternet地址(Internet套接字),本地節(jié)點(diǎn)的路徑名(Unix套接字),CCITTX.25(X.25套接字完全忽略)Unix機(jī)器上還有其它的。我們?cè)谶@里只講第一種:Internet套接字。Internet我可不想嚇著你。我們這里只講兩種。除了這些,"RawSockets"也是非Sockets"()"SOCK_STREAM"和用connect()。)流式套接字是可靠的雙向通訊的數(shù)據(jù)流。如果你向套接字按順序輸出“1,2有什么在使用流式套接字?你可能聽(tīng)net,不是嗎?它就使用流式套接字。你需要你所輸入的字符按順序到達(dá),不是嗎?同樣,WWW瀏覽器使用的HTTP協(xié)議也使用它們來(lái)頁(yè)面。實(shí)際上,當(dāng)你通過(guò)端口80net到一個(gè)WWW站點(diǎn),然后輸入“GETpagename”的時(shí)候,你也可以得到HTML的內(nèi)容。為什么流式套接字可以達(dá)到高質(zhì)量的數(shù)據(jù)傳輸?這是因?yàn)樗褂昧恕皞鬏斂刂茀f(xié)議(TheTransmissionControlProtocol)“TCP(RFC-793獲得詳細(xì)資料。)TCP控制你的數(shù)據(jù)按順序到達(dá)并且沒(méi)有錯(cuò)誤。TCPTCP/IPIP是指“Internet協(xié)議”(請(qǐng)參考RFC-791。)IP只是處理Internet路由而已。報(bào)協(xié)議(UserDatagramProtocol)UDP”(請(qǐng)參考RFC-768。)為什么它們是無(wú)連接的呢?主要是因?yàn)樗⒉幌罅魇教捉幼帜菢泳S持接你只要IP頭,然后發(fā)出去。無(wú)需連接。它們通常使用于傳輸包-包信息。簡(jiǎn)單的應(yīng)用程序有:tftp,bootp等等。收到了(一個(gè)“命令正確應(yīng)答”也叫“ACK”包)。如果在一定時(shí)間內(nèi)(例如5秒),發(fā)送ACKACKSOCK_DGRAM既然我剛才提到了協(xié)議層,那么現(xiàn)在是討論網(wǎng)絡(luò)究竟如何工作和一些關(guān)于SOCK_DGRAM(DataEncapsulation)的時(shí)候了!它非常非常重要。它重要性重要整個(gè)數(shù)據(jù)(TFTP頭)(UDP封裝,然后下一個(gè)IP,一直重復(fù)下去,直到硬件(物理)層(這里是以太網(wǎng))。IPUDP頭,TFTP程序再剝TFTP頭,最后得到數(shù)據(jù)?,F(xiàn)在我們終于講到聲名狼藉的網(wǎng)絡(luò)分層模型(LayeredNetworkModel)。這種網(wǎng)絡(luò)模型在描述網(wǎng)絡(luò)系統(tǒng)上相對(duì)其它模型有很多優(yōu)點(diǎn)。例如,你可以寫(xiě)一個(gè)套接字程序而不用關(guān)心數(shù)據(jù)的物理傳輸(串行口,以太網(wǎng),連接單元接口(AUI)還是其它介質(zhì)),因?yàn)榈讓拥某绦驎?huì)為你處理它們。實(shí)際的網(wǎng)絡(luò)硬件和拓?fù)鋵?duì)于程序員來(lái)說(shuō)是透明的。不說(shuō)其它廢話了,我現(xiàn)在列出整個(gè)層次模型。如果你要參加網(wǎng)絡(luò)考試,可一定要記住:應(yīng)用層(Application)(Presentation)會(huì)話層(Session)數(shù)據(jù)鏈路層(Data物理層Unix,結(jié)果是:應(yīng)用層(ApplicationLayer)(net,ftp,等等)傳輸層(Host-to-HostTransportLayer)TCPUDP)Internet層(InternetLayer)(IP和路由)網(wǎng)絡(luò)層(NetworkAccessLayer)(網(wǎng)絡(luò)層,數(shù)據(jù)鏈路層和物理層send()發(fā)送數(shù)據(jù)。對(duì)于數(shù)據(jù)報(bào)式套接字,你按sendto()Internet層,硬件完成網(wǎng)絡(luò)層。這就是現(xiàn)代科技?,F(xiàn)在結(jié)束我們的網(wǎng)絡(luò)理論速成班哦忘記告訴你關(guān)于路由的事情了。是我備談它如果你真的關(guān)心,那么參考IPRF。首先是簡(jiǎn)單的一個(gè):socket僅僅是一個(gè)常見(jiàn)的int種字節(jié)排列順序:重要的字節(jié)(有時(shí)叫"octet",即八位位組)面,或者不重要的字節(jié)在Order)NBO順序,那么你要調(diào)用函數(shù)(例如htons())(HostByteOrder)NBO我的第一個(gè)結(jié)構(gòu)(TM中)--structsockaddr.structsockaddrunsignedshortsa_family;/*地址,AF_xxx*/charsa_data[14];/*14字節(jié)協(xié)議地址*/sa_family"AF_INET"sa_data包含套接為了處理structsockaddr,程序員創(chuàng)造了一個(gè)并列的結(jié)構(gòu):structsockaddr_in("in"structsockaddr_inshortintsin_family;/*通信類(lèi)型*/unsignedshortintsin_port;/*端口*/structin_addrsin_addr;/*Internet*/unsignedcharsin_zero[8];/*sockaddr結(jié)構(gòu)的長(zhǎng)度相同sin_zero它被加入到這個(gè)結(jié)構(gòu),并且長(zhǎng)度和structsockaddr一樣)應(yīng)該使用函數(shù)bzero()或memset()來(lái)全部置零。同時(shí),這一重要的字節(jié),一個(gè)指向sockaddr_insockaddr并且代替它。這樣的話即使socket()想要的是structsockaddr*,你仍然可以使用structsockaddr_insin_familystructsockaddrsa_family一致并能夠設(shè)置為"AF_INET"。最后,sin_port和sin_addr必須是網(wǎng)絡(luò)字節(jié)順序(NetworkByteOrder)!你也許會(huì)道:"但是怎么讓整個(gè)數(shù)據(jù)結(jié)構(gòu)structin_addrsin_addr按照網(wǎng)絡(luò)字節(jié)順序呢?"structin_addr,有這樣一個(gè)聯(lián)合(unions):/*Internet(一個(gè)與歷史有關(guān)的結(jié)構(gòu)*/structin_addr{unsignedlong它曾經(jīng)是個(gè)的聯(lián)合,但是現(xiàn)在那些日子過(guò)去了。如果你"ina"是數(shù)據(jù)結(jié)構(gòu)structsockaddr_in"ina.sin_addr.s_addr"4IP地址(使用網(wǎng)絡(luò)字節(jié)順序)如果你不幸的系統(tǒng)使用的還是的聯(lián)合structin_addr你還是可以放心4字節(jié)的IP地址并且和上面我說(shuō)的一樣(這是因?yàn)槭褂昧恕?define)你能夠轉(zhuǎn)換兩種類(lèi)型:short(兩個(gè)字節(jié))和long(節(jié))。這個(gè)函數(shù)對(duì)于變量類(lèi)型unsignedshort"h""(host)""to""n""(network)""s""short":h-to-n-s,或者h(yuǎn)tons()("HosttoNetworkShort")。太簡(jiǎn)單了htons()--"HosttoNetworkShort"htonl()--"HosttoNetworkLong"ntohs()--"NetworktoHostShort"ntohl()--"NetworktoHostLong"現(xiàn)在你可能想你已經(jīng)知道它們了你也可能想“如果改變char的順序要怎么辦呢?”68000機(jī)器已經(jīng)使用了網(wǎng)htonl()IP地址。你可能是對(duì)的,但是當(dāng)你移植你的Unix世界!記?。涸谀鉻ckddrinaddr和t需要轉(zhuǎn)換為網(wǎng)絡(luò)字節(jié)順序,而n_famly需不需要呢?答案是:n_adr和in_pot分別封裝在包的IP和Py(kerel)使n_famly沒(méi)有發(fā)送到網(wǎng)絡(luò)上,它們可以是本機(jī)字節(jié)順序。IP現(xiàn)在我們很幸運(yùn),因?yàn)槲覀冇泻芏嗟暮瘮?shù)來(lái)方便地操作IP地址。沒(méi)有必要用手工計(jì)算它們,也沒(méi)有必要用"<<"操作來(lái)成長(zhǎng)整字型。首先,假設(shè)你已經(jīng)有了一個(gè)sockaddr_in結(jié)構(gòu)體ina,你有一個(gè)IP地址"0"要在其中,你就要用到函數(shù)inet_addr(),將IP地址從點(diǎn)數(shù)格式轉(zhuǎn)換成無(wú)符號(hào)長(zhǎng)整型。使用方法如下:ina.sin_addr.s_addr=注意,inet_addr()htonl()我們現(xiàn)在發(fā)現(xiàn)上面的代碼片斷不是十分完整的,因?yàn)樗鼪](méi)有錯(cuò)誤檢查。顯而易見(jiàn),當(dāng)inet_addr發(fā)生錯(cuò)誤時(shí)返回-1。記住這些二進(jìn)制數(shù)字?無(wú)符號(hào)數(shù))-1僅僅和IP地址55相符合!這可是廣播地址!大錯(cuò)特錯(cuò)!記住要先進(jìn)行錯(cuò)誤檢查。好了,現(xiàn)在你可以將IP地址轉(zhuǎn)換成長(zhǎng)整型了。有沒(méi)有其相反的方法呢?它可以將一個(gè)in_addr結(jié)構(gòu)體輸出成點(diǎn)數(shù)格式?這樣的話,你就要用到函數(shù)inet_ntoa()("ntoa"的含義是"networktoascii"),就像這樣:Pinet_ntoa(inddr作為一個(gè)參數(shù),不是長(zhǎng)整形。ne_ntoa()的固定的指針,所以每次調(diào)用inetntoa(P地址。例如:char*a1,*a;..a1inet_ntoa(ina1.sin_addr/**/a2inet_ntoa(ina2.sin_addr/*0*/printf("address1:%s\n",a1);printf("address2:address1:address2:IPstrcopy()上面就是關(guān)于這個(gè)的介紹。稍后,你將學(xué)習(xí)將一個(gè)類(lèi)似"wintehouse. 成它所對(duì)應(yīng)的IP地址(查閱服務(wù),稍后)。#include<sys/types.h>#include<sys/socket.h>int ,inttype,int但是它們的參數(shù)是什么?首先,應(yīng)該設(shè)置成"AF_INET",就象上面的數(shù)據(jù)結(jié)構(gòu)structsockaddr_in中一樣。然后,參數(shù)type告訴內(nèi)核是SOCK_STREAM類(lèi)型還是SOCK_DGRAM類(lèi)型。最后,把protocol設(shè)置為"0"。(注意:有很多種、type,我不可能一一列出了,請(qǐng)看socket()的man幫助。當(dāng)然,還有一個(gè)"更好"的方式去得到protocol。同時(shí)請(qǐng)查閱getprotobyname()的man幫助。)socket()socket-1。全局變量errno中將返回的錯(cuò)誤值。(請(qǐng)參考perror()的man幫助)一旦你有一個(gè)套接字,你可能要將套接字和機(jī)器上的一定的端口關(guān)聯(lián)起來(lái)。(如果你想用listen()來(lái)偵聽(tīng)一定端口的數(shù)據(jù),這是必要一步--MUD告訴你說(shuō)用命令"netx.y.z6969"。)connect(),那么這個(gè)步驟沒(méi)有必要。但是無(wú)論如何,請(qǐng)繼續(xù)讀下去。這里是系統(tǒng)調(diào)用bind()的大概:#include<sys/types.h>#include<sys/socket.h>intbind(intsockfd,structsockaddr*my_addr,intsockfdsocket返回的文件描述符。my_addrstructsockaddr的指針,它保存你的地址(即端口和IP地址)信息。addrlen設(shè)置為sizeof(structsockaddr)。簡(jiǎn)單得很不是嗎?#include<string.h>#include<sys/types.h>#include<sys/socket.h>#defineMYPORT3490{intstructsockaddr_insockfdsocket(AF_INETSOCK_STREAM0);**/my_addr.sin_family=AF_INET;/*hostbyteorder*/my_addr.sin_port=htons(MYPORT);/*short,networkbyteorder*/my_addr.sin_addr.s_addr=inet_addr("0");bzero(&(my_addr.sin_zero),;/*zerotherestofthestruct*//*don'tforgetyourerrorcheckingforbind():bind(sockfd,(structsockaddr*)&my_addr,sizeof(struct...這里也有要注意的幾件事情。my_addr.sin_port是網(wǎng)絡(luò)字節(jié)順序,my_addr.sin_addr.s_addrman幫助文件。在bind()中最后要說(shuō)的話是在處理自己的IP地址和/或端口的時(shí)候有些工作是可my_addr.sin_port=0;/*隨機(jī)選擇一個(gè)沒(méi)有使用的端口*/my_addr.sin_addr.s_addrINADDR_ANY/*IP通過(guò)將0賦給my_addr.sin_port,你告訴bind()自己選擇合適的端口。同樣,將my_addr.sin_addr.s_addrINADDR_ANYIP如果你一向謹(jǐn)慎,那么你可能注意到我沒(méi)有將INADDR_ANY轉(zhuǎn)換為網(wǎng)絡(luò)字節(jié)順序!這是因?yàn)槲抑纼?nèi)部的東西:INADDR_ANY0!即使你改變字節(jié)的順序,0依0INADDR_ANY12呢?你的代碼就不能工作了,那么就看下面的代碼:my_addr.sin_port=htons(0);/*隨機(jī)選擇一個(gè)沒(méi)有使用的端口*/my_addr.sin_addr.s_addrhtonl(INADDR_ANY);/*IP*/你或許不相信,上面的代碼將可以隨便移植。想,既然你所遇到的程序不會(huì)都htonlINADDR_ANY。bind()在錯(cuò)誤的時(shí)候依然是返回-1errno于1024的端都被系統(tǒng)保留!你可以選擇從1024到65535的端口(如果它們沒(méi)有被別的你要注意的另外一件小事是:有時(shí)候你根本不需要調(diào)用它。如果你使用connect()來(lái)和遠(yuǎn)connect()就可以了,它會(huì)檢查套接字是否綁定端口,如果沒(méi)有,它會(huì)自己綁定一個(gè)現(xiàn)在我們假設(shè)你是個(gè)net程序。你的用戶命令你得到套接字的文件描述符。你聽(tīng)從命令調(diào)用了socket()。下一步,你的用戶告訴你通過(guò)端口23(標(biāo)準(zhǔn)net端口)連接到connect()系統(tǒng)調(diào)用是這樣的:#include<sys/types.h>#includeintconnect(intsockfd,structsockaddr*serv_addr,intsockfd是系統(tǒng)調(diào)用socket()返回的套接字文件描述符。serv_addrIPstructsockaddr。addrlensizeof(structsockaddr)。想知道得嗎?讓我們來(lái)看個(gè)例子:#include<string.h>#include<sys/types.h>#include<sys/socket.h>#defineDEST_IP#defineDEST_PORT23{intstructsockaddr_indest_addr*目的地址sockfd=socket(AF_INET,SOCK_STREAM,0);/*錯(cuò)誤檢查*/dest_addr.sin_family=AF_INET;/*hostbyteorder*/dest_addr.sin_porthtons(DEST_PORT);*short,networkbyteorder*/dest_addr.sin_addr.s_addr=inet_addr(DEST_IP);bzero(&(dest_addr.sin_zero),;/*zerotherestofthestruct*//*don'tforgettoerrorchecktheconnect()!connect(sockfd,(structsockaddr*)&dest_addr,sizeof(struct...connect()的返回值--它在錯(cuò)誤的時(shí)候返回-1量errno。同時(shí),你可能看到,我沒(méi)有調(diào)用bind()。因?yàn)槲也辉诤醣镜氐亩?。我只關(guān)心我要去那。是換換內(nèi)容得時(shí)候了。假如你不希望與的一個(gè)地址相連,或者說(shuō),僅僅是將它踢開(kāi),那你就需要等待接入請(qǐng)求并且用各種方法處理它們。處理過(guò)程分兩步:首先,你聽(tīng)--listen(),然后,你接受--accept()(請(qǐng)看下面的內(nèi)容)。listenintlisten(intsockfd,intsockfdsocket()返回的套接字文件描述符。backlog?(accept()請(qǐng)看下面的文章)連它們的數(shù)目限制于隊(duì)列的允許。大多數(shù)系統(tǒng)的允許數(shù)目是20你也可以設(shè)置為5到10。和別的函數(shù)一樣,在發(fā)生錯(cuò)誤的時(shí)候返回-1,并設(shè)置全局錯(cuò)誤變量errno。listen()bind()/*accept()應(yīng)該在這因?yàn)樗喈?dāng)?shù)拿髁?,我將在這里不給出例子了。(在accept()那一章的代碼將更加完全。)真正麻煩的部分在accept()。accept()accept()(listen())(connect())(accept())accept()告訴它你有空閑的連接。它將返端口,新的在準(zhǔn)備發(fā)送(send())和接收(recv())數(shù)據(jù)。這就是這個(gè)過(guò)程!#includeintaccept(intsockfd,void*addr,intsockfd相當(dāng)簡(jiǎn)單,是和listen()中一樣的套接字描述符。addr是個(gè)指向局部的數(shù)據(jù)結(jié)構(gòu)sockaddr_in(你可以測(cè)定那個(gè)地址在那個(gè)端口呼叫你。在它的地址傳遞給acceptaddrlen是個(gè)局部的整形變量,設(shè)置為變addrlen同樣,在錯(cuò)誤時(shí)返回-1errno。#include<string.h>#include<sys/socket.h>#include<sys/types.h>#defineMYPORT3490/*用戶接入端口*/#defineBACKLOG10/*多少等待連接控制*/{intsockfd,new_fd;/*listenonsock_fd,newconnectiononnew_fd*/structsockaddr_inmy_addr;/*地址信息*/structsockaddr_intheir_addr;/*connector'saddressinformation*/intsin_size;sockfdsocket(AF_INETSOCK_STREAM0);/*錯(cuò)誤檢查*/my_addr.sin_family=AF_INET;/*hostbyteorder*/my_addr.sin_port=htons(MYPORT);/*short,networkbyteorder*/my_addr.sin_addr.s_addr=INADDR_ANY;/*auto-fillwithmyIP*/bzero(&(my_addr.sin_zero),;/*zerotherestofthestruct*//*don'tforgetyourerrorcheckingforthesecalls:bind(sockfd,(structsockaddr*)&my_addr,sizeof(structsockaddr));listen(sockfd,BACKLOG);sin_size=sizeof(structnew_fd=accept(sockfd,&their_addr,...注意,在系統(tǒng)調(diào)用send()和recv()中你應(yīng)該使用新的套接字描述符new_fd。如果你只想讓接進(jìn)來(lái)那么你可以使用close()去關(guān)閉原來(lái)的文件描述符sockfd來(lái)避免同一個(gè)端口的連接。send()andrecv()sendto()和recvfrom()的章節(jié)。send()intsend(intsockfd,constvoid*msg,intlen,intsockfd是你想發(fā)送數(shù)據(jù)的套接字描述符(socket()accept())msg是指向你想發(fā)送的數(shù)據(jù)的指針。lenflags0就可以了。(詳細(xì)的資料請(qǐng)看send()的manpage)。char*msg="Beejwashere!";intlen,bytes_sent;..len=bytes_sent=send(sockfd,msg,len,...send()返回實(shí)際發(fā)送的數(shù)據(jù)的字節(jié)數(shù)--send()len送完。最后要說(shuō)得就是,它在錯(cuò)誤的時(shí)候返回-1,并設(shè)置errno。recv()intrecv(intsockfd,void*buf,intlen,unsignedintsockfdbuflenflags可0。(recvmanpage。recv()返回實(shí)際讀入緩沖的數(shù)據(jù)的字節(jié)數(shù)。或者在錯(cuò)誤的時(shí)候返回-1,同時(shí)設(shè)置errno。很簡(jiǎn)單,不是嗎?Unix網(wǎng)sendto()recvfrom()既然數(shù)據(jù)報(bào)套接字不是連接到主機(jī)的,那么在我們發(fā)送一個(gè)包之前需要什么信息呢不錯(cuò),是目標(biāo)地址!的intsendto(intsockfd,constvoid*msg,intlen,unsignedintflags,conststructsockaddr*to,inttolen);send()to是個(gè)指向數(shù)structsockaddrIP地址和端口信息。tolen可以簡(jiǎn)單地sizeof(structsockaddr)send()類(lèi)似,sendto()返回實(shí)際發(fā)送的字節(jié)數(shù)(它也可能小于你想要發(fā)送的字節(jié)數(shù)!),或者在錯(cuò)誤的時(shí)候返回-1。recv()recvfrom()。recvfrom()intrecvfrom(intsockfd,void*buf,intlen,unsignedint structsockaddr*from,recv()也是一樣的。from是一個(gè)指向局部數(shù)structsockaddrIPfromlenintsizeof(structsockaddr)。函數(shù)調(diào)用返回后,fromlen保存著實(shí)際在from中的地址的長(zhǎng)度。recvfrom()-1connect()send()recv()來(lái)(send())(recv())述符了。這很簡(jiǎn)單,你可以使用一般的Unix文件描述符的close()函數(shù):它將防止套接字上的數(shù)據(jù)的讀寫(xiě)任何在另一端讀寫(xiě)套接字的企圖都將返回錯(cuò)誤信息。shutdown()定方向上的通訊或者雙向的通訊(close()一樣)關(guān)閉,你可以使用:intshutdown(intsockfd,intsockfd是你想要關(guān)閉的套接字文件描述復(fù)。how---不允許發(fā)送和接受(close()一樣shutdown()0-1(errno)如果在無(wú)連接的數(shù)據(jù)報(bào)套接字shutdown()send()recv()不能使用(記住你在數(shù)據(jù)報(bào)套接字中使用了connect后是可以使用它們的)。getpeername()告訴你在連接的流式套接字上誰(shuí)在另外一邊。函數(shù)是這樣的:#includeintgetpeername(intsockfd,structsockaddrintsockfd是連接的流式套接字的描述符。addrstructsockaddr(sockaddr_in)addrlenint型的指針,它初始化為sizeof(structsockaddr)。函數(shù)在錯(cuò)誤的時(shí)候返回-1,設(shè)置相應(yīng)的errno。inet_ntoa()gethostbyaddr()來(lái)打印或者獲得的討論已經(jīng)超出了本文的范圍,請(qǐng)參考RFC-1413以獲得的信息。)getpeername()gethostname()主機(jī)名字。然后你可以使用gethostbyname()以獲得你的機(jī)器的IP地址。#includeintgethostname(char*hostname,size_t參數(shù)很簡(jiǎn)單:hostname是一個(gè)字符數(shù)組指針,它將在函數(shù)返回時(shí)保存主機(jī)名。sizehostname數(shù)組的字節(jié)長(zhǎng)度。0,失敗時(shí)返回-1errno服務(wù)如果你不知道DNS的意思,那么我告訴你,它代表服務(wù)( NameService)。它主要的功能是:你給它一個(gè)容易的某站點(diǎn)的地址,它給你IP地址(然后你就可以使用bind(),connect(),sendto()或者其它函數(shù))。當(dāng)一個(gè)人輸入: netnet能知道它將連接(connect())到"00"。但是這是如何工作的呢?gethostbyname():#include<netdb.h>structhostent*gethostbyname(constcharstructhostentstructhostent{char*h_name;char**h_aliases;inth_addrtype;inth_length;char#defineh_addrh_addr_list[0]structhostent:h_name-h_aliases-空字節(jié)-地址的預(yù)備名稱(chēng)的指針。h_addrtype-地址類(lèi)型;AF_INET。h_length-地址的比特長(zhǎng)度。h_addr_list-零字節(jié)-h_addrh_addr_listgethostbyname()成功時(shí)返回一個(gè)指向結(jié)構(gòu)體hostent的指針,或者是個(gè)空(NULL)(errno,h_errnoherror()。但是如何使用呢?有時(shí)候(我們可以從電腦手冊(cè)中發(fā)現(xiàn)#include<stdio.h>#include<stdlib.h>#include<errno.h>#include#include<sys/types.h>#includeintmain(intargc,char{structhostentif(argc!=2){/*檢查命令行*/fprintf(stderr,"usage:getipaddress\n");}if((h=gethostbyname(argv[1]))NULL)/**/}printf("Hostname:%s\n",h-printf("IPAddress:%s\n",inet_ntoa(*((structin_addr*)h->h_addr)));return0;}gethostbyname()perror()(errno沒(méi)有使用),你應(yīng)該調(diào)用herror()。相當(dāng)簡(jiǎn)單你只是傳遞一個(gè)保存機(jī)器名的字符串(例如"whitehouse. ")給gethostbyname(),然后從返回的數(shù)據(jù)結(jié)構(gòu)structhostent中獲取信息。IP地址信息。h->h_addrchar*inet_ntoa()需要的是structin_addr。因此,我轉(zhuǎn)換h->h_addr成structin_addr*,然后得到數(shù)據(jù)。這里是個(gè)客戶--服務(wù)器的世界。在網(wǎng)絡(luò)上的所有東西都是在處理客戶進(jìn)服務(wù)器進(jìn)程的交談。舉個(gè)net的例子。當(dāng)你用net(客戶)通過(guò)23號(hào)端口登陸到主機(jī),主機(jī)上運(yùn)行的一個(gè)程序(一般叫netd,服務(wù)器)激活。它處理這個(gè)連接,顯示登陸界面,等等。2--SOCK_STREAMSOCK_DGRAM或者其它(只要它們采用相同的)。一些很好的客戶--服務(wù)器的例子有net/netd、ftp/ftpd和bootp/bootpd。每次你使用ftp的時(shí)候,在遠(yuǎn)端都有一個(gè)ftpd為你服務(wù)。一般,在服務(wù)端只有一個(gè)服務(wù)器,它采用fork()來(lái)處理多個(gè)客戶的連接?;镜某绦蚴牵悍?wù)器等待接,接受(accept())連接,然后fork()一個(gè)子進(jìn)程處理它。這是下一章我這個(gè)服務(wù)器所做的全部工作是在流式連接上發(fā)送字符串" 個(gè)程序的話,可以在一臺(tái)機(jī)器上運(yùn)行該程序,然后在另外一機(jī)器上登陸: netremotehostname3490remotehostname是該程序運(yùn)行的機(jī)器的名字。#include<stdio.h>#include<stdlib.h>#include<errno.h>#include#include<sys/types.h>#include<netinet/in.h>#include<sys/socket.h>#include<sys/wait.h>#defineMYPORT3490/*定義用戶連接端口*/#defineBACKLOG10/*多少等待連接控制*/{intsockfd,new_fd;/*listenonsock_fd,newconnectiononstructsockaddr_inmy_addr;/*myaddressinformationstructsockaddr_intheir_addr;/*connector'saddressinformation*/intsin_size;if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1){}my_addr.sin_family=AF_INET;/*hostbyteordermy_addr.sin_port=htons(MYPORT);/*short,networkbyteorder*/my_addr.sin_addr.s_addr=INADDR_ANY;/*auto-fillwithmyIP*/bzero(&(my_addr.sin_zero),;/*zerotherestofthestruct*/if(bind(sockfd,(structsockaddr*)&my_addr,sizeof(structsockaddr))==-1){}if(listen(sockfd,BACKLOG)==-1){}while(1){/*mainaccept()loopsin_size=sizeof(structif((new_fd=accept(sockfd,(structsockaddr*)&their_addr,\&sin_size))==-1){}printf("server:gotconnectionfrom%s\n",\if(!fork()){/*thisisthechildprocessif(send(new_fd," o,world!\n",14,0)==-1)}close(new_fd);/*parentdoesn'tneedthiswhile(waitpid(-1,NULL,WNOHANG)>0);/*cleanupchildprocesses}}main()函數(shù)中。如果你不喜3490端口連接到命令行中指定客戶代碼#include<stdio.h>#include<stdlib.h>#include<errno.h>#include#include<sys/types.h>#include<netinet/in.h>#include<sys/socket.h>#include<sys/wait.h>#definePORT3490/*客戶機(jī)連接主機(jī)的端口*/#defineMAXDATASIZE100/**/intmain(intargc,char*argv[]){intsockfd,structhostent*he;structsockaddr_intheir_addr;/*connector'saddressinformationif(argc!=2)fprintf(stderr,"usage:clienthostname\n");}if((he=gethostbyname(argv[1]))==NULL){/*getthehostinfo*/}if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1){}their_addr.sin_family=AF_INET;/*hostbyteorder*/their_addr.sin_port=htons(PORT);/*short,networkbyteorder*/their_addr.sin_addr=*((structin_addr*)he->h_addr);bzero(&(their_addr.sin_zero),;/*zerotherestofthestruct*/if(connect(sockfd,(structsockaddr*)&their_addr,sizeof(structsockaddr))==-1){}if((numbytes=recv(sockfd,buf,MAXDATASIZE,0))==-1){}buf[numbytes]='\0';printf("Received:%s",buf);return}connect()"Connectionrefused"信息,我不想講了,所以我給出代碼talker.c和listener.clistener4590來(lái)的數(shù)據(jù)包。talkerlistener.c:#include<stdio.h>#include<stdlib.h>#include<errno.h>#include#include<sys/types.h>#include<netinet/in.h>#include<sys/socket.h>#include<sys/wait.h>#defineMYPORT4950/*theportuserswillbesendingto*/#defineMAXBUFLEN100{intstructsockaddr_inmy_addr;/*myaddressinformationstructsockaddr_intheir_addr;/*connector'saddressinformation*/intaddr_len,numbytes;charif((sockfd=socket(AF_INET,SOCK_DGRAM,0))==-1){}my_addr.sin_family=AF_INET;/*hostbyteordermy_addr.sin_port=htons(MYPORT);/*short,networkbyteorder*/my_addr.sin_addr.s_addr=INADDR_ANY;/*auto-fillwithmyIP*/bzero(&(my_addr.sin_zero),;/*zerotherestofthestruct*/if(bind(sockfd,(structsockaddr*)&my_addr,sizeof(struct\==-1)}addr_len=sizeof(structif((numbytes=recvfrom(sockfd,buf,MAXBUFLEN,0,\(structsockaddr*)&their_addr,&addr_len))==-1){}printf("gotpacketfrom%s\n",inet_ntoa(their_addr.sin_addr));printf("packetis%dbyteslong\n",numbytes);buf[numbytes]='\0';printf("packetcontains}注意在我們的調(diào)用socket(),我們最后使用了SOCK_DGRAM。同時(shí),沒(méi)有必要去使用listen()accept()下面是talker.c:#include<stdio.h>#include<stdlib.h>#include<errno.h>#include#include<sys/types.h>#include<netinet/in.h>#include<sys/socket.h>#include<sys/wait.h>#defineMYPORT4950/*theportuserswillbesendingto*/intmain(intargc,char*argv[]){intstructsockaddr_intheir_addr;/*connector'saddressinformation*/structhostent*he;intif(argc!=3)fprintf(stderr,"usage:talkerhostnamemessage\n");}if((he=gethostbyname(argv[1]))==NULL){/*getthehostinfo*/}if((sockfd=socket(AF_INET,SOCK_DGRAM,0))==-1){}their_addr.sin_family=AF_INET;/*hostbyteorder*/their_addr.sin_port=htons(MYPORT);/*short,networkbyteordertheir_addr.sin_addr=*((structin_addr*)he->h_addr);bzero(&(their_addr.sin_zero),;/*zerotherestofthestruct*/if((numbytes=sendto(sockfd,argv[2],strlen(argv[2]),0,(structsockaddr*)&their_addr,sizeof(structsockaddr)))==-1){}printf("sent%dbytesreturn}listenertalker。觀察它,當(dāng)一個(gè)者呼叫connect()函數(shù)時(shí)并指定接受者的地址時(shí),從這點(diǎn)可以看出者只能向connect()函數(shù)指定的地址發(fā)送和接受信息。因此,你不需要使用sendto()和recvfrom(),你完send()recv()代替。,阻塞,你也許早就聽(tīng)說(shuō)了。"阻塞"是"sleep"listenerrecvfrom(),然后沒(méi)有數(shù)據(jù),因此recvfrom()說(shuō)"阻塞(block)",直到數(shù)據(jù)的到來(lái)。很多函數(shù)都利用阻塞。accept()recv*()函數(shù)阻塞。它們之所以能這樣做是因?yàn)樗鼈儽辉试S這樣做。當(dāng)你第一次調(diào)用socket()建立套接字描述符的時(shí)候,內(nèi)核就將它設(shè)置為阻塞。如

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論