實(shí)驗(yàn)四客戶服務(wù)器通信_(tái)第1頁(yè)
實(shí)驗(yàn)四客戶服務(wù)器通信_(tái)第2頁(yè)
實(shí)驗(yàn)四客戶服務(wù)器通信_(tái)第3頁(yè)
實(shí)驗(yàn)四客戶服務(wù)器通信_(tái)第4頁(yè)
實(shí)驗(yàn)四客戶服務(wù)器通信_(tái)第5頁(yè)
已閱讀5頁(yè),還剩8頁(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)介

1、實(shí)驗(yàn)四 客戶/服務(wù)器通信實(shí)驗(yàn)一、實(shí)驗(yàn)?zāi)康? 學(xué)習(xí)Linux 的網(wǎng)絡(luò)編程的基本知識(shí)2 理解socket結(jié)構(gòu)和機(jī)制3 編寫簡(jiǎn)單客戶/服務(wù)器通信程序二、實(shí)驗(yàn)內(nèi)容1 了解Linux 的網(wǎng)絡(luò)編程的基本知識(shí):TCP/IP協(xié)議,尋址機(jī)制,客戶/服務(wù)器通信機(jī)制;2 理解端口的概念,熟悉socket有關(guān)的編程結(jié)構(gòu)和函數(shù),比如:socket(), bind(), connect(), listen(), accept(), send(), recv(), close();3 自己編寫ip2uint()函數(shù),把IP地址轉(zhuǎn)換為unsigned int格式;4 參考附錄中的源文件,在兩個(gè)虛擬控制臺(tái)分別實(shí)現(xiàn)分別服務(wù)器端和

2、客戶端功能,實(shí)現(xiàn)以下功能:1) 服務(wù)器端程序通過(guò)一個(gè)連接向客戶端發(fā)送字符串"Hello,world!n”,畫出客戶端程序和服務(wù)器端程序的流程圖;2) 服務(wù)器端程序通過(guò)一個(gè)連接向客戶端發(fā)送由客戶端指定的文件,畫出客戶端程序和服務(wù)器端程序的流程圖;5 在虛擬控制臺(tái)分別編譯、調(diào)試程序;三、實(shí)驗(yàn)指導(dǎo)與步驟按照以下步驟分別實(shí)現(xiàn)功能1和功能2:1、首先編寫好服務(wù)器和客戶端程序;2、打開一個(gè)虛擬終端,用gcc編譯預(yù)先寫好的服務(wù)器和客戶端程序;3、運(yùn)行服務(wù)器程序;4、打開另一個(gè)虛擬終端,運(yùn)行客戶端程序,連接成功后服務(wù)器給客戶端發(fā)送數(shù)據(jù);四、實(shí)驗(yàn)報(bào)告要求1 實(shí)驗(yàn)?zāi)康? 實(shí)驗(yàn)內(nèi)容3 實(shí)驗(yàn)步驟記錄自己實(shí)際

3、完成的步驟,實(shí)驗(yàn)過(guò)程中所碰到的難題以及你解決問(wèn)題的步驟和方法;4 實(shí)驗(yàn)技巧和心得體會(huì)附錄:簡(jiǎn)單的客戶/服務(wù)器通信示例一個(gè)建立分布式應(yīng)用時(shí)最常用的范例便是客戶機(jī)服務(wù)器模型。在這種方案中,客戶應(yīng)用程序向服務(wù)器程序請(qǐng)求服務(wù),這種方式隱含了在建立客戶機(jī)服務(wù)器間通信的非對(duì)稱性。客戶機(jī)服務(wù)器模型工作時(shí)要求有一套為客戶機(jī)和服務(wù)器所共識(shí)的協(xié)議,以保證服務(wù)能夠被提供或被接收,它必須在通信的兩端都被實(shí)現(xiàn)。在非對(duì)稱協(xié)議中,一方為主機(jī)(服務(wù)器),另一方則是從機(jī)(客戶機(jī))。當(dāng)服務(wù)被提供時(shí)必然存在“客戶進(jìn)程”和“服務(wù)進(jìn)程”。一個(gè)服務(wù)器通常在一個(gè)眾所周知的端口監(jiān)聽對(duì)服務(wù)的請(qǐng)求。也就是說(shuō),服務(wù)器一直處于休眠狀態(tài),直到一個(gè)客戶

4、對(duì)這個(gè)服務(wù)的端口提出連接請(qǐng)求。在這個(gè)時(shí)刻,服務(wù)程序被喚醒并且為客戶提供服務(wù),對(duì)客戶的請(qǐng)求做出了適當(dāng)?shù)姆磻?yīng)。其流程見圖1。例1:服務(wù)器端程序通過(guò)一個(gè)連接向客戶發(fā)送字符串"Hello,world!n”。在PC機(jī)上運(yùn)行服務(wù)器端程序,在開發(fā)板上運(yùn)行客戶端程序并輸入服務(wù)器的IP地址,則開發(fā)板的LCD屏上能顯示該字符串。服務(wù)器端發(fā)送程序host.c:#include <stdio.h>#include <stdlib.h>#include <errno.h>#include <string.h>#include <sys/types.h>

5、;#include <netinet/in.h>#include <sys/wait.h>#include <sys/socket.h>#include <ctype.h>#define MYPORT 3000 /*定義服務(wù)器的監(jiān)聽端口*/#define Max 100 /*定義了服務(wù)器一次可以發(fā)送的字符數(shù)目*/#define BACKLOG 10 /*BACKLOG指定在請(qǐng)求隊(duì)列中允許的最大請(qǐng)求數(shù),進(jìn)入的連接請(qǐng)求將在隊(duì)列中等待accept()函數(shù)接受它們*/main( )int sock_fd,new_fd, numbytes,i; /*soc

6、k_fd,new_fd是套接字描述*/char bufMax; /*發(fā)送數(shù)據(jù)的緩沖區(qū)*/struct sockaddr_in my_addr; /*服務(wù)器的地址結(jié)構(gòu)體*/struct sockaddr_in their_addr; /*主機(jī)的地址結(jié)構(gòu)體*/int sin_size;if(sock_fd=socket(AF_INET,SOCK_STREAM,0)= =1) /*建立流式套接字描述符*/ perror("socket"); exit(1);/*服務(wù)器結(jié)構(gòu)體的地址賦初值*/my_addr.sin_family=AF_INET;my_addr.sin_port=ht

7、ons(MYPORT); /*服務(wù)器的端口號(hào)*/my_addr.sin_addr.s_addr=INADDR_ANY;bzero(&(my_addr.sin_zero),8); /*填充0,湊齊長(zhǎng)度*/if(bind(sock_fd,(struct sockaddr*)&my_addr,sizeof(struct sockaddr)= = 1) /*綁定*/ perror("bindB"); /*綁定失敗*/ exit(1);if(listen(sock_fd,BACKLOG)= =1) /*監(jiān)聽端口是否有請(qǐng)求*/ perror("listen&q

8、uot;); /*監(jiān)聽失敗*/exit(1); while(1)sin_size=sizeof(struct sockaddr_in); if (new_fd=accept(sock_fd,(struct sockaddr *)&their_addr,&sin_size)= =1) perror("accept"); continue; printf("server:got connection from %sn",inet_ntoa(their_addr.sin_addr);if(!fork( ) /*子進(jìn)程代碼段:創(chuàng)建一個(gè)子進(jìn)程,用來(lái)

9、處理與剛建立的套接字的通信*/ if(send(new_fd,"Hello,World! n",14,0)= = 1) /*發(fā)送字符串*/ perror("send"); close(new_fd); exit(1); close(new_fd); /*父進(jìn)程不再需要該socket*/ while(waitpid(1,NULL,WNOHANG)>0); /*等待子進(jìn)程結(jié)束,清除子進(jìn)程所占用資源*/return 0;服務(wù)器首先創(chuàng)建一個(gè)socket,然后將該socket與本地地址/端口號(hào)捆綁,成功之后就在相應(yīng)的socket上監(jiān)聽,當(dāng)accpet捕捉到一

10、個(gè)連接服務(wù)請(qǐng)求時(shí),就生成一個(gè)新的socket,并調(diào)用fork( )函數(shù)產(chǎn)生一個(gè)子進(jìn)程與客戶機(jī)通信。該子進(jìn)程處理數(shù)據(jù)傳輸部分,通過(guò)這個(gè)新的socket向客戶端發(fā)送字符串"Hello,world!n",然后關(guān)閉該socket。fork( )函數(shù)語(yǔ)句是一個(gè)單調(diào)用雙返回的函數(shù)。若調(diào)用成功,在子進(jìn)程中返回的值為0,在父進(jìn)程中返回子進(jìn)程的進(jìn)程標(biāo)識(shí)號(hào);若調(diào)用失敗,則返回1。包含fork函數(shù)的if語(yǔ)句是子進(jìn)程代碼部分,它與if語(yǔ)句后面的父進(jìn)程代碼部分是并發(fā)執(zhí)行的??蛻舳私邮粘绦騟thernet.c:#include <sys/socket.h>#include <sys/

11、types.h>#include <netinet/in.h>#include <stdio.h>#include <unistd.h>#include <stdlib.h>#include <string.h>#include "./gui/gui.h" /*用于LCD屏的顯示*/#define PORT 3000 /*定義連接到服務(wù)器的端口號(hào)*/#define MAXDATASIZE 100 /*客戶機(jī)一次可接收的最大傳輸量*/*延時(shí)程序,用于LCD屏的顯示*/void delay( ) int i,j;

12、 for(i=0;i<4500;i+) for(j=0;j<4000;j+) /*將命令行輸入的字符串IP地址轉(zhuǎn)換成connect函數(shù)可識(shí)別的整數(shù)uiip*/int aiptoi(char * pszip,unsigned int* piip)char psziphere17,*psztmp1,*psztmp2,*pchar; /*定義指針*/int i;bzero(psziphere,17); /*清空將要進(jìn)行操作的數(shù)組*/strcpy(psziphere,pszip);/*將要轉(zhuǎn)換的IP地址存入該數(shù)組*/strcat(psziphere,".");/*在IP

13、地址串的末尾加“·”*/for(i=0,psztmp1=psziphere,pchar=(char )piip;i<4;i+)/*循環(huán)4次,將“·”轉(zhuǎn)變成0,并將字符串型轉(zhuǎn)換成整型*/if(psztmp2=strstr(psztmp1,".")=NULL) /*psztmp2返回指向字符“·”位置的指針*/ return 0;psztmp20=0;(pchar+i)=atoi(psztmp1); /*調(diào)用atoi( )函數(shù),將字符串轉(zhuǎn)換成整數(shù)*/psztmp1=psztmp2+1; /*指針psatmp1移到下一段的開始*/return

14、1;int main(int argc,char * argv)int sockfd,numbytes;unsigned int uiip;char bufMAXDATASIZE;int i;struct sockaddr_in servaddr;if(!aiptoi(argv1,&uiip)|argc<=1) /*檢查IP地址格式是否正確及IP是否輸入*/printf("the ip is not correct or have not input the ip!n");return 0;if (sockfd = socket(AF_INET,SOCK_ST

15、REAM,0)= =1) /*建立流式套接字描述符*/ perror("socket"); exit(1);/*給定主機(jī)信息*/servaddr.sin_family=AF_INET;servaddr.sin_port=htons(PORT); bzero(&(servaddr.sin_zero),8); servaddr.sin_addr.s_addr=uiip; if(connect(sockfd,(struct sockaddr *)&servaddr,sizeof(struct sockaddr)=1) /*建立連接*/printf("Ca

16、n't connect to the server!n");return 0;initgraph( ); /*初始化顯示環(huán)境*/if(numbytes=recv(sockfd,buf,MAXDATASIZE,0)= 1) /*接收服務(wù)器傳送過(guò)來(lái)的字符串*/ perror("recv"); exit(1);bufnumbytes='0'clearscreen( ); /*清屏*/textout(0,0,buf,0xffff,0x1111); /*顯示字符串*/delay( );clearscreen();close(sockfd);retur

17、n 0;函數(shù)aiptoi()處理的是字符串型的IP地址。首先將該字符串存放入psziphere 數(shù)組中,“psztmp1=psziphere”語(yǔ)句將字符串的首地址賦給psztmp1。為了便于使用循環(huán),調(diào)用strcat(psziphere,"."),將符號(hào)“·”添加到字符串尾部。接著循環(huán)開始,先找到第一個(gè)“·”的位置,psztmp2指向該處,并將該處賦為0(作為字符串的串結(jié)束符),調(diào)用函數(shù)atoi(psztmp1),此時(shí)psztmp1指向的是psziphere 數(shù)組的首地址,該函數(shù)將psztmp1指針?biāo)柑幍狡浜竺孀址Y(jié)束符處(即psztmp2處)的字

18、符串轉(zhuǎn)換成整型數(shù),并存放到pchar 數(shù)組中。然后,將psztmp1指針指向psztmp2所指的下一個(gè)字符,準(zhǔn)備開始下一個(gè)循環(huán)。以IP地址“192.168.2.100”為例,第一個(gè)循環(huán)中,psztmp1指向了“192.”的“1”處,而psztmp2指向了“192.168”的“·”處,并將該串改為“1960168”;atoi(psztmp1)函數(shù)將該串轉(zhuǎn)換成整數(shù)192;然后psztmp1指向了字符串“1960168”中的“1”;經(jīng)過(guò)四次循環(huán),用“·”分開的四段字符串就可以轉(zhuǎn)換成整數(shù)了??蛻舳舜a相對(duì)來(lái)說(shuō)要簡(jiǎn)單一些,首先通過(guò)命令行得到服務(wù)器的IP地址,然后創(chuàng)建一個(gè)socket,

19、調(diào)用connect函數(shù)與服務(wù)器建立連接,連接成功之后接收從服務(wù)器發(fā)送過(guò)來(lái)的數(shù)據(jù),最后關(guān)閉socket,結(jié)束程序。無(wú)連接的客戶/服務(wù)器程序的在原理上和連接的客戶/服務(wù)器是一樣的,兩者的區(qū)別在于無(wú)連接的客戶/服務(wù)器中的客戶一般不需要建立連接,而且在發(fā)送接收數(shù)據(jù)時(shí),需要指定遠(yuǎn)端機(jī)的地址。例2:在PC機(jī)上運(yùn)行一個(gè)發(fā)送程序,將一文件(圖片或文本文件)通過(guò)網(wǎng)口傳送到開發(fā)板,并在LCD上顯示該文件。該程序的流程如圖2所示。服務(wù)器端發(fā)送程序host.c:#include <stdio.h>#include <stdlib.h>#include <errno.h>#inclu

20、de <string.h>#include <sys/types.h>#include <sys/stat.h>#include <netinet/in.h>#include <sys/wait.h>#include <sys/socket.h>#include <ctype.h>#define MYPORT 3000 /*定義服務(wù)器的監(jiān)聽端口*/#define BACKLOG 10 /*BACKLOG指定在請(qǐng)求隊(duì)列中允許的最大請(qǐng)求數(shù),進(jìn)入的連接請(qǐng)求將在隊(duì)列中等待accept()函數(shù)接受它們*/int main

21、( )int sock_fd,new_fd; /*sock_fd,new_fd是套接字描述*/char filename20; /*存放要傳送文件的文件名*/struct sockaddr_in my_addr; /*服務(wù)器的地址結(jié)構(gòu)體*/struct sockaddr_in their_addr; /*主機(jī)的地址結(jié)構(gòu)體*/int sin_size;FILE *fp;char szsendbuf1024,head8; /*發(fā)送數(shù)據(jù)緩沖區(qū)大小為1K*/int nsize, allsize=0;int *phead=head+4;if(sock_fd=socket(AF_INET,SOCK_STR

22、EAM,0)= 1) /*建立流式套接字描述符/perror("socket");exit(1);/*服務(wù)器結(jié)構(gòu)體的地址賦初值*/my_addr.sin_family=AF_INET; my_addr.sin_port=htons(MYPORT); /*服務(wù)器的端口號(hào)3000*/my_addr.sin_addr.s_addr=INADDR_ANY;bzero(&(my_addr.sin_zero),8); /*填充0,湊齊長(zhǎng)度*/if(bind(sock_fd,(struct sockaddr*)&my_addr,sizeof(struct sockaddr

23、)= = 1) /*綁定*/perror("bindB"); /*綁定失敗*/exit(1);if(listen(sock_fd,BACKLOG)= = 1) /*監(jiān)聽端口是否有請(qǐng)求*/perror("listen"); /*監(jiān)聽失敗*/exit(1);while(1) sin_size=sizeof(struct sockaddr_in); if (new_fd=accept(sock_fd,(struct sockaddr *)&their_addr,&sin_size)= 1) perror("accept");

24、 continue; printf("server:got connection from %sn",inet_ntoa(their_addr.sin_addr);read(new_fd,filename,20); /*從端口讀文件名*/printf("%sn",filename);if(fp=fopen(filename,"r")=NULL) /*打開文件*/ printf("Can't find the file"); exit(1) ; nsize=1024;allsize=0;/*每次從文件讀取10

25、24個(gè)字節(jié)發(fā)送出去,若讀出少于1024個(gè)字節(jié),則認(rèn)為已到達(dá)文件末尾*/while(nsize = = 1024) bzero(szsendbuf,1024); /*清空緩沖區(qū)*/*從文件中讀取并發(fā)送到緩沖區(qū),填寫通信頭的數(shù)據(jù)長(zhǎng)度*/nsize = *phead = fread(szsendbuf,1,1024,fp);write(new_fd,head,8); /*發(fā)送協(xié)議頭*/nsize =write(new_fd,szsendbuf,nsize); /*發(fā)送數(shù)據(jù)*/allsize+=nsize; /*統(tǒng)計(jì)發(fā)送字節(jié)數(shù)*/if(allsize) /*每發(fā)送一次,打印當(dāng)前發(fā)送信息*/ print

26、f("now size:%d this time %d times:%dn",allsize,nsize,allsize/1024);if(nsize <= 0) /*若發(fā)送完畢,退出*/ printf("Can't send data!n"); return 0;close(new_fd);fclose(fp);close(sock_fd);return 0;字符串的IP和32位整型IP的轉(zhuǎn)換,由函數(shù)inet_aton()和inet_ntoa()完成。函數(shù)原型:int inet_aton(const char * cp,struct in

27、_addr* inp);char * inet_ntoa(struct in_addr in);函數(shù)里面a代表ascii,n代表network。第一個(gè)函數(shù)表示將a.b.c.d的IP地址轉(zhuǎn)換為32位的整型IP,由inp指針指向;第二個(gè)是將32位整型IP轉(zhuǎn)換為a.b.c.d的格式??蛻舳私邮粘绦騠ile.c:#include <sys/socket.h>#include <sys/types.h>#include <netinet/in.h>#include <stdio.h>#include <unistd.h>#include <

28、;stdlib.h>#include <string.h>#include "./gui/gui.h"#define PORT 3000#define Max 60000 /*接收文件的最大字節(jié)數(shù)*/void delay()int i,j; for(i=0;i<4500;i+) for(j=0;j<4000;j+) int aiptoi(char * pszip,unsigned int* piip)char psziphere17,*psztmp1,*psztmp2,*pchar;int i;bzero(psziphere,17);strcp

29、y(psziphere,pszip);strcat(psziphere,".");for(i=0,psztmp1=psziphere,pchar=(char *)piip;i<4;i+)if(psztmp2=strstr(psztmp1,".")=NULL)return 0;psztmp20=0;*(pchar+i)=atoi(psztmp1);psztmp1=psztmp2+1;return 1;int main(int argc,char *argv)int sockfd;unsigned int uiip;char bufMAX,*bmpbu

30、f;struct sockaddr_in myddr;FILE* fp;char szrecvbuf1024 /*一次接收數(shù)據(jù)緩沖區(qū)大小為1K*/char head8,*filename=”test.bmp”; /*filename指向要傳送文件的文件名*/int *phead=head+4,nsize=1024,allsize=0,i;if(sockfd=socket(AF_INET,SOCK_STREAM,0)= = 1) /*建立流式套接字描述符/perror("socket");exit(1);/*給定主機(jī)信息*/myaddr.sin_family=AF_INET;myaddr.sin_port=htons(PORT);bzero(&(myaddr.sin_zero),8);if(!aiptoi(argv1,&uiip)|

溫馨提示

  • 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)論