实验四 客户服务器通信.docx

上传人:牧羊曲112 文档编号:5175296 上传时间:2023-06-11 格式:DOCX 页数:17 大小:260.52KB
返回 下载 相关 举报
实验四 客户服务器通信.docx_第1页
第1页 / 共17页
实验四 客户服务器通信.docx_第2页
第2页 / 共17页
实验四 客户服务器通信.docx_第3页
第3页 / 共17页
实验四 客户服务器通信.docx_第4页
第4页 / 共17页
实验四 客户服务器通信.docx_第5页
第5页 / 共17页
亲,该文档总共17页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述

《实验四 客户服务器通信.docx》由会员分享,可在线阅读,更多相关《实验四 客户服务器通信.docx(17页珍藏版)》请在三一办公上搜索。

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简单的服务器/客户机通信流程图例1:服务器端程序通过一个连接向客户发送字符串Hello, world!n”。在PC机上运行服务器 端程序,在开发板上运行客户端程序并输入服务器的IP地址,则开发板的LCD屏上能显示 该字符串。服务器端发送程序host.c: #include #include #include #include #include #include #include #include #include #def

5、ine MYPORT 3000 #define Max 100/*定义服务器的监听端口 */*定义了服务器一次可以发送的字符数目*/ #define BACKLOG 10 /*BACKLOG指定在请求队列中允许的最大请求数,进入的连接 请求将在队列中等待accept()函数接受它们*/int sock_fd,new_fd, numbytes,i;char bufMax;struct sockaddr_in my_addr;struct sockaddr_in their_addr; int sin_size;/*sock_fd,new_fd是套接字描述*/*发送数据的缓冲区*/*服务器的地址结

6、构体*/*主机的地址结构体*/main()if(listen(sock_fd,BACKLOG)= = 1) perror(listen); exit(1);(listen);/*监听端口是否有请求*/*监听失败*/*监听端口是否有请求*/if(sock_fd=socket(AF_INET,SOCK_STREAM,0)= =-1)/* 建立流式套接字描述符*/ perror(socket); exit(1);/*服务器结构体的地址赋初值*/my_addr.sin_family=AF_INET;my_addr.sin_port=htons(MYPORT);/*服务器的端口号 */my_addr.s

7、in_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);while(1) sin_size=sizeof(struct sockaddr_in);if (new_fd=accept(sock_fd,(struct sockaddr *)&their_addr,&sin_size)= 1) per

8、ror(accept);continue;printf(server:got connection from %sn,inet_ntoa(their_addr.sin_addr);if(!fork()/*子进程代码段:创建一个子进程,用来处理与刚建立的套接字的通信*/ 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); /*等待子进程结束,清

9、除子进程所占用资源*/ return 0;服务器首先创建一个socket,然后将该socket与本地地址/端口号捆绑,成功之后就在相 应的socket上监听,当accpet捕捉到一个连接服务请求时,就生成一个新的socket,并 调用fork()函数产生一个子进程与客户机通信。该子进程处理数据传输部分,通过这个新 的socket向客户端发送字符串Hello,world!n,然后关闭该socket。fork()函数语句是一个单调用双返回的函数。若调用成功,在子进程中返回的值为0,在 父进程中返回子进程的进程标识号;若调用失败,则返回-1。包含fork函数的if语句是 子进程代码部分,它与if语句

10、后面的父进程代码部分是并发执行的。客户端接收程序ethernet.c:#include#include#include#include#include#include#include#include/*用于LCD屏的显示*/./gui/gui.h#define PORT 3000#define MAXDATASIZE 100/*延时程序,用于LCD屏的显示*/ void delay() int i,j;for(i=0;i4500;i+)for(j=0;j4000;j+) /*定义连接到服务器的端口号*/*客户机一次可接收的最大传输量*/*将命令行输入的字符串IP地址转换成connect函数可识

11、别的整数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 地址串的末尾加“ ” */for(i=0,psztmp1=psziphere,pchar=(char )piip;i4;i+)/*循环4次,将“ ”转变成0,并将字符串

12、型转换成整型*/if(psztmp2=strstr(psztmp1,.)=NULL) /*psztmp2 返回指向字符“ ”位置的指针*/ return 0;psztmp20=0;(pchar+i)=atoi(psztmp1); /*调用atoi()函数,将字符串转换成整数*/psztmp1=psztmp2+1;/*指针 psatmp1 移到下一段的开始*/return 1;int main(int argc,char * argv)int sockfd,numbytes;unsigned int uiip;char bufMAXDATASIZE;int i;struct sockaddr_i

13、n 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_STREAM,0)= =- 1)/* 建立流式套接字描述符*/ perror(socket);exit(1);/*给定主机信息*/servaddr.sin_family=AF_INET;servaddr.sin_port=htons(PORT);bzero(&(se

14、rvaddr.sin_zero),8);servaddr.sin_addr.s_addr=uiip;if(connect(sockfd,(struct sockaddr *)&servaddr,sizeof(struct sockaddr)=-1)/*建立连接*/printf(Cant connect to the server!n); return 0;initgraph( );/*初始化显示环境*/if(numbytes=recv(sockfd,buf,MAXDATASIZE,0)= 1) /* 接收服务器传送过来的字符 串*/ perror(recv);exit(1);bufnumbyt

15、es=0;clearscreen( );/*青屏*/textout(0,0,buf,0xffff,0x1111);/*显示字符串 */delay();clearscreen();close(sockfd);return 0;函数aiptoi ()处理的是字符串型的IP地址。首先将该字符串存放入psziphere 数组中,“psztmp1=psziphere”语句将字符串的首地址赋给psztmp1。为了便于使用循环, 调用strcat(psziphere,.),将符号“ ”添加到字符串尾部。接着循环开始,先找到第 一个“ ”的位置,psztmp2指向该处,并将该处赋为0 (作为字符串的串结束符)

16、,调用函 数atoi (psztmp1),此时psztmp1指向的是psziphere数组的首地址,该函数将psztmp1 指针所指处到其后面字符串串结束符处(即psztmp2处)的字符串转换成整型数,并存放到 pchar数组中。然后,将psztmp1指针指向psztmp2所指的下一个字符,准备开始下一个 循环。以IP地址“ 192.168.2.100”为例,第一个循环中,psztmp1指向了“ 192. ”的“1” 处,而 psztmp2 指向了 “192.168” 的 “” 处,并将该串改为 “1960168”; atoi (psztmp1) 函数将该串转换成整数192;然后psztmp1

17、指向了字符串“ 1960168”中的“1”;经过四次 循环,用“”分开的四段字符串就可以转换成整数了。客户端代码相对来说要简单一些,首先通过命令行得到服务器的IP地址,然后创建一 个socket,调用connect函数与服务器建立连接,连接成功之后接收从服务器发送过来的 数据,最后关闭socket,结束程序。无连接的客户/服务器程序的在原理上和连接的客户/服务器是一样的,两者的区别在于 无连接的客户/服务器中的客户一般不需要建立连接,而且在发送接收数据时,需要指定远 端机的地址。例2:在PC机上运行一个发送程序,将一文件(图片或文本文件)通过网口传送到开发板,并在 LCD上显示该文件。该程序的

18、流程如图2所示。图2网口通信程序流程图服务器端发送程序host.c:#include #include #include #include #include #include #include #include #include #include #define MYPORT 3000/*定义服务器的监听端口 */#define BACKLOG 10/*BACKLOG指定在请求队列中允许的最大请求数,进入的连接请求将在队列中等待accept()函数接受它们*/ int main()int sock_fd,new_fd;char filename20;struct sockaddr_in my_

19、addr;struct sockaddr_in their_addr;int sin_size;FILE *fp;char szsendbuf1024,head8;int nsize, allsize=0;int *phead=head+4;/*sock_fd,new_fd是套接字描述*/*存放要传送文件的文件名*/*服务器的地址结构体*/*主机的地址结构体*/*发送数据缓冲区大小为1K*/if(sock_fd=socket(AF_INET,SOCK_STREAM,0)= -1)/* 建立流式套接字描述符/ perror(socket);exit(1);/*服务器结构体的地址赋初值*/my_a

20、ddr.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)= = 1) /* 绑定*/ perror(bindB);/*绑定失败*/exit(1);if(listen(sock_fd,BACKLOG)= = 1)/* 监听端口是

21、否有请求 */ 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);continue;printf(server:got connection from %sn,inet_ntoa(their_addr.sin_addr);read(new_fd,filename,20);/*从端口读文件名 */printf(sn,filen

22、ame);if(fp=fopen(filename,r)=NULL)/*打开文件 */ printf(Cant find the file);exit(1);nsize=1024;allsize=0;/*每次从文件读取1024个字节发送出去,若读出少于1024个字节,则认为已到达文件末尾 */while(nsize = = 1024) bzero(szsendbuf,1024);/*清空缓冲区*/*从文件中读取并发送到缓冲区,填写通信头的数据长度*/ nsize = *phead = fread(szsendbuf,1,1024,fp);write(new_fd,head,8);/*发送协议头

23、 */nsize =write(new_fd,szsendbuf,nsize);/*发送数据*/allsize+=nsize;/*统计发送字节数*/if(allsize)/*每发送一次,打印当前发送信息*/printf(now size: %d this time %d times: %dn,allsize,nsize,allsize/1024);if(nsize = 0)/*若发送完毕,退出*/ printf(Cant send data!n);return 0;close(new_fd);fclose(fp);close(sock_fd);return 0;字符串的IP和32位整型IP的转

24、换,由函数inet_aton()和inet_ntoa()完成。函数原 型:int inet_aton(const char * cp, struct in_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 #include #include #include #include #include #include #inclu

25、de ./gui/gui.h#define PORT 3000#define Max 60000/*接收文件的最大字节数*/void delay()int i,j;for(i=0;i4500;i+)for(j=0;j4000;j+) int aiptoi(char * pszip,unsigned int* piip)char psziphere17,*psztmp1,*psztmp2,*pchar;int i;bzero(psziphere,17);strcpy(psziphere,pszip);strcat(psziphere,.);for(i=0,psztmp1=psziphere,pc

26、har=(char *)piip;i4;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,*bmpbuf;struct sockaddr_in myddr;FILE* fp;char szrecvbuf1024/*一次接收数据缓冲区大小为1K*/char head8,*filename=

27、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)|argc=1) printf(the ip is n

28、ot return 0;correct or have not input the ip !n);myaddr.sin_addr.s_addr=uiip;if(connect(sockfd,(struct printf(Cant connect return 0;sockaddr *)&myaddr,sizeof(struct sockaddr)to the server!n)initgraph();/*初始化显示环境*/bmpbuf=(char*)malloc(Max);bzero(bmpbuf,Max);/*申请空间,存放整个接收文件*/*清空缓冲区*/*将文件名发送给服务器*/write

29、(sockfd,filename,10);/*每次接收1024个字节,若接收的数据少于1024个字节,则认为已接收完毕*/ while(nsize= =1024)/*清空缓冲区*/*接收协议头*/*接收数据*/ bzero(szrecvbuf,1024);read(sockfd,head,8);nsize=read(sockfd,szrecvbuf,1024);/*将接收的数据存入bmpbuf缓冲区*/strcat(bmpbuf+allsize,szrecvbuf);allsize+=nsize;if(nsize0) break;bmpbufallsize=0;clearscreen();Sh

30、owBuf(bmpbuf,0,0);free(bmpbuf);/*青屏*/*在 LCD上显示bmpbuf缓冲区中的内容*/*释放缓冲区*/delay();clearscreen();close(sockfd);return 0;编写Makefile文件,在存放host.c和file.c的目录下执行make,生成可执行文件。注意在该目录下还应包含需传送的文件test.bmp。在PC机上运行:./host;在开发板上运行:./file PC机的IP地址;则开发板的LCD上显示test.bmp图片。同样,也可实现从开发板发送文件,由PC机接收;发送的文件可以是图片或文本文件。 只需对上述源程序略作修改即可,不妨自己动手试一试。IZ区槌入需要帮助的问题,x:文件但)编辑 视图 插入任)格式 工具d)表格)窗口地)帮助Qi)J以厦国uQ-la 1A号心J金堕E7恿口宇山正文 Times New Roman 五号 B Z U 囚A X 国言季莒拒 | 三买章章沏 & 孕昆

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 生活休闲 > 在线阅读


备案号:宁ICP备20000045号-2

经营许可证:宁B2-20210002

宁公网安备 64010402000987号