printf("argv[%d]:
%s\n",i,argv[i]);
return0;
}
运行:
./execvemyecho
结果:
cwjuneva@ubuntu:
~$geditexecve.c
cwjuneva@ubuntu:
~$geditmyecho.c
cwjuneva@ubuntu:
~$gcc-omyechomyecho.c
cwjuneva@ubuntu:
~$./execvemyecho
argv[0]:
myecho
argv[1]:
you
argv[2]:
me
实验二实现Echo服客户端程序(UDP)
【实验目的】
1.掌握客户端程序的基本结构
2.掌握如何形成socket地址
3.掌握在UDP的套接字上读写数据
【实验环境配置】
Linux,开启echo后台服务
【实验原理】
一、获取系统当前时间API:
#include
intgettimeofday(structtimeval*tv,structtimezone*tz);
保存时间的结构体
struttimeval{
longtv_sec;/*秒数*/
longtv_usec;/*微秒数*/};
例子:
#include
#include
intmain(){
structtimevaltpstart,tpend;
doubletimeuse;
inti=0;
gettimeofday(&tpstart,NULL);
for(i=0;i<1000000000;i++);
printf("%d,i);
gettimeofday(&tpend,NULL);
timeuse=1000000*(tpend.tv_sec-tpstart.tv_sec)+tpend.tv_usec-tpstart.tv_usec;
timeuse/=1000000;
printf("processortimeis%lfs\n",timeuse);
return0;}
二、参阅教材6、7两章的代码理解客户端echo程序的结构以及相关socket系统调用
【实验步骤】
1.实现教材第7章练习第11题,对echo客户端程序进行改进,实现简单超时重传。
(可以利用alarm函数或者select函数)
2.启动系统后台echo服务,测试编写的程序能否与后台echo交互(127.0.0.1)
3.关闭后台echo服务,测试编写的程序能否重传(在标准输出上显示相邻重传之间的时间间隔)
实验二实现Echo服务客户端程序(UDP)
实验时间:
_____________
//client.c
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
intreadable_timeo(intfd,intsec)
{
fd_setrset;
structtimevaltv;
FD_ZERO(&rset);
FD_SET(fd,&rset);
tv.tv_sec=sec;
tv.tv_usec=0;
return(select(fd+1,&rset,NULL,NULL,&tv));//使用select函数实现简单超时重传
}
intmain(intargc,char**argv)
{
intsockfd,len,res,i;
structsockaddr_inaddress;
char*host;
structhostent*hostinfo;
structservent*servinfo;
charbuf[128],buf2[128];
intnsec=20;//timeout:
20s
structtimevaltpstart,tpend;
doubletimeuse;
if(argc==1)
host="localhost";
else
host=argv[1];
hostinfo=gethostbyname(host);
if(!
hostinfo)
{
fprintf(stderr,"nohost:
%s\n",host);
exit
(1);
}
servinfo=getservbyname("echo","udp");
if(!
servinfo)
{
fprintf(stderr,"noechoserver!
\n");
exit
(1);
}
sockfd=socket(AF_INET,SOCK_DGRAM,0);
address.sin_family=AF_INET;
address.sin_port=servinfo->s_port;
address.sin_addr=*(structin_addr*)*hostinfo->h_addr_list;
len=sizeof(address);
while(fgets(buf,128,stdin)!
=NULL)
{
for(i=0;i<2;i++)//juseonechancetoresend
{
if(i==1)//resend
{
printf("ReSend!
!
!
\n");
gettimeofday(&tpend,NULL);
timeuse=1000000*(tpend.tv_sec-tpstart.tv_sec)+tpend.tv_usec-tpstart.tv_usec;
timeuse/=1000000;
printf("resendtimeis%lfs\n",timeuse);
}
gettimeofday(&tpstart,NULL);
res=sendto(sockfd,buf,strlen(buf),0,(structsockaddr*)&address,len);
if(readable_timeo(sockfd,nsec)==0)
{
fprintf(stderr,"sockettimeout\n");
continue;
}
res=recvfrom(sockfd,buf2,128,0,(structsockaddr*)&address,&len);
buf2[res]=0;
fputs(buf2,stdout);
break;//sendsuccessfully,quit!
}
}
close(sockfd);
exit(0);
}
实验三循环无连接服务器Echo的实现
【实验目的】
1.掌握服务器程序套接字构造方法
2.掌握实现迭代服务的程序结构
【实验原理】
一、服务器端构造UDP套接字
constchar*service;//nameofservice
constchar*transport;//tcporudp
intqlen;//thesizeofrequestqueue
/*
*Arguments:
*service-serviceassociatedwiththedesiredport
*transport-transportprotocoltouse("tcp"or"udp")
*qlen-maximumserverrequestqueuelength
*/
{
structservent*pse;/*pointertoserviceinformationentry*/
structprotoent*ppe;/*pointertoprotocolinformationentry*/
structsockaddr_insin;/*anInternetendpointaddress*/
ints,type;/*socketdescriptorandsockettype*/
memset(&sin,0,sizeof(sin));
sin.sin_family=AF_INET;
sin.sin_addr.s_addr=INADDR_ANY;//localIPinterfacedeterminedbykernel
/*Mapservicenametoportnumber*/
if(pse=getservbyname(service,transport))
sin.sin_port=htons(ntohs((unsignedshort)pse->s_port)
+portbase);//portbaseisusedtopreventcollisionwithwell-knownports
elseif((sin.sin_port=htons((unsignedshort)atoi(service)))==0)
errexit("can'tget\"%s\"serviceentry\n",service);
/*Mapprotocolnametoprotocolnumber*/
if((ppe=getprotobyname(transport))==0)
errexit("can'tget\"%s\"protocolentry\n",transport);
/*thestructureofsockethasbeenfilledcompletelysofar*/
/*Useprotocoltochooseasockettype*/
if(strcmp(transport,"udp")==0)
type=SOCK_DGRAM;
else
type=SOCK_STREAM;
/*Allocateasocket*/
s=socket(PF_INET,type,ppe->p_proto);
if(s<0)
errexit("can'tcreatesocket:
%s\n",strerror(errno));
/*Bindthesocket*/
if(bind(s,(structsockaddr*)&sin,sizeof(sin))<0)
errexit("can'tbindto%sport:
%s\n",service,
strerror(errno));
if(type==SOCK_STREAM&&listen(s,qlen)<0)
errexit("can'tlistenon%sport:
%s\n",service,
strerror(errno));
returns;
二、获取socket信息的系统API
#include
intioctl(intfd,intrequest,.../*void*arg*/);
fd是文件描述符,request是希望对fd执行的操作,当要获取socket信息时为SIOCGIFCONF.当调用ioctl函数前,我们需要首先创建一个ifcong结构并初始化(对ifc_len赋以一个足够的长度),并将其地址作为ioctl函数的第三个参数。
下面是ifcong结构的定义:
structifconf{
intifc_len;/*sizeofbuffer,value-result*/
union{
caddr_tifcu_buf;/*inputfromuser->kernel*/
structifreq*ifcu_req;/*returnfromkernel->user*/
}ifc_ifcu;
};
下面是ifreq结构的定义:
#defineIFNAMSIZ16
structifreq{
charifr_name[IFNAMSIZ];/*interfacename,e.g.,"le0"*/
union{
structsockaddrifru_addr;
structsockaddrifru_dstaddr;
structsockaddrifru_broadaddr;
shortifru_flags;
intifru_metric;
caddr_tifru_data;
}ifr_ifru;
};
【实验步骤】
实现服务端程序,需满足:
1.无连接、循环服务。
2.利用实验二的客户端程序向服务器程序请求服务,每次收到请求时在本地终端上输出客户端的IP地址和本次服务的时间。
3.客户端多次请求服务,观察服务器对客户端的反馈和本地终端输出,判断是否正确实现迭代服务。
试验三循环无连接服务器Echo的实现
实验时间:
_____________
//server.c
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#defineMAXLINE128
intsockfd,flag=1;
voidclose_action(intsig)
{
printf("closethesockfd\n");
close(sockfd);
signal(SIGINT,SIG_DFL);
flag=0;
}
intmain()
{
structsockaddr_insin,sin_cli;
inttype,res,opt;
charmesg[MAXLINE],buf[MAXLINE];
socklen_tlen;
structsigactionact;
structtm*ptm;
inty,m,d,h,n,s;
longts;
//setthesignalaction
act.sa_handler=close_action;
sigemptyset(&act.sa_mask);
act.sa_flags=0;
memset(&sin,0,sizeof(sin));
sin.sin_family=AF_INET;
sin.sin_addr.s_addr=INADDR_ANY;
sin.sin_port=htons(45454);
sockfd=socket(AF_INET,SOCK_DGRAM,0);
if(sockfd<0)
{
fprintf(stderr,"can'tcreatesocket%s\n",strerror(errno));
exit
(1);