设置随同Echo请求一起发送的可选数据长度处理命令行参数为SIGALARM信号建立一个处理程序处理主机名参数调用readloop处理分组
2)readloop函数
创建套接口设置套接口缓冲区大小发送第一个分组读取返回给ICMP原始套接口的每个分组记录收到分组的时间调用proc来处理这些分组
3)proc函数
11
获取ICMP头部指针检查ICMP Echo replay输出收到的所有ICMP消息
4)send函数
构造ICMP消息计算校验和发送数据报 四、程序核心功能的实现机制
程序分为两大部分:一部分读取收到的所有消息,并输出ICMP Echo replay消息,另一部分每隔一秒钟发送一个Echo消息。另一部分由SIGALARM信号每秒驱动一次。
首先需要在main()函数里面的循环getopt()的参数里面增加参数,本次实验加的是b,c,h,i,q,s,t,v.然后不同的分支执行不同的操作。
在主函数的最后也就是readloop()函数之后再加一个statistics()数据统计函数,目的是在readloop()中返回时直接执行这个函数。 五、程序源代码(核心部分) 黑体字部分是修改部分
int main(int argc, char **argv) {
extern char *optarg; int c;
struct addrinfo *ai; char *e;
opterr = 0; /* don't want getopt() writing to stderr */
while ( (c = getopt(argc, argv, \ switch (c) { case 'b':
options |= F_BROADCAST; break; case 'c':
npackets = strtol(optarg, &e, 10);
12
if (npackets <= 0 || *optarg == '\\0' || *e != '\\0') errx(1, \ break; case 'h': usage(); exit(1); break;
case 'i': /* wait between sending packets */ interval = strtol(optarg, &e, 10);
if (interval <= 0 || *optarg == '\\0' || *e != '\\0') errx(1, \ options |= F_INTERVAL; break; case 'q':
options |= F_QUIET; break;
case 's': /* size of packet to send */ datalen = strtol(optarg, &e, 10);
if (datalen <= 0 || *optarg == '\\0' || *e != '\\0') errx(1, \ if (datalen > MAXPACKET)
errx(1, \value too large, maximum is MAXPACKET);
break; case 't':
ttl = strtol(optarg, &e, 10);
if (datalen <= 0 || *optarg == '\\0' || *e != '\\0') errx(1, \ options |= F_TTL; break; case 'v':
options |= F_VERBOSE; break; //case '?':
//err_quit(\ default: usage(); } }
if (optind != argc-1) usage(); host = argv[optind]; pid = getpid();
signal(SIGALRM, sig_alrm);
ai = host_serv(host, NULL, 0, 0);
if (options & F_BROADCAST)
13
%d\ printf(\
printf(\ Sock_ntop_host(ai->ai_addr, ai->ai_addrlen), datalen);
/* 4initialize according to protocol */ if (ai->ai_family == AF_INET) { pr = &proto_v4; #ifdef IPV6
} else if (ai->ai_family == AF_INET6) { pr = &proto_v6;
if (IN6_IS_ADDR_V4MAPPED(&(((struct sockaddr_in6 *) ai->ai_addr)->sin6_addr))) err_quit(\#endif } else
err_quit(\
(void)signal(SIGINT, onint);
pr->sasend = ai->ai_addr;
pr->sarecv = calloc(1, ai->ai_addrlen); pr->salen = ai->ai_addrlen;
readloop();
statistics(); exit(0); }
////////////////////////////////////////////////////////////// void readloop(void) {
int size;
char recvbuf[BUFSIZE]; socklen_t len; ssize_t n; struct timeval tval; int yes = 1;
sockfd = socket(pr->sasend->sa_family, SOCK_RAW, pr->icmpproto);
setuid(getuid()); /* don't need special permissions any more */
size = 60 * 1024; /* OK if setsockopt fails */
setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
if (options & F_TTL)
14
setsockopt(sockfd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)); if (options & F_BROADCAST) setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &yes, sizeof(yes));
sig_alrm(SIGALRM); /* send first packet */ for ( ; ; ) {
len = pr->salen;
n = recvfrom(sockfd, recvbuf, sizeof(recvbuf), 0, pr->sarecv, &len); if (n < 0) {
if (errno == EINTR) continue; else
err_sys(\ }
gettimeofday(&tval, NULL);
(*pr->fproc)(recvbuf, n, &tval);
if (npackets && nreceived >= npackets) break; } }
///////////////////////////////////////////////////////////// void usage() {
err_quit(\ [-b] [-q] [-s packetsize]\\n\\
[-t ttl] [-v] [-h]
///////////////////////////////////////////////////////////// void statistics()
{ printf(\
printf(\packets transmitted, %ld received , %%%d lost\\n\nsend, nreceived, (nsend-nreceived)/nsend*100); close(sockfd); exit(1); }
六、程序扩展功能的需求分析与实现
-b分支,主要是允许ping广播地址,设置option |=F_BROADCAST,然后在reedloop()函数
里面增加
if (options & F_BROADCAST)
setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &yes, sizeof(yes));语句 -c分支,主要是要获取包的数量,通过npackets = strtol(optarg, &e, 10);来实现。 -h分支,主要用来显示使用帮组信息的,只需要通过函数usage(),就可显示帮助信息。
15
百度搜索“77cn”或“免费范文网”即可找到本站免费阅读全部范文。收藏本站方便下次阅读,免费范文网,提供经典小说综合文库计算机网络课程设计(3)在线全文阅读。
相关推荐: