面向連接的套接字通信-socket編程_第1頁
面向連接的套接字通信-socket編程_第2頁
已閱讀5頁,還剩25頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡(jiǎn)介

1、面向連接的套接字通信面向連接的套接字通信工作流程為了實(shí)現(xiàn)服務(wù)器與客戶機(jī)的通信,服務(wù)器和客戶機(jī)都必須建立套接字。服務(wù)器與客戶機(jī)的工作原理可以用下面的過程來描述。(1) 服務(wù)器先用socket函數(shù)來建立一個(gè)套接字,用這個(gè)套接字完成通信的監(jiān)聽。(2) 用bind函數(shù)來綁定一個(gè)端口號(hào)和IP地址。因?yàn)楸镜赜?jì)算機(jī)可能有多個(gè)網(wǎng)址和IP,每一個(gè)IP和端口有多個(gè)端口。需要指定一個(gè)IP和端口進(jìn)行監(jiān)聽。(3) 服務(wù)器調(diào)用listen函數(shù),使服務(wù)器的這個(gè)端口和IP處于監(jiān)聽狀態(tài),等待客戶機(jī)的連接。(4) 客戶機(jī)用socket函數(shù)建立一個(gè)套接字,設(shè)定遠(yuǎn)程IP和端口。(5) 客戶機(jī)調(diào)用connect函數(shù)連接遠(yuǎn)程計(jì)算機(jī)指定的

2、端口。(6) 服務(wù)器用accept函數(shù)來接受遠(yuǎn)程計(jì)算機(jī)的連接,建立起與客戶機(jī)之間的通信。(7) 建立連接以后,客戶機(jī)用write函數(shù)向socket中寫入數(shù)據(jù)。也可以用read函數(shù)讀取服務(wù)器發(fā)送來的數(shù)據(jù)。(8) 服務(wù)器用read函數(shù)讀取客戶機(jī)發(fā)送來的數(shù)據(jù),也可以用write函數(shù)來發(fā)送數(shù)據(jù)。(9) 完成通信以后,用close函數(shù)關(guān)閉socket連接??蛻魴C(jī)與服務(wù)器建立面向連接的套接字進(jìn)行通信,請(qǐng)求與響應(yīng)過程可用圖來表示Illi等曙1.1.1套接口地址結(jié)構(gòu)IPV4套接口地址結(jié)構(gòu)sockaddr_in”命名,定義在頭文件IPV4套接口地址結(jié)構(gòu)通常也稱為“網(wǎng)際套接口地址結(jié)構(gòu)”,它以“structInad

3、drin-addr-ts-aettj<netinet/>。f*32-biiIPv4address*/*networkBytgordered*/strictsockacUr-ln!uint8-tsin-lenj/*lengthofstruclur«(16)*/sa-famlly-tsin-famllyf/*AF-INET*/inport.tsfn-port;/*1S-t>ltTCPorUDPportnumber*/Znetworkbyteordered*/ulructinaddrslnaddr/«32bitIPv4sddess*/«networkb

4、yteordered«/charsin,zeroIBr/*unused僭f通用套接口地址結(jié)構(gòu)structsockaddruint8_tsa_len;sa_family_tsa_family;charsa_data14;IFv4wcka彎f二in長度RfineTi6位端口號(hào)32位IfM迪址|irvB嗣確関仁臥長度|AFJNET616位端口號(hào)32位洗様U(kuò)nixwcUddr-unOIAF-LOCAL(未用)固定隹度門6字節(jié)圖LI1圈位IP帕地址路徑名f最多104宇節(jié))長度AF-LINK接口索引類型名字忙度地址長度選擇符長度接口名字和儺路層地址Daialinksoctoddr-dlO可變長度

5、圖Ml固定長度(囂字節(jié)S14數(shù)據(jù)類型說明頭文件in(8-t芾符號(hào)的8垃整數(shù)<sye/type8*h>uint8-t無符號(hào)的號(hào)位整數(shù)<Isys/t/pe3*h>int16.t帶符號(hào)的16fit®數(shù)<sys/types.H>uin(16_t無符號(hào)的16位整數(shù)Vsys/types*hAmt32-t帶符號(hào)的撫位搭數(shù)<$ys/types,h>Uint32-t不帶符號(hào)的32位螯數(shù)Vwys/typc乩h>SB-Iamiiyr套接口地址結(jié)構(gòu)的地址族<sys/socket,hAsocklen.t套接口地址結(jié)枸的長度,一般為uint32-C&l

6、t;;sys/socket»h>ia-addrtIPv4地址*般為uint32_t*<netjnet/in,h>inpon-(TCP或UDP端口一般為Vneti砂t/imhA03.2Posix,lg®求的數(shù)據(jù)類陽可變檢度B14圖3/不同套接口地址結(jié)構(gòu)的比校1.1.2 socket函數(shù)為了執(zhí)行網(wǎng)絡(luò)I/O,個(gè)進(jìn)程必須做的第一件事情就是調(diào)用socet函數(shù),指定期望的通信協(xié)議類型#inclucfe<sys/sock6rt,h>intsockotdntfarnHyJntprotocol)i回,非負(fù)描述字一成功一1出錯(cuò)參數(shù):其中family參數(shù)指明協(xié)議族,

7、是下圖中的某個(gè)常值。該參數(shù)也被稱為協(xié)議域(domain)族-解釋AF,INETIPv4協(xié)徴AF-INET6TfMifr墳AF-LOCALUnk域協(xié)儀(第】4章AF,.ROUTS略由套接口(第17AF-KEY1密鑰套接口圖£2socket函數(shù)的協(xié)儀族(family)Type參數(shù)指明套接口類型,是下圖中的某個(gè)常值類型解釋SOCK-STREAM字節(jié)關(guān)套按白3OCK-DGRAM數(shù)據(jù)根套接口SOCK-RAW原始套接口,圖43socket函數(shù)的套接口類執(zhí)type)Protocol參數(shù)應(yīng)設(shè)為下圖所示的某個(gè)協(xié)議類型常值,或者設(shè)為0,以選擇所給定的family和type組合和系統(tǒng)缺省值。protoco

8、l說明IPPROTO_TCPTCP傳輸協(xié)議IPPROTO_UDPUDP傳輸協(xié)議IPPROTO_SCTPSCTP傳輸協(xié)議綁定端口綁定端口指的是將套接字與指定的端口相連。用socket函數(shù)建立起一個(gè)套接字以后,需要用bind函數(shù)在這個(gè)套接字上面綁定一個(gè)端口。本節(jié)將講解套接字的綁定端口操作1.2.1綁定端口函數(shù)bind函數(shù)bind可以將一個(gè)端口綁定到一個(gè)已經(jīng)建立的socket上,這個(gè)函數(shù)的使用方法如下所示。include<sys/b(nd(intsockM,conststructsockaddr*myadct*&ccklen-1adctlen)i返回山伐功出錯(cuò)參數(shù)列

9、表中,sockfd表示已經(jīng)建立的socket編號(hào),sockaddr是一個(gè)指向sockaddr結(jié)構(gòu)體類型的指針sockaddr的定義方法如下所示。structsockaddrunsignedshortintsa_family;charsa_data14;這個(gè)結(jié)構(gòu)體的成員含義如下所示。sa_family:為調(diào)用socket()時(shí)的domain參數(shù),即AF_xxxx值。sa_data:最多使用14個(gè)字符長度,含有IP地址與端口的信息。如果建立socket時(shí)使用的是AF_INET參數(shù),則socketaddr結(jié)構(gòu)體的定義方法如下所示structsocketaddr_inunsignedshortints

10、in_family;uint16_tsin_port;structin_addrsin_addr;unsignedcharsin_zero8;結(jié)構(gòu)體的成員in_addr也是一個(gè)結(jié)構(gòu)體,定義方式如下所示。structin_addruint32_ts_addr;在這些結(jié)構(gòu)體中,成員變量的作用與含義如下所示。sin_family:即為sa_family,為調(diào)用socket()時(shí)的domain參數(shù)。sin_port:使用的端口號(hào)。:IP地址。sin_zero:未使用的字段,填充為0。參數(shù)addrlen表示my_addr的長度,可以用sizeof函數(shù)來取得。函數(shù)可以把指定的IP與端口綁定到已經(jīng)建立的so

11、cket上面。如果綁定成功,則返回0,失敗則返回-1。函數(shù)可能發(fā)生下面的錯(cuò)誤,可以用error捕獲發(fā)生的錯(cuò)誤。在使用這個(gè)函數(shù)前,需要在程序的最前面包含下面的頭文件。#include<sys/>#include<sys/>1.2.2 bind函數(shù)綁定端口實(shí)例下面的實(shí)例使用了bind函數(shù)在一個(gè)打開的socket上面綁定IP與端口。綁定的端口是5678,IP為INADDR_ANY表示本地計(jì)算機(jī)的默認(rèn)IP地址。#include<sys/>#include<sys/>#include<netinet/>#include<arpa/>

12、#include<>/*包含頭文件。*/#definePORT5678/定*義一個(gè)表示端口的常量。*/main()intsockfd,newsockfd,fd;/*定義相關(guān)的變量。*/structsockaddr_inaddr;intaddr_len=sizeof(structsockaddr_in);fd_setmyreadfds;charmsgbuffer256;/*定義一個(gè)字符數(shù)組存儲(chǔ)發(fā)送和接收到的信息。*/if(sockfd=socket(AFNET,SOCK_STREAM,O)<0建立一個(gè)socket。*/perror("socket");exi

13、t(1);else/*建立成功。*/printf("socketcreated.n");printf("sockedid:%dn",sockfd);bzero(&addr,sizeof(addr);/*清空表示地址的結(jié)構(gòu)體變量。*/=AF_INET;=htons(PORT);/*設(shè)置addr的成員。*/=htonl(INADDR_ANY);if(bind(sockfd,&addr,sizeof(addr)<O)/*bind函數(shù)綁定端口。*/perror("connect");exit(1);else/*失敗的情況

14、。*/printf("connected.n");printf("localport:%dn",PORT);程序運(yùn)行結(jié)果如下:socketcreated.sockedid:3connected.localport:5678監(jiān)聽與連接所謂監(jiān)聽,指的是socket的端口處于等待狀態(tài),如果客戶端有連接請(qǐng)求,這個(gè)端口會(huì)接受這個(gè)連接。連接指的是客戶端向服務(wù)端發(fā)送一個(gè)通信申請(qǐng),服務(wù)端會(huì)響應(yīng)這個(gè)請(qǐng)求。本節(jié)將講述socket的監(jiān)聽與連接操作。1.3.1等待監(jiān)聽函數(shù)listen服務(wù)器必須等待客戶端的連接請(qǐng)求,listen函數(shù)用于實(shí)現(xiàn)監(jiān)聽等待功能。這個(gè)函數(shù)的使用方法如下所示

15、。intlisten(ints,intbacklog);在參數(shù)列表中,s表示已經(jīng)建立的socket,backlog表示能同時(shí)處理的最大連接請(qǐng)求,如果超過這個(gè)數(shù)目,客戶端將會(huì)接收到ECONNREFUSE拒絕連接的錯(cuò)誤。需要注意的是,listen并未真正的接受連接,只是設(shè)置socket的狀態(tài)為listen模式,真正接受客戶端連接的是accept函數(shù)。通常情況下,listen函數(shù)會(huì)在socket,bind函數(shù)之后調(diào)用,然后才會(huì)調(diào)用accept函數(shù)。listen函數(shù)只適用SOCK_STREA或SOCK_SEQPACKETsocket類型。如果socket為AF_INET則參數(shù)backlog最大值可設(shè)至

16、128,即最多可以同時(shí)接受128個(gè)客戶端的請(qǐng)求。如果調(diào)用成功,則函數(shù)的返回值為0,失敗返回-1。函數(shù)可能發(fā)生如下所示的錯(cuò)誤,可以用errno來捕獲發(fā)生的錯(cuò)誤。在使用這個(gè)函數(shù)前,需要在程序的最前面包含下面的頭文件。#include<sys/>1.3.2 listen函數(shù)使用實(shí)例本節(jié)將講述一個(gè)listen函數(shù)使用實(shí)例。在程序中,先建立一個(gè)socket,然后用bind函數(shù)在這個(gè)socket上面綁定端口與IP,然后用listen函數(shù)設(shè)置這個(gè)socket進(jìn)行監(jiān)聽。程序的代碼如下所示。#include<sys/>#include<sys/>#include<net

17、inet/>#include<arpa/>#include<>/*包含頭文件。*/#definePORT5678/定*義一個(gè)表示端口號(hào)的常量。*/#defineMAX10/*最多的連接客戶端數(shù)。*/main()intsockfd,newsockfd,is_connectedMAX,fd;/*定義相關(guān)的變量。*/structsockaddr_inaddr;intaddr_len=sizeof(structsockaddr_in);fd_setmyreadfds;charmsgbuffer256;charmsg="Thisisthemessagefrom.n

18、"if(sockfd=socket(AFNET,SOCK_STREAM,0)v(建立一個(gè)socket。*/perror("socket");exit(1);printf("socketcreated.n");printf("sockedid:%dn",sockfd);bzero(&addr,sizeof(addr);/*清空addr所在的內(nèi)存。*/=AF_INET;/*設(shè)置addr的相關(guān)信息。*/=htons(PORT);=htonl(INADDR_ANY);if(bind(sockfd,&addr,size

19、of(addr)<0)/*綁定端口。*/perror("connect");exit(1);else/*端口綁定成功。*/printf("connected.n");printf("localport:%dn",PORT);if(listen(sockfd,3)<0)/*監(jiān)聽一個(gè)端口。*/perror("listen");/*錯(cuò)誤則輸出提示。*/exit(1);else/*輸出結(jié)果。*/printf("listenningn");程序的運(yùn)行結(jié)果如下所示。socketcreated.s

20、ockedid:3connected.localport:5678listenning1.3.3 接受連接函數(shù)accept服務(wù)器處于監(jiān)聽狀態(tài)時(shí),如果獲得客戶機(jī)的請(qǐng)求會(huì)將這個(gè)請(qǐng)求放在等待隊(duì)列中,當(dāng)系統(tǒng)空閑時(shí)將處理客戶機(jī)的連接請(qǐng)求。接受連接請(qǐng)求的函數(shù)是accept,這個(gè)函數(shù)的使用方法如下所示。intaccept(ints,structsockaddr*addr,int*addrlen);在參數(shù)列表中,s表示處于監(jiān)聽狀態(tài)的socket,addr是一個(gè)sockaddr結(jié)構(gòu)體類型的指針,系統(tǒng)會(huì)把遠(yuǎn)程主機(jī)的這些信息保存到這個(gè)結(jié)構(gòu)體指針上,addrlen表示sockaddr的內(nèi)存長度,可以用sizeof函數(shù)

21、來取得。當(dāng)accept函數(shù)接受一個(gè)連接時(shí),會(huì)返回一個(gè)新的socket編號(hào)。以后的數(shù)據(jù)傳輸與讀取就是通過這個(gè)新的socket編號(hào)來處理。原來參數(shù)中的socket可以繼續(xù)使用。接受連接以后,遠(yuǎn)程主機(jī)的地址和端口信息將會(huì)保存到addr所指的結(jié)構(gòu)體內(nèi)。如果處理失敗,返回值為-1。函數(shù)可能產(chǎn)生下面的錯(cuò)誤,可以用error來捕獲發(fā)生的錯(cuò)誤。在使用這個(gè)函數(shù)前,需要在程序中包含下面的頭文件。#include<sys/>#include<sys/>1.3.4 accept函數(shù)使用實(shí)例本節(jié)將講述一個(gè)accept函數(shù)使用實(shí)例。在程序中,先建立一個(gè)socket,然后用bind函數(shù)在這個(gè)sock

22、et函數(shù)上面綁定一個(gè)端口,然后使用listen函數(shù)使這個(gè)端口處于監(jiān)聽狀態(tài)。當(dāng)有連接請(qǐng)求時(shí),accpet函數(shù)會(huì)產(chǎn)生一個(gè)新的socket,然后輸出提示信息。程序的代碼如下所示。#include<sys/>#include<sys/>#include<netinet/>#include<>/*包含頭文件。*/#definePORT5678/*定義一個(gè)端口常量。*/main()intsockfd,newsockfd,fd;/*定義相關(guān)的變量。*/structsockaddr_inaddr;intaddr_len=sizeof(structsockaddr

23、_in);fd_setmyreadfds;charmsgbuffer256;/*定義一個(gè)字符串。*/if(sockfd=socket(AFNET,SOCK_STREAM,O)<0建立一個(gè)socket。*/perror("socket");exit(1);elseprintf("socketcreated.n");/*socket建立成功。*/printf("sockedid:%dn",sockfd);bzero(&addr,sizeof(addr);/*設(shè)置addr的信息。*/=AF_INET;=htons(PORT);

24、=htonl(INADDR_ANY);if(bind(sockfd,&addr,sizeof(addr)<O)/*綁定端口號(hào)。*/perror("connect");exit(1);elseprintf("connected.n");printf("localport:%dn",PORT);if(listen(sockfd,3)<0)/*監(jiān)聽一個(gè)端口號(hào)。*/perror("listen");exit(1);elseprintf("listenningn");if(newsoc

25、kfd=accept(sockfd,&addr,&addr_len)<0)/*接受一個(gè)連接。*/perror("accept");elseprintf("acceptedanewconnecttion.n");程序的運(yùn)行結(jié)果如下所示。socketcreated.sockedid:3connected.localport:5678listenning結(jié)果表明,本地計(jì)算機(jī)的5678號(hào)端口處于監(jiān)聽狀態(tài)。打開瀏覽器,在瀏覽器的地址欄中輸入下面的網(wǎng)址,然后按“Ente鍵。這樣瀏覽器會(huì)請(qǐng)求連接本地計(jì)算機(jī)的5678號(hào)端口。瀏覽器會(huì)顯示無法打開這個(gè)

26、網(wǎng)頁。在終端中顯示的結(jié)果如下所示。表明這個(gè)程序已經(jīng)接受了這個(gè)連接,然后退出了程序。acceptedanewconnecttion.1.3.5 請(qǐng)求連接函數(shù)connet所謂請(qǐng)求連接,指的是客戶機(jī)向服務(wù)器發(fā)送信息時(shí),需要發(fā)送一個(gè)連接請(qǐng)求。connect函數(shù)可以完成這項(xiàng)功能,這個(gè)函數(shù)的使用方法如下所示。intconnect(intsockfd,structsockaddr*serv_addr,intaddrlen);在參數(shù)列表中,sockfd表示已經(jīng)建立的socket,serv_addr是一個(gè)結(jié)構(gòu)體指針,指向一個(gè)sockaddr結(jié)構(gòu)體,這個(gè)結(jié)構(gòu)體存儲(chǔ)著遠(yuǎn)程服務(wù)器的IP與端口信息,Addrlen表示s

27、ockaddr結(jié)構(gòu)體的內(nèi)存長度,可以用sizeof函數(shù)來獲取。sockaddr結(jié)構(gòu)體的定義見前面節(jié)中的bind函數(shù)所述。函數(shù)會(huì)將本地的socket連接到serv_addr所指定的服務(wù)器IP與端口。如果連接成功,返回值為0,連接失敗則返回-1。函數(shù)可能發(fā)生下面的錯(cuò)誤,可以用error來捕獲發(fā)生的錯(cuò)誤。如果需要使用這個(gè)函數(shù),需要在程序的最前面包含下面的頭文件。#include<sys/>#include<sys/>1.3.6 connet函數(shù)使用實(shí)例本節(jié)將講解一個(gè)connet函數(shù)的實(shí)例,在程序中連接到遠(yuǎn)程服務(wù)器。在實(shí)例中連接的遠(yuǎn)程服務(wù)器是央視國際網(wǎng)站,域名是??梢栽诮K端中輸

28、入下面的命令來取得這個(gè)域名的IP地址。Ping顯示的結(jié)果如下所示PING56(84)bytesofdata.所以央視國際的服務(wù)器IP地址是。網(wǎng)站服務(wù)的端口是80。程序的代碼如下所示#inelude<>#inelude<netinet/>#inelude<arpa/>#inelude<>#inelude<>#inelude<sys/>#inelude<sys/>#inelude<sys/>#definePORT80/定義一個(gè)端口號(hào)。*/#defineREMOTE_IP""/定義一個(gè)

29、IP地址。*/intmain(intarge,ehar*argv)ints;/*定義相關(guān)的變量。*/struetsockaddr_inaddr;charmybuffer256;if(s=soeket(AFNET,SOCK_STREAM,0)<0建建立一個(gè)socket。*/perror("soeket");exit(1);elseprintf("soeketereated.n");printf("sockedid:%dn",s);bzero(&addr,sizeof(addr);/*設(shè)置addr的信息。*/=AF_INET

30、;=htons(PORT);if(connect(s,&addr,sizeof(addr)<0)/*連接到遠(yuǎn)程服務(wù)器。*/perror("connect");exit(1);else/輸出信息。*/printf("connectedok!n");printf("remoteip:%sn",REMOTE_IP);printf("remoteport:%dn",PORT);程序的運(yùn)行結(jié)果如下所示。結(jié)果表明程序已經(jīng)正常連接到了遠(yuǎn)程服務(wù)器socketcreated.sockedid:3connectedok!

31、remoteip:remoteport:80數(shù)據(jù)的發(fā)送與接收建立套接字并完成網(wǎng)絡(luò)連接以后,可以把信息傳送到遠(yuǎn)程主機(jī)上,這個(gè)過程就是信息的發(fā)送。對(duì)于遠(yuǎn)程主機(jī)發(fā)送來的信息,本地主機(jī)需要進(jìn)行接收處理。本節(jié)將講述這種面向連接的套接字信息發(fā)送與接收操作。LU1.4.1數(shù)據(jù)接收函數(shù)recv函數(shù)recv可以接收遠(yuǎn)程主機(jī)發(fā)送來的數(shù)據(jù),并把這些數(shù)據(jù)保存到一個(gè)數(shù)組中。該函數(shù)的使用方法如下所示。intrecv(ints,void*buf,intlen,unsignedintflags);在參數(shù)列表中,s表示已經(jīng)建立的socket,buf是一個(gè)指針,指向一個(gè)數(shù)組,接收到的數(shù)據(jù)會(huì)保存到這個(gè)數(shù)組上,Ien表示數(shù)組的長度,

32、可以用sizeof函數(shù)來取得,flags一般設(shè)置為0,其他可能的賦值與含義如下所示。MSG_OOB:接收以out-of-band送出的數(shù)據(jù)。MSG_PEEK返回來的數(shù)據(jù)并不會(huì)在系統(tǒng)內(nèi)刪除,如果再調(diào)用recv時(shí)會(huì)返回相同的數(shù)據(jù)內(nèi)容。MSG_WAITALL強(qiáng)迫接收到len大小的數(shù)據(jù)后才能返回,除非有錯(cuò)誤或信號(hào)產(chǎn)生。MSG_NOSIGNAL此操作被SIGPIPE信號(hào)中斷。recv函數(shù)如果接收到數(shù)據(jù),會(huì)把這些數(shù)據(jù)保存在buf指針指向的內(nèi)存中,然后返回接收到字符的個(gè)數(shù)。如果發(fā)生錯(cuò)誤則會(huì)返回-1。函數(shù)可能發(fā)生下面這些錯(cuò)誤,可以用errno來捕獲錯(cuò)誤。EBADF參數(shù)s不是一個(gè)合法的socket。EFAULT

33、參數(shù)中的指針指向了無法讀取的內(nèi)存空間。ENOTSOCK參數(shù)s是文件描述詞,而不是一個(gè)socket。EINTR被信號(hào)中斷。EAGAIN:此動(dòng)作會(huì)阻斷進(jìn)程,但參數(shù)s的socket不可阻斷。ENOBUFS系統(tǒng)的緩沖內(nèi)存不足。ENOMEM:核心內(nèi)存不足EINVAL參數(shù)不正確。在使用這個(gè)函數(shù)前,需要在程序的最前面包含下面的頭文件。#include<sys/>#include<sys/>d1.4.2recv函數(shù)使用實(shí)例本節(jié)將講解一個(gè)recv函數(shù)使用實(shí)例。在程序中,連接到北京大學(xué)的FTP服務(wù)器,然后用recv函數(shù)取得ftp服務(wù)器返回的信息。北京大學(xué)的FTP服務(wù)器域名如下所示。在終端中

34、輸入下面的命令,取得這個(gè)域名的IP地址。ping終端中顯示的結(jié)果如下所示。PING56(84)bytesofdata.if(connect(s,&addr,sizeof(addr)<0)/*連接遠(yuǎn)程服務(wù)器。*/代碼1-5recv函數(shù)接收數(shù)據(jù)#include<>#include<netinet/>#include<arpa/>#include<>#include<>#include<sys/>#include<sys/>#include<sys/>/*包含頭文件。*/#definePOR

35、T21/*定義一個(gè)端口號(hào)。*/#defineREMOTE_IP""/*定義一個(gè)IP地址。*/intmain(intargc,char*argv)ints;/*定義相關(guān)的變量。*/structsockaddr_inaddr;charmybuffer256;if(s=socket(AF_INET,SOCK_STREAM,O)<0/*建立一個(gè)socketo*/perror("socket");exit(1);elseprintf("socketcreated.n");/*socket建立成功。*/printf("socked

36、id:%dn",s);bzero(&addr,sizeof(addr);/*清空addr所占的內(nèi)存。*/=AF_INET;/*設(shè)置addr的成員。*/=htons(PORT);perror("connect");exit(1);elseprintf("connectedok!n");/*連接成功。*/printf("remoteip:%sn",REMOTE_IP);printf("remoteport:%dn",PORT);recv(s,mybuffer,sizeof(mybuffer),0);/

37、*接收信息。*/printf("%sn",mybuffer);/*輸出接收到的信息。*/程序的運(yùn)行結(jié)果如下所示。結(jié)果表明程序已經(jīng)正確連接到了北京大學(xué)的FTP服務(wù)器。服務(wù)器返回了一段歡迎信息。socketcreated.sockedid:3connectedok!remoteip:port:21220WelcometoVINEYARDFTPservice.1.4.3信息發(fā)送函數(shù)send用connect函數(shù)連接到遠(yuǎn)程計(jì)算機(jī)以后,可以用send函數(shù)將信息發(fā)送到對(duì)方的計(jì)算機(jī)。這個(gè)函數(shù)的使用方法如下所示。intsend(ints,constvoid*msg,intlen,unsign

38、edintflags);在參數(shù)列表中,s表示已經(jīng)建立的socket,msg是需要發(fā)送數(shù)據(jù)的指針,len表示需要發(fā)送數(shù)據(jù)的長度。這個(gè)長度可以用sizeof函數(shù)來取得,參數(shù)flags一般設(shè)置為0,可能的賦值與含義如下所示。MSG_OOB:傳送的數(shù)據(jù)以out-of-band的方式送出。MSGDONTROUTE取消路由表查詢。MSG_DONTWAIT:設(shè)置為不可阻斷傳輸。MSG_NOSIGNAL此傳輸不可被SIGPIPE言號(hào)中斷。如果發(fā)送數(shù)據(jù)成功,函數(shù)會(huì)返回已經(jīng)傳送的字符個(gè)數(shù),否則會(huì)返回-1。函數(shù)可能發(fā)生下面這些錯(cuò)誤,可以用errno來捕獲函數(shù)的錯(cuò)誤。EBADF參數(shù)s不是一個(gè)正確的socket。EFA

39、ULT參數(shù)中的指針指向了不可讀取的內(nèi)存空間。ENOTSOCK參數(shù)s是一個(gè)文件,而不是一個(gè)socket。EINTR被信號(hào)中斷。EAGAIN:此操作會(huì)中斷進(jìn)程,但socket不允許中斷。ENOBUFS系統(tǒng)的緩沖內(nèi)存不足。ENOMEM:核心內(nèi)存不足。EINVAL傳給系統(tǒng)調(diào)用的參數(shù)不正確。在使用這個(gè)函數(shù)前,需要在程序的最前面包含下面的頭文件。1.4.4數(shù)據(jù)傳輸函數(shù)write與read在前面的章節(jié)講述過,write函數(shù)可以向文件中寫入數(shù)據(jù),read函數(shù)可以從文件中讀取數(shù)據(jù)。socket建立連接以后,向這個(gè)socket中寫入數(shù)據(jù)表示向遠(yuǎn)程主機(jī)傳送數(shù)據(jù),從socket中讀取數(shù)據(jù)相當(dāng)于接受遠(yuǎn)程主機(jī)傳送過來的數(shù)

40、據(jù)。這兩個(gè)函數(shù)的使用方法如下所示。ssize_twrite(intfd,constvoid*buf,size_tcount);ssize_tread(intfd,void*buf,size_tcount);在參數(shù)列表中,fd表示已經(jīng)建立的socket,buf是指向一段內(nèi)存的指針,count表示buf指向內(nèi)存的長度。read函數(shù)讀取字節(jié)時(shí),會(huì)把讀取的內(nèi)容保存到buf指向的內(nèi)存中,然后返回讀取到字節(jié)的個(gè)數(shù)。使用write函數(shù)傳輸數(shù)據(jù)時(shí),會(huì)把buf指針指向的內(nèi)存中的數(shù)據(jù)發(fā)送到socket連接的遠(yuǎn)程主機(jī),然后返回實(shí)際發(fā)送字節(jié)的個(gè)數(shù)。在使用這個(gè)函數(shù)前,需要在程序的最前面包含下面的頭文件。#include

41、<>LU1.4.5read函數(shù)接收數(shù)據(jù)實(shí)例本節(jié)將講解一個(gè)read函數(shù)讀取數(shù)據(jù)的實(shí)例。在程序中,監(jiān)聽一個(gè)端口,如果有客戶端連接這個(gè)端口則接受這個(gè)連接,然后用read函數(shù)讀取遠(yuǎn)程主機(jī)發(fā)送的數(shù)據(jù),輸出這些數(shù)據(jù)以后結(jié)束這個(gè)程序。程序的代碼如下所示。代碼1-6read函數(shù)接收數(shù)據(jù):#include<sys/>#include<sys/>#inelude<netinet/>#include<arpa/>#include<>/*包含頭文件。*/#definePORT6677/*定義一個(gè)端口號(hào)。*/main()intsockfd,news

42、ockfd,fd;/*定義相關(guān)的變量。*/structsockaddr_inaddr;intaddr_len=sizeof(structsockaddr_in);fd_setmyreadfds;charmsgbuffer256;charmsg="Thisisthemessagefrom.n"if(sockfd=socket(AF_INET,SOCK_STREAM,0)<0)/*建立一個(gè)socket。*/perror("socket");exit(1);elseprintf("socketcreated.n");/*socket建

43、立成功。*/printf("sockedid:%dn”,sockfd);bzero(&addr,sizeof(addr);/*清空zero所在的內(nèi)存。*/=AF_INET;=htons(PORT);=htonl(INADDR_ANY);if(bind(sockfd,&addr,sizeof(addr)<0)/*綁定IP端口。*/perror("connect");exit(1);elseprintf("connected.n");printf("localport:%dn”,PORT);if(listen(soc

44、kfd,3)<0)/*監(jiān)聽一個(gè)端口號(hào)。*/perror("listen");exit(1);elseprintf("listenningn”);if(newsockfd=accept(sockfd,&addr,&addr_len)<0)/*接受一個(gè)連接。*/perror("accept");else/*輸出結(jié)果。*/printf("cnnectfrom%sn",inet_ntoa);if(read(newsockfd,msgbuffer,sizeof(msgbuffer)<=0)/*接收信息

45、。*/perror("accept");elseprintf("message:n%sn",msgbuffer);/*輸出接收到的信息。*/程序的運(yùn)行結(jié)果如下所示。結(jié)果表明這個(gè)程序正在監(jiān)聽本地計(jì)算機(jī)的6677號(hào)端口。socketcreated.sockedid:3connected.localport:6677listenning打開瀏覽器,在瀏覽器中輸入下面的網(wǎng)址,然后按“Enter鍵,使瀏覽器訪問本地計(jì)算機(jī)的6677號(hào)端口。瀏覽器顯示無法打開網(wǎng)頁。在終端中顯示了下面的代碼,這些代碼是瀏覽器向本機(jī)的6677號(hào)端口請(qǐng)求打開網(wǎng)頁的數(shù)據(jù)報(bào)。cnnectfro

46、m/HTTP/Host:Mozilla/(X11;U;Linuxi686;zh-CN;rv:)Gecko/Fedora/Firefox/text/xml,application/xml,application/xhtml+xml,text/html;q=,text/plain;q=,image/png,*/*elseprintfHi呂tunningn'');m一個(gè)簡(jiǎn)單的時(shí)間獲取客戶/服務(wù)器程序Figure51.SimpleechoclientandsetA/er.TCTclivnlvritenitenRTsencr服務(wù)器程序#inclade<sys/tvpe

47、s.h>fineludecsys/soclet,h>frin匚Ind皂<netinet/inh#in匚_udE<arpa/inet.h>include<tire.h>ludecunistd-h>*/intnainCintargc.char*argv)liltlisrenfdpConnfd,111;Etrnctsockaddr_inservaddr,cliaddT;charbuff1024;time_tticks;socklen_tlen;if(listenfd=socket(AF_INETfSOCK.STREAMh0)<0)perrorf&

48、quot;socket'1);exit(l):>elseprintfC'Socketcreated.nsocketid:%dn*',listenfd);bzero(&servadc3r,eizeoi(servaddr);servaddr.5in_family=AF_INET;exit(l);servaddr.sin_port=htons(丄日);servaddr.sin_addrHsaddr=titonl(INAEDE_ANY):1f(bind(listenfdt(structsockaddr*)dservaddrtsizecf(servaddr)<

49、0)elseptintf("connected.nlocalport:13n');if(Listen(li£tsnfd,3)<03exit(1);foC;)(len二siaeaf(cliaddr);ifttconnfd=acceptdistenfd.(Truersockaddr)<Sclladdr.t&len)<0)perrorf'acceperror*');elseprintf(iraccepedanewconmetion.n");ticks=time(WUtL);snprintf(buffh1zeof(buff

50、)h.24srn"tctime(&ticks);111=write(connfd.bufl*strlwcifbuff);close(cQnnfd);printf(,'oneok1sendlen二n"rlll);運(yùn)行結(jié)果:lucji-localhost:-日亡LdiTViewlerminal口oHelpAArQotGlocalhostcoot#gccdaytimetcpsrvlc-qdaytiinetcpsxvlrootOlDcalhostroot,/daytimetcpsrvl&ocltetcreated.socketid:3conttct&d.Localport:13Listenningaccepedanewconnetiontieok!sendlen=26客戶程序inelude<stdio.h>#in.elude<&s/types_h>#i

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(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)論