實驗四客戶服務器通信_第1頁
實驗四客戶服務器通信_第2頁
實驗四客戶服務器通信_第3頁
實驗四客戶服務器通信_第4頁
實驗四客戶服務器通信_第5頁
已閱讀5頁,還剩8頁未讀 繼續免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

1、實驗四 客戶/服務器通信實驗一、實驗目的1 學習Linux 的網絡編程的基本知識2 理解socket結構和機制3 編寫簡單客戶/服務器通信程序二、實驗內容1 了解Linux 的網絡編程的基本知識:TCP/IP協議,尋址機制,客戶/服務器通信機制;2 理解端口的概念,熟悉socket有關的編程結構和函數,比如:socket(), bind(), connect(), listen(), accept(), send(), recv(), close();3 自己編寫ip2uint()函數,把IP地址轉換為unsigned int格式;4 參考附錄中的源文件,在兩個虛擬控制臺分別實現分別服務器端和

2、客戶端功能,實現以下功能:1) 服務器端程序通過一個連接向客戶端發送字符串"Hello,world!n”,畫出客戶端程序和服務器端程序的流程圖;2) 服務器端程序通過一個連接向客戶端發送由客戶端指定的文件,畫出客戶端程序和服務器端程序的流程圖;5 在虛擬控制臺分別編譯、調試程序;三、實驗指導與步驟按照以下步驟分別實現功能1和功能2:1、首先編寫好服務器和客戶端程序;2、打開一個虛擬終端,用gcc編譯預先寫好的服務器和客戶端程序;3、運行服務器程序;4、打開另一個虛擬終端,運行客戶端程序,連接成功后服務器給客戶端發送數據;四、實驗報告要求1 實驗目的2 實驗內容3 實驗步驟記錄自己實際

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

4、對這個服務的端口提出連接請求。在這個時刻,服務程序被喚醒并且為客戶提供服務,對客戶的請求做出了適當的反應。其流程見圖1。例1:服務器端程序通過一個連接向客戶發送字符串"Hello,world!n”。在PC機上運行服務器端程序,在開發板上運行客戶端程序并輸入服務器的IP地址,則開發板的LCD屏上能顯示該字符串。服務器端發送程序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 /*定義服務器的監聽端口*/#define Max 100 /*定義了服務器一次可以發送的字符數目*/#define BACKLOG 10 /*BACKLOG指定在請求隊列中允許的最大請求數,進入的連接請求將在隊列中等待accept()函數接受它們*/main( )int sock_fd,new_fd, numbytes,i; /*soc

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

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

8、uot;); /*監聽失敗*/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( ) /*子進程代碼段:創建一個子進程,用來

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

10、個連接服務請求時,就生成一個新的socket,并調用fork( )函數產生一個子進程與客戶機通信。該子進程處理數據傳輸部分,通過這個新的socket向客戶端發送字符串"Hello,world!n",然后關閉該socket。fork( )函數語句是一個單調用雙返回的函數。若調用成功,在子進程中返回的值為0,在父進程中返回子進程的進程標識號;若調用失敗,則返回1。包含fork函數的if語句是子進程代碼部分,它與if語句后面的父進程代碼部分是并發執行的。客戶端接收程序ethernet.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 /*定義連接到服務器的端口號*/#define MAXDATASIZE 100 /*客戶機一次可接收的最大傳輸量*/*延時程序,用于LCD屏的顯示*/void delay( ) int i,j;

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

13、地址串的末尾加“·”*/for(i=0,psztmp1=psziphere,pchar=(char )piip;i<4;i+)/*循環4次,將“·”轉變成0,并將字符串型轉換成整型*/if(psztmp2=strstr(psztmp1,".")=NULL) /*psztmp2返回指向字符“·”位置的指針*/ return 0;psztmp20=0;(pchar+i)=atoi(psztmp1); /*調用atoi( )函數,將字符串轉換成整數*/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);/*給定主機信息*/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( ); /*初始化顯示環境*/if(numbytes=recv(sockfd,buf,MAXDATASIZE,0)= 1) /*接收服務器傳送過來的字符串*/ perror("recv"); exit(1);bufnumbytes='0'clearscreen( ); /*清屏*/textout(0,0,buf,0xffff,0x1111); /*顯示字符串*/delay( );clearscreen();close(sockfd);retur

17、n 0;函數aiptoi()處理的是字符串型的IP地址。首先將該字符串存放入psziphere 數組中,“psztmp1=psziphere”語句將字符串的首地址賦給psztmp1。為了便于使用循環,調用strcat(psziphere,"."),將符號“·”添加到字符串尾部。接著循環開始,先找到第一個“·”的位置,psztmp2指向該處,并將該處賦為0(作為字符串的串結束符),調用函數atoi(psztmp1),此時psztmp1指向的是psziphere 數組的首地址,該函數將psztmp1指針所指處到其后面字符串串結束符處(即psztmp2處)的字

18、符串轉換成整型數,并存放到pchar 數組中。然后,將psztmp1指針指向psztmp2所指的下一個字符,準備開始下一個循環。以IP地址“192.168.2.100”為例,第一個循環中,psztmp1指向了“192.”的“1”處,而psztmp2指向了“192.168”的“·”處,并將該串改為“1960168”;atoi(psztmp1)函數將該串轉換成整數192;然后psztmp1指向了字符串“1960168”中的“1”;經過四次循環,用“·”分開的四段字符串就可以轉換成整數了??蛻舳舜a相對來說要簡單一些,首先通過命令行得到服務器的IP地址,然后創建一個socket,

19、調用connect函數與服務器建立連接,連接成功之后接收從服務器發送過來的數據,最后關閉socket,結束程序。無連接的客戶/服務器程序的在原理上和連接的客戶/服務器是一樣的,兩者的區別在于無連接的客戶/服務器中的客戶一般不需要建立連接,而且在發送接收數據時,需要指定遠端機的地址。例2:在PC機上運行一個發送程序,將一文件(圖片或文本文件)通過網口傳送到開發板,并在LCD上顯示該文件。該程序的流程如圖2所示。服務器端發送程序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 /*定義服務器的監聽端口*/#define BACKLOG 10 /*BACKLOG指定在請求隊列中允許的最大請求數,進入的連接請求將在隊列中等待accept()函數接受它們*/int main

21、( )int sock_fd,new_fd; /*sock_fd,new_fd是套接字描述*/char filename20; /*存放要傳送文件的文件名*/struct sockaddr_in my_addr; /*服務器的地址結構體*/struct sockaddr_in their_addr; /*主機的地址結構體*/int sin_size;FILE *fp;char szsendbuf1024,head8; /*發送數據緩沖區大小為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);/*服務器結構體的地址賦初值*/my_addr.sin_family=AF_INET; my_addr.sin_port=htons(MYPORT); /*服務器的端口號3000*/my_addr.sin_addr.s_addr=INADDR_ANY;bzero(&(my_addr.sin_zero),8); /*填充0,湊齊長度*/if(bind(sock_fd,(struct sockaddr*)&my_addr,sizeof(struct sockaddr

23、)= = 1) /*綁定*/perror("bindB"); /*綁定失敗*/exit(1);if(listen(sock_fd,BACKLOG)= = 1) /*監聽端口是否有請求*/perror("listen"); /*監聽失敗*/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個字節發送出去,若讀出少于1024個字節,則認為已到達文件末尾*/while(nsize = = 1024) bzero(szsendbuf,1024); /*清空緩沖區*/*從文件中讀取并發送到緩沖區,填寫通信頭的數據長度*/nsize = *phead = fread(szsendbuf,1,1024,fp);write(new_fd,head,8); /*發送協議頭*/nsize =write(new_fd,szsendbuf,nsize); /*發送數據*/allsize+=nsize; /*統計發送字節數*/if(allsize) /*每發送一次,打印當前發送信息*/ print

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

27、_addr* inp);char * inet_ntoa(struct in_addr in);函數里面a代表ascii,n代表network。第一個函數表示將a.b.c.d的IP地址轉換為32位的整型IP,由inp指針指向;第二個是將32位整型IP轉換為a.b.c.d的格式。客戶端接收程序file.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 /*接收文件的最大字節數*/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 /*一次接收數據緩沖區大小為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);/*給定主機信息*/myaddr.sin_family=AF_INET;myaddr.sin_port=htons(PORT);bzero(&(myaddr.sin_zero),8);if(!aiptoi(argv1,&uiip)|

溫馨提示

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

評論

0/150

提交評論