实验四 客户服务器通信Word格式.docx
《实验四 客户服务器通信Word格式.docx》由会员分享,可在线阅读,更多相关《实验四 客户服务器通信Word格式.docx(15页珍藏版)》请在冰豆网上搜索。
2、打开一个虚拟终端,用gcc编译预先写好的服务器和客户端程序;
3、运行服务器程序;
4、打开另一个虚拟终端,运行客户端程序,连接成功后服务器给客户端发送数据;
四、实验报告要求
1.实验目的
2.实验内容
3.实验步骤
记录自己实际完成的步骤,实验过程中所碰到的难题以及你解决问题的步骤和方法;
4.实验技巧和心得体会
附录:
简单的客户/服务器通信示例
一个建立分布式应用时最常用的范例便是客户机/服务器模型。
在这种方案中,客户应用程序向服务器程序请求服务,这种方式隐含了在建立客户机/服务器间通信的非对称性。
客户机/服务器模型工作时要求有一套为客户机和服务器所共识的协议,以保证服务能够被提供或被接收,它必须在通信的两端都被实现。
在非对称协议中,一方为主机(服务器),另一方则是从机(客户机)。
当服务被提供时必然存在“客户进程”和“服务进程”。
一个服务器通常在一个众所周知的端口监听对服务的请求。
也就是说,服务器一直处于休眠状态,直到一个客户对这个服务的端口提出连接请求。
在这个时刻,服务程序被唤醒并且为客户提供服务,对客户的请求做出了适当的反应。
其流程见图1。
例1:
服务器端程序通过一个连接向客户发送字符串"
\n”。
在PC机上运行服务器端程序,在开发板上运行客户端程序并输入服务器的IP地址,则开发板的LCD屏上能显示该字符串。
服务器端发送程序host.c:
#include<
stdio.h>
stdlib.h>
errno.h>
string.h>
sys/types.h>
netinet/in.h>
sys/wait.h>
sys/socket.h>
ctype.h>
#defineMYPORT3000/*定义服务器的监听端口*/
#defineMax100/*定义了服务器一次可以发送的字符数目*/
#defineBACKLOG10/*BACKLOG指定在请求队列中允许的最大请求数,进入的连接请求将在队列中等待accept()函数接受它们*/
main()
{
intsock_fd,new_fd,numbytes,i;
/*sock_fd,new_fd是套接字描述*/
charbuf[Max];
/*发送数据的缓冲区*/
structsockaddr_inmy_addr;
/*服务器的地址结构体*/
structsockaddr_intheir_addr;
/*主机的地址结构体*/
intsin_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=htons(MYPORT);
/*服务器的端口号*/
my_addr.sin_addr.s_addr=INADDR_ANY;
bzero(&
(my_addr.sin_zero),8);
/*填充0,凑齐长度*/
if(bind(sock_fd,(structsockaddr*)&
my_addr,sizeof(structsockaddr))==−1)/*绑定*/
bindB"
/*绑定失败*/
exit
(1);
if(listen(sock_fd,BACKLOG)==−1)/*监听端口是否有请求*/
listen"
/*监听失败*/
exit
(1);
while
(1)
sin_size=sizeof(structsockaddr_in);
if((new_fd=accept(sock_fd,(structsockaddr*)&
their_addr,&
sin_size))==−1)
{perror("
accept"
continue;
}
printf("
server:
gotconnectionfrom%s\n"
inet_ntoa(their_addr.sin_addr));
if(!
fork())/*子进程代码段:
创建一个子进程,用来处理与刚建立的套接字的通信*/
{if(send(new_fd,"
Hello,World!
\n"
14,0)==−1)/*发送字符串*/
{perror("
send"
close(new_fd);
}
close(new_fd);
/*父进程不再需要该socket*/
}
while(waitpid(−1,NULL,WNOHANG)>
0);
/*等待子进程结束,清除子进程所占用资源*/
return0;
服务器首先创建一个socket,然后将该socket与本地地址/端口号捆绑,成功之后就在相应的socket上监听,当accpet捕捉到一个连接服务请求时,就生成一个新的socket,并调用fork()函数产生一个子进程与客户机通信。
该子进程处理数据传输部分,通过这个新的socket向客户端发送字符串"
\n"
,然后关闭该socket。
fork()函数语句是一个单调用双返回的函数。
若调用成功,在子进程中返回的值为0,在父进程中返回子进程的进程标识号;
若调用失败,则返回−1。
包含fork函数的if语句是子进程代码部分,它与if语句后面的父进程代码部分是并发执行的。
客户端接收程序ethernet.c:
unistd.h>
#include"
../gui/gui.h"
/*用于LCD屏的显示*/
#definePORT3000/*定义连接到服务器的端口号*/
#defineMAXDATASIZE100/*客户机一次可接收的最大传输量*/
/*延时程序,用于LCD屏的显示*/
voiddelay()
{inti,j;
for(i=0;
i<
4500;
i++)
for(j=0;
j<
4000;
j++){}
/*将命令行输入的字符串IP地址转换成connect函数可识别的整数uiip*/
intaiptoi(char*pszip,unsignedint*piip)
charpsziphere[17],*psztmp1,*psztmp2,*pchar;
/*定义指针*/
inti;
bzero(psziphere,17);
/*清空将要进行操作的数组*/
strcpy(psziphere,pszip);
/*将要转换的IP地址存入该数组*/
strcat(psziphere,"
."
/*在IP地址串的末尾加“·
”*/
for(i=0,psztmp1=psziphere,pchar=(char)piip;
4;
/*循环4次,将“·
”转变成0,并将字符串型转换成整型*/
{
if((psztmp2=strstr(psztmp1,"
))==NULL)/*psztmp2返回指向字符“·
”位置的指针*/
return0;
psztmp2[0]=0;
(pchar+i)=atoi(psztmp1);
/*调用atoi()函数,将字符串转换成整数*/
psztmp1=psztmp2+1;
/*指针psatmp1移到下一段的开始*/
return1;
intmain(intargc,char**argv)
intsockfd,numbytes;
unsignedintuiip;
charbuf[MAXDATASIZE];
structsockaddr_inservaddr;
if(!
aiptoi(argv[1],&
uiip)||argc<
=1)/*检查IP地址格式是否正确及IP是否输入*/
theipisnotcorrectorhavenotinputtheip!
return0;
if((sockfd=socket(AF_INET,SOCK_STREAM,0))==−1)/*建立流式套接字描述符*/
/*给定主机信息*/
servaddr.sin_family=AF_INET;
servaddr.sin_port=htons(PORT);
(servaddr.sin_zero),8);
servaddr.sin_addr.s_addr=uiip;
if(connect(sockfd,(structsockaddr*)&
servaddr,sizeof(structsockaddr))==−1)/*建立连接*/
Can'
tconnecttotheserver!
initgraph();
/*初始化显示环境*/
if((numbytes=recv(sockfd,buf,MAXDATASIZE,0))==−1)/*接收服务器传送过来的字符串*/
recv"
buf[numbytes]='
\0'
;
clearscreen();
/*清屏*/
textout(0,0,buf,0xffff,0x1111);
/*显示字符串*/
delay();
clearscreen();
close(sockfd);
函数aiptoi()处理的