版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
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”;经过四次循环,用“·”分开的四段字符串就可以转换成整数了。客户端代码相对来说要简单一些,首先通过命令行得到服务器的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. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 吉林艺术学院《劳动教育II》2021-2022学年第一学期期末试卷
- 房产经纪人返佣协议书范本模板
- 主播外出安全协议书范文范本
- 2024年大商铺出租转让协议书模板范本
- 【初中数学】整式的加法与减法课件 2024-2025学年人教版数学七年级上册
- 2024年处理废石协议书模板范本
- 资金代管协议书范文样本
- 2025(新人教版)地理八年级下册全册复习知识清单 课件
- 吉林师范大学《数字剪辑创作》2021-2022学年第一学期期末试卷
- 吉林师范大学《量子力学》2021-2022学年第一学期期末试卷
- 2024-2030年中国虚拟专用网络(VPN)行业市场行业发展分析及发展前景研究报告
- 检验检测机构内审员检查表
- 2024中煤电力限公司面向中煤集团内部招聘15人高频难、易错点500题模拟试题附带答案详解
- 统编版(2024新版)七年级上册历史第二单元 夏商周时期:奴隶制王朝的更替和向封建社会的过渡 单元复习课件
- 第07讲 物态变化(原卷版)-2024全国初中物理竞赛试题编选
- 高危儿规范化健康管理专家共识解读
- 第13课《纪念白求恩》课件2024-2025学年统编版语文七年级上册
- 食品安全的规章制度和食品操作流程
- 《义务教育体育与健康课程标准(2022年版)》解读
- 部编版三年级上册语文第七单元大单元教学设计
- NB-T 10435-2020 电动汽车快速更换电池箱锁止机构通.用技术要求
评论
0/150
提交评论