[关闭]
@rg070836rg 2017-01-10T00:50:43.000000Z 字数 2683 阅读 1216

TCP_IP第四次作业

TCP_IP


由于自己的偷懒,现在才开始补作业。
2017年1月10日0点

第四次作业 myping

这个作业主要是用到icmp差错检查的知识,不是很难

设置ICMP报头函数,压包

  1. /*设置ICMP报头*/
  2. int pack(int pack_no)
  3. {
  4. int i,packsize;
  5. struct icmp *icmp;
  6. struct timeval *tval;
  7. icmp = (struct icmp*)sendpacket;
  8. icmp->icmp_type = ICMP_ECHO; //ICMP_ECHO类型的类型号为0
  9. icmp->icmp_code = 0;
  10. icmp->icmp_cksum = 0;
  11. icmp->icmp_seq = pack_no; //发送的数据报编号
  12. icmp->icmp_id = pid;
  13. packsize = 8 + datalen; //数据报大小为64字节
  14. tval = (struct timeval *)icmp->icmp_data;
  15. gettimeofday(tval,NULL); //记录发送时间
  16. //校验算法
  17. icmp->icmp_cksum = cal_chksum((unsigned shortshort *)icmp,packsize);
  18. return packsize;
  19. }

发送ICMP报文

  1. void send_packet()
  2. {
  3. int packetsize;
  4. if(nsend < MAX_NO_PACKETS)
  5. {
  6. nsend++;
  7. packetsize = pack(nsend); //设置ICMP报头
  8. //发送数据报
  9. if(sendto(sockfd,sendpacket,packetsize,0,
  10. (struct sockaddr *)&dest_addr,sizeof(dest_addr)) < 0)
  11. {
  12. perror("sendto error");
  13. }
  14. }
  15. }

接受ICMP报文

  1. void recv_packet()
  2. {
  3. int n,fromlen;
  4. extern int error;
  5. fromlen = sizeof(from);
  6. if(nreceived < nsend)
  7. {
  8. //接收数据报
  9. if((n = recvfrom(sockfd,recvpacket,sizeof(recvpacket),0,
  10. (struct sockaddr *)&from,&fromlen)) < 0)
  11. {
  12. perror("recvfrom error");
  13. }
  14. gettimeofday(&tvrecv,NULL); //记录接收时间
  15. unpack(recvpacket,n); //剥去ICMP报头
  16. nreceived++;
  17. }
  18. }

拆包,做时间计算等

  1. int unpack(charchar *buf,int len)
  2. {
  3. int i;
  4. int iphdrlen; //ip头长度
  5. struct ip *ip;
  6. struct icmp *icmp;
  7. struct timeval *tvsend;
  8. double rtt;
  9. ip = (struct ip *)buf;
  10. iphdrlen = ip->ip_hl << 2; //求IP报文头长度,即IP报头长度乘4
  11. icmp = (struct icmp *)(buf + iphdrlen); //越过IP头,指向ICMP报头
  12. len -= iphdrlen; //ICMP报头及数据报的总长度
  13. if(len < 8) //小于ICMP报头的长度则不合理
  14. {
  15. printf("ICMP packet\'s length is less than 8\n");
  16. return -1;
  17. }
  18. //确保所接收的是所发的ICMP的回应
  19. if((icmp->icmp_type == ICMP_ECHOREPLY) && (icmp->icmp_id == pid))
  20. {
  21. tvsend = (struct timeval *)icmp->icmp_data;
  22. tv_sub(&tvrecv,tvsend); //接收和发送的时间差
  23. //以毫秒为单位计算rtt
  24. rtt = tvrecv.tv_sec*1000 + tvrecv.tv_usec/1000;
  25. temp_rtt[nreceived] = rtt;
  26. all_time += rtt; //总时间
  27. //显示相关的信息
  28. printf("%d bytes from %s: icmp_seq=%u ttl=%d time=%.1f ms\n",
  29. len,inet_ntoa(from.sin_addr),
  30. icmp->icmp_seq,ip->ip_ttl,rtt);
  31. }
  32. else return -1;
  33. }

主调用函数

生成ICMP的原始套接字,压入ip,发包,守包,检查包内内容,然后设置ttl

  1. main(int argc,charchar *argv[])
  2. {
  3. struct hostent *host;
  4. struct protoent *protocol;
  5. unsigned long inaddr = 0;
  6. int size = 550 * 1024;
  7. addr[0] = argv[1];
  8. //参数小于两个
  9. if(argc < 2)
  10. {
  11. printf("usage:%s hostname/IP address\n",argv[0]);
  12. exit(1);
  13. }
  14. //不是ICMP协议
  15. if((protocol = getprotobyname("icmp")) == NULL)
  16. {
  17. perror("getprotobyname");
  18. exit(1);
  19. }
  20. //生成使用ICMP的原始套接字
  21. if((sockfd = socket(AF_INET,SOCK_RAW,protocol->p_proto)) < 0)
  22. {
  23. perror("socket error");
  24. exit(1);
  25. }
  26. setsockopt(sockfd,SOL_SOCKET,SO_RCVBUF,&size,sizeof(size));
  27. bzero(&dest_addr,sizeof(dest_addr)); //初始化
  28. dest_addr.sin_family = AF_INET; //套接字域是AF_INET(网络套接字)
  29. //压入ip
  30. dest_addr.sin_addr.s_addr = inet_addr(argv[1]);
  31. pid = getpid();
  32. printf("PING %s(%s):%d bytes of data.\n",argv[1],
  33. inet_ntoa(dest_addr.sin_addr),datalen);
  34. //当按下ctrl+c时发出中断信号,并开始执行统计函数
  35. signal(SIGINT,statistics);
  36. while(nsend < MAX_NO_PACKETS){
  37. sleep(1); //每隔一秒发送一个ICMP报文
  38. send_packet(); //发送ICMP报文
  39. recv_packet(); //接收ICMP报文
  40. }
  41. return 0;
  42. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注