1、tcpip实验报告TCP/IP技术实验指导书李沁 编写专 业 网络工程 班 级 104 学 号 109074 姓 名 指导教师 李 沁 安徽工业大学计算机学院二一三年六月实验一 熟悉Linux编程环境 3实验二 实现Echo服客户端程序(UDP) 8实验三 循环无连接服务器Echo的实现 11实验四 循环的、面向连接服务器的实现 16实验五 并发的、面向连接服务器的实现 18实验六 单进程并发服务 21实验七 并发客户端 25实验八 多线程服务 29实验九 预分配进程服务器 331 实验总体目标配合TCPIP技术课程的教学,加强学生对TCP/IP编程技术的理解,培养学生的实际编程能力。2 实验
2、课时分配序号实 验 项 目学时试验类型实验一熟悉Linux编程环境2综合性实验二实现Echo服务客户端程序(UDP)2综合性实验三循环无连接服务器的实现2综合性实验四循环的、面向连接服务器的实现2综合性实验五并发的、面向连接服务器的实现2综合性实验六单进程并发服务2综合性实验七并发的客户端2综合性实验八多线程服务2综合性实验九预分配进程服务器2综合性3 实验环境开发工具:gcc以及编辑器(gedit, vi)操作系统:Linux 2.6以上 4 实验总体要求 按照各项实验内容做实验,包括操作、观察、记录、分析,通过操作和观察获得直观印象,从获得的数据中分析网络协议的工作原理; 每项实验均提交实
3、验报告,实验报告的内容可参照实验的具体要求,但总体上应包括以下内容:实验准备情况,实验记录,实验结果分析,算法描述,程序段,实验过程中遇到的问题以及对思考问题的解答等,实验目的、实验原理、实验步骤不需要写入实验报告中。实验一 熟悉Linux编程环境【实验目的】1 掌握gcc的基本使用方法。2 掌握fork函数的使用方法。3 掌握exeve函数的使用方法。【实验原理】一、gcc的基本编译命令设定编译出的 object 档档名或是可执行档档名:参数: -o out_put_filename说明: 指定编译出的档名为 out_put_filename。范例: 本例将程式码 test.c 编译成可执行
4、档,并设定档名为 test。gcc test.c o test二、fork函数 父进程调用fork函数创建子进程,返回值分别为0和子进程的PID,前者返回给子进程,后者返回给父进程。父子进程根据返回的PID确定将要继续执行的指令。例: int pid; sum=0; pid=fork(); if (pid!=0) /*original process*/ printf(The original process prints this.n); else printf(The new process prints this.n);三、execve函数int execve(const char *p
5、athname, char *const argv, char *const envp );函数说明 execve()用来执行参数filename字符串所代表的文件路径,第二个参数系利用数组指针来传递给执行文件,最后一个参数则为传递给执行文件的新环境变量数组。 返回值 如果执行成功则函数不会返回,执行失败则直接返回-1,失败原因存于errno中。 例:#include #include int main(int arg,char *args)/char *name=/usr/bin/ls;char *argv=ls,-l,/cway-linux/source,NULL;/传递给执行文件的参数数
6、组,这里包含执行文件的参数 char *envp=0,NULL;/传递给执行文件新的环境变量数组execve(/bin/ls,argv,envp);【实验步骤】一、练习1:编写一个并发程序,利用fork函数创建五个进程,让每一个进程打印出可用来分辨不同进程的信息。练习2:编写一个程序,利用execve函数改变进程执行的代码。二、利用gcc编译程序三、执行程序观察程序输出试验一 熟悉Linux编程环境实验时间:_ 成绩:_ 练习1:编写一个并发程序,利用fork函数创建五个进程,让每一个进程打印出可用来分辨不同进程的信息。#include#include#include int main() i
7、nt pid, i; i = 0; while(i 5) i+; if(pid=fork() = 0) printf(pid:%dn,getpid(); sleep(3); break; waitpid(pid,(int*)0,0); printf(ppid:%dn,getpid(); return 0; 运行结果:练习2:编写一个程序,利用execve函数改变进程执行的代码。/execve.c#include#include#includeint main(int argc,char *argv) char *newargv = NULL,you,me,NULL; char *newenvi
8、ron=NULL;if(argc != 2) fprintf(stderr,Usage:%s n,argv0); exit(EXIT_FAILURE); newargv0 = argv1; execve(argv1,newargv,newenviron); perror(execve); exit(EXIT_FAILURE);/myecho.c#include#include#includeint main(int argc, char *argv) int i; for(i = 0; i argc; i+) printf(argv%d:%sn,i,argvi);return 0;运行:./e
9、xecve myecho结果:cwjunevaubuntu:$ gedit execve.ccwjunevaubuntu:$ gedit myecho.ccwjunevaubuntu:$ gcc -o myecho myecho.ccwjunevaubuntu:$ ./execve myechoargv0:myechoargv1:youargv2:me实验二 实现Echo服客户端程序(UDP)【实验目的】1掌握客户端程序的基本结构2掌握如何形成socket地址3掌握在UDP的套接字上读写数据【实验环境配置】Linux,开启echo后台服务【实验原理】一、获取系统当前时间API:#include
10、 int gettimeofday(struct timeval *tv,struct timezone *tz); 保存时间的结构体strut timeval long tv_sec; /* 秒数 */ long tv_usec; /* 微秒数 */ ;例子:#include #include int main()struct timeval tpstart,tpend;double timeuse;int i=0;gettimeofday(&tpstart,NULL);for(i=0;i1000000000;i+);printf(%d,i);gettimeofday(&tpend,NULL
11、);timeuse=1000000*(tpend.tv_sec-tpstart.tv_sec)+tpend.tv_usec-tpstart.tv_usec;timeuse/=1000000;printf(processor time is %lf sn,timeuse);return 0;二、参阅教材6、7两章的代码理解客户端echo程序的结构以及相关socket系统调用【实验步骤】 1. 实现教材第7章练习第11题,对echo客户端程序进行改进,实现简单超时重传。(可以利用alarm函数或者select函数) 2. 启动系统后台echo服务,测试编写的程序能否与后台echo交互(127.0.
12、0.1) 3. 关闭后台echo服务,测试编写的程序能否重传(在标准输出上显示相邻重传之间的时间间隔)实验二 实现Echo服务客户端程序(UDP)实验时间:_ /client.c#include#include#include#include#include#include#include#include#include#includeint readable_timeo(int fd, int sec) fd_set rset; struct timeval tv; FD_ZERO(&rset); FD_SET(fd,&rset); tv.tv_sec = sec; tv.tv_usec =
13、 0; return (select(fd+1,&rset,NULL,NULL,&tv); /使用select函数实现简单超时重传int main(int argc, char *argv) int sockfd, len, res, i; struct sockaddr_in address; char *host; struct hostent *hostinfo; struct servent *servinfo; char buf128, buf2128; int nsec = 20;/timeout:20s struct timeval tpstart,tpend; double t
14、imeuse; if(argc = 1) host = localhost; else host = argv1; hostinfo = gethostbyname(host); if(!hostinfo) fprintf(stderr,no host:%sn,host); exit(1); servinfo = getservbyname(echo,udp); if(!servinfo) fprintf(stderr,no echo server!n); exit(1); sockfd = socket(AF_INET,SOCK_DGRAM,0); address.sin_family =
15、AF_INET; address.sin_port = servinfo-s_port; address.sin_addr = *(struct in_addr*)*hostinfo-h_addr_list; len = sizeof(address); while(fgets(buf,128,stdin) != NULL) for(i = 0; i s_port) + portbase); / portbase is used to prevent collision with well-known ports else if (sin.sin_port=htons(unsigned sho
16、rt)atoi(service) = 0) errexit(cant get %s service entryn, service); /* Map protocol name to protocol number */ if ( (ppe = getprotobyname(transport) = 0) errexit(cant get %s protocol entryn, transport); /*the structure of socket has been filled completely so far*/ /* Use protocol to choose a socket
17、type */ if (strcmp(transport, udp) = 0) type = SOCK_DGRAM; else type = SOCK_STREAM; /* Allocate a socket */ s = socket(PF_INET, type, ppe-p_proto); if (s 0) errexit(cant create socket: %sn, strerror(errno); /* Bind the socket */ if (bind(s, (struct sockaddr *)&sin, sizeof(sin) 0) errexit(cant bind t
18、o %s port: %sn, service, strerror(errno); if (type = SOCK_STREAM & listen(s, qlen) 0) errexit(cant listen on %s port: %sn, service, strerror(errno); return s;二、获取socket信息的系统API#include int ioctl(int fd, int request, . /* void *arg */ );fd是文件描述符,request是希望对fd执行的操作,当要获取socket信息时为SIOCGIFCONF.当调用ioctl函数
19、前,我们需要首先创建一个ifcong结构并初始化(对ifc_len赋以一个足够的长度),并将其地址作为ioctl函数的第三个参数。下面是ifcong结构的定义:struct ifconf int ifc_len; /* size of buffer, value-result */ union caddr_t ifcu_buf; /* input from user - kernel */ struct ifreq *ifcu_req; /* return from kernel - user */ ifc_ifcu;下面是ifreq结构的定义:#define IFNAMSIZ 16struc
20、t ifreq char ifr_nameIFNAMSIZ; /* interface name, e.g., le0 */ union struct sockaddr ifru_addr; struct sockaddr ifru_dstaddr; struct sockaddr ifru_broadaddr; short ifru_flags; int ifru_metric; caddr_t ifru_data; ifr_ifru;【实验步骤】实现服务端程序,需满足:1. 无连接、循环服务。2. 利用实验二的客户端程序向服务器程序请求服务,每次收到请求时在本地终端上输出客户端的IP地址和
21、本次服务的时间。3. 客户端多次请求服务,观察服务器对客户端的反馈和本地终端输出,判断是否正确实现迭代服务。试验三 循环无连接服务器Echo的实现实验时间:_ /server.c#include#include#include#include#include#include#include#include#include#include#define MAXLINE 128int sockfd, flag = 1;void close_action(int sig) printf(close the sockfdn); close(sockfd); signal(SIGINT,SIG_DFL)
22、; flag = 0;int main() struct sockaddr_in sin,sin_cli; int type, res, opt; char mesgMAXLINE, bufMAXLINE; socklen_t len; struct sigaction act; struct tm *ptm; int y,m,d,h,n,s; long ts; /set the signal action 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,cant create socket %s n,strerror(errno); exit(1);
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1