1,报文格式

报文如下,10.30.13.1往10.30.16.10的80端口发送了一个UDP报文,80端口其实监听的是TCP。

服务器回复了一个类型为端口不可达的ICMP,ICMP数据部分就是请求UDP ip层及其以上的数据。

2,产生的原因

首先原因就是接收udp报文的服务器对应的端口没有开启UDP服务器。注意这里的描述,并不是端口没有开启服务,而是没有开启UDP服务,如果开启了TCP服务,照样也会回port unreachable。

有时候,写UDP socket程序的时候,在调用sendto或者recvfrom的时候,会发现有Connection refused错误返回,错误码是ECONNREFUSED。对于懂得socket接口但是不很很懂网络的人,可能这根本就不是个问题,他会根据错误码知道远端没有这个服务端口,正如socket api的man手册中描述的那样:
ECONNREFUSED
              A remote host refused to allow the network connection (typically because it is not running the requested service).

有时候无知真的是一种幸福!但是如果你十分精通TCP/IP栈,那么就想不通了,UDP既然无连接,怎么知道远端的情况呢?UDP不正如协议标准描述的那样,发出去就不管了吗?对于接收,没有数据就一直等,如果设置了NOWAIT,则直接返回EAGAIN,表示稍后再试。不管怎么说,也不会有ECONNREFUSED这么详细的信息返回才对啊。
        既然UDP不会从对端返回任何错误信息,那么一定有别的什么返回了,总不能凭空猜测啊。这就涉及到了网络协议设计中的数据平面和控制平面了,对于控制平面的消息,可以是带内传输,也可以是带外传输。对于TCP而言,无疑是带内传输的,因为它本身就是有连接的协议,协议本身会处理任何的错误和异常,然而对于UDP而言,因为其设计目的就是保持简单性,故不再附带有任何带内的控制消息逻辑,互联网上为了弥补这一类协议的控制逻辑的缺失,ICMP协议才显得尤为重要!实际上,ICMP,根据名称就可以看出它是一种专门的控制协议,控制和指示IP层发生的事件。
        ECONNREFUSED正是ICMP返回的!然而并不是所有的UDP socket都可以享用ICMP带来的错误提示,毕竟带外控制消息和协议本身的关联太松散了。UDP socket必须显式的connect对端才可以。现在问题又来了,既然UDP根本就是一个无连接的协议,connect的意义何在呢?这其实是socket接口设计的范畴,和协议本身没有任何关系,当一个UDP socket去connect一个远端时,并没有发送任何的数据包,其效果仅仅是在本地建立了一个五元组映射,对应到一个对端,该映射的作用正是为了和UDP带外的ICMP控制通道捆绑在一起,使得UDP socket的接口含义更加丰满。
        我们知道,ICMP错误信息返回时,ICMP的包内容就是出错的那个原始数据包,根据这个原始数据包可以找出一个五元组,根据该五元组就可以对应到一个本地的connect过的UDP socket,进而把错误消息传输给该socket,应用程序在调用socket接口函数的时候,就可以得到该错误消息。如果一个UDP socket没有调用过connect,那么即使有ICMP数据包返回,由于socket保持了UDP的完整语义,协议栈也就不保存关于该socket和对端关联的任何信息,因此也就无法找到一个特定的五元组将错误码传给它。

3,应用程序怎么获知端口不可达。

udp一般应用程序不会获知icmp 的端口不可达信息。

为了获取udp端口不可达的情况,有2种方法:

1):int val = 1;

setsockopt(fd, IPPROTO_IP, IP_RECVERR , &val,sizeof(int));

2):

对udp进行connect操作,并且将sendto改成send

注:如果发送的目的ip,在当前网络中不存在,会怎么样?

客户端会先发送arp, 寻找目的主机的mac,因为目的ip不存在,自然没有回应,但是sendto返回成功(sendto返回成功仅仅表示将该报文发到ip的输出队列中),该报文不会被发送出去。

4,源程序

注意,阻塞情况下,recvfrom会阻塞,即使收到端口不可达消息,也会阻塞。但是经过 方法1 和 方法2后,recvfrom会返回,返回值是-1,然后 判断errno是否是ECONNREFUSED来判断是否收到端口不可达消息。

#include <stdio.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <string.h>
#include <errno.h>
unsigned char revc_buf[1024];int main()
{int fd,ret,recv_len,size=1024;struct sockaddr_in server_addr,addr;int val = 1;server_addr.sin_family = AF_INET;server_addr.sin_addr.s_addr = inet_addr("192.168.2.254");server_addr.sin_port = htons(77);fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);if(fd < 0){  perror("socket fail ");return -1;}printf("socket sucess\n");//方法1#if 1setsockopt(fd, IPPROTO_IP, IP_RECVERR , &val,sizeof(int));if(sendto(fd, "nihao", strlen("nihao"), 0, (const struct sockaddr *)&(server_addr), sizeof(struct sockaddr_in))<0){perror("sendto fail ");return -1;}printf("sendto sucess\n");recv_len = recvfrom(fd, revc_buf, sizeof(revc_buf), 0, (struct sockaddr *)&addr, (int *)&size);if (ret == -1){if (errno == ECONNREFUSED){printf("Recv port unreachable\n");}}//方法2#elif 0ret = connect(fd, (const struct sockaddr *) &(server_addr), sizeof (struct sockaddr_in));if(ret < 0){printf("connect fail\n");return -1;}ret = send(fd, "ni hao", strlen("nihao"),0);if(ret < 0){printf("write fail\n");return -1;}ret = recvfrom(fd, revc_buf, sizeof(revc_buf), 0, (struct sockaddr *)&addr, (int *)&size);if (ret == -1) {if (errno == ECONNREFUSED){printf("Recv port unreachable\n");}}#endifclose(fd);return 0;
}

udp端口不可达 icmp相关推荐

  1. linux udp端口大数据包,Linux协议栈中UDP数据报从网卡到用户空间流程总结

    NAPI驱动流程: 中断发生 -->确定中断原因是数据接收完毕(中断原因也可能是发送完毕,DMA完毕,甚至是中断通道上的其他设备中断) -->通过netif_rx_schedule将驱动自 ...

  2. python测试udp端口_zabbix上使用外部检查的方式监测公网tcp/udp端口开放情况

    1.使用nmap程序可以监测公网tcp/udp开放情况,比较准确 2.zabbix服务器支持使用外部检查的方式定义监控项,需要自己编写脚本 3.脚本的思路使用nmap监测公网指定tcp/udp端口,使 ...

  3. 如何对udp端口进行扫描

    由于UDP协议是非面向连接的,对UDP端口的探测也就不可能像TCP端口的探测那样依赖于连接建立过程(不能使用telnet这种tcp协议类型命令),这也使得UDP端口扫描的可靠性不高.所以虽然UDP协议 ...

  4. 97-ICMP 协议(端口不可达)

    ICMP 端口不可达是差错报文中的一种,它的类型(type)是 3,代码(code)也是 3. 1. 差错报文首部格式 图1 差错报文首部 2. 实验 打开我们之前写的 ICMP 报文接收程序 程序托 ...

  5. 如何判断远端主机UDP端口是否开启

    一.服务端TCP监听端口 如果是tcp作为监听端口,很多人里面可以想到相应的方法,由于tcp三次握手协议,我们可以直接写一个客户端程序即可判断tcp端口是否监听.我们汇总几种方法: 1.tcp soc ...

  6. UDP 端口扫描 - Nmap

    0x00:简介 nmap 在二层做主机发现时使用的参数是 sn(ping 扫描,不做端口扫描).在三层做主机发现时也是使用的 sn 参数,这里二三层都用的 sn 参数,而具体使用的是二层协议 arp ...

  7. python udp_如何用python方法检测UDP端口

    如何用python方法检测UDP端口,首先要了解什么是UDP端口及作用.网上搜索了一圈后,我得到的个人理解是:UDP端口是含有网络服务必须的源端口和目的端口信息,用以建立和实现网络传输服务. 那么如何 ...

  8. python监听udp端口_python检测远程udp端口是否打开

    python检测远程udp端口是否打开 import socket import threading import time import struct import Queue queue = Qu ...

  9. Apple 软件产品使用的 TCP 和 UDP 端口

    了解 Apple 产品(如 macOS.macOS 服务器."Apple 远程桌面"和 iCloud)使用的 TCP 和 UDP 端口.其中的很多端口都是大家熟知的行业标准端口. ...

最新文章

  1. 分析了 600 多种烘焙配方,机器学习开发出新品
  2. 聚焦AI落地痛点,纵论跨域学习技术前沿和应用趋势 | CNCC技术论坛
  3. RHEL/CentOS/Fedora各种源(EPEL、Remi、RPMForge、RPMFusion)配置
  4. 用python画出简单笑脸画法_【Python】怎么用matplotlib画出漂亮的分析图表
  5. ITK:将图像粘贴到另一个
  6. 滑动拼图验证码操作步骤:_拼图项目:延期的后果
  7. https抓包_从Wireshark抓包看HTTPS的加密功能
  8. 数据可视化系统在哪些行业中应用
  9. 1.4-shell中特殊符号
  10. 积分简明笔记-第二类曲线积分的类型
  11. c++学习————VC报错解决方案(vc2013)
  12. 《Redis开发与运维》学习第五章
  13. layim在线客服 架构实现
  14. 辅助工具_keysight_手持频谱仪(HSA) N9340B SCPI命令
  15. 电话交换机原理(企业运用方案)
  16. 如何利用计算机画立体几何图形,[转载]谈谈用Word2003画立体几何图形的技巧
  17. Cortex-A 架构
  18. LeetCode第82场双周赛
  19. git+vimdiff 一次关闭所有文件
  20. 《软件测试的艺术》万字笔记

热门文章

  1. 用友t3安装计算机名称不符合,「用友T3安装教程」简单三步安装T3,安装再也不求人!...
  2. MODBUS-寄存器与功能码学习
  3. 联想服务器rq940运维端口,联想RQ940服务器,联想服务器总代,金牌分销
  4. Linux在线安装mysql57-community-release-el7-10.noarch.rpm
  5. 北斗二号 号 RDSS 接收机数据接口要求(2.1 版)
  6. sai简画电吉他教程
  7. java计算机毕业设计理发店会员管理系统源码+系统+mysql数据库+lw文档
  8. Centos7 firewall的使用,以开放3306端口为例
  9. 网络安全学习篇28_阶段一小结篇_木马的原理及木马防范
  10. OBS云插件,智播,智慧主播最佳选择