公司内部的一个 golang 中间件报 UDP 连接异常的日志,问题很明显,对端的服务挂了,自然重启下就可以了。

哈哈,但让我疑惑的问题是 udp 是如何检测对端挂了?

err:  write udp 172.16.44.62:62651->172.16.0.46:29999: write: connection refusederr:  write udp 172.16.44.62:62651->172.16.0.46:29999: write: connection refusederr:  write udp 172.16.44.62:62651->172.16.0.46:29999: write: connection refused...

UDP 协议既没有三次握手,又没有 TCP 那样的状态控制报文,那么如何判定对端的 UDP 端口是否已打开?

通过抓包可以发现,当服务端的端口没有打开时,服务端的系统向客户端返回 icmp ECONNREFUSED 报文,表明该连接异常。

通过抓包可以发现返回的协议为 ICMP,但含有源端口和目的端口,客户端系统解析该报文时,通过五元组找到对应的 socket,并 errno 返回异常错误,如果客户端陷入等待,则唤醒起来,设置错误状态.

(上面是 udp 异常下的 icmp,下面是正常 icmp)

当 UDP 连接异常时,可以通过 tcpdump 工具指定 ICMP 协议来抓取该异常报文,毕竟对方是通过 icmp 返回的 ECONNREFUSED。

使用 tcpdump 抓包

请求命令:

先找到一个可以 ping 通的主机,然后用 nc 模拟 udp 客户端去请求不存在的端口,出现 Connection refused

[root@ocean ~]# nc -vzu 172.16.0.46 8888
Ncat: Version 7.50 ( https://nmap.org/ncat )
Ncat: Connected to 172.16.0.46:8888.
Ncat: Connection refused.

抓包信息如下:

[root@ocean ~]# tcpdump -i any icmp -nn
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
17:01:14.075617 IP 172.16.0.46 > 172.16.0.62: ICMP 172.16.0.46 udp port 8888 unreachable, length 37
17:01:17.326145 IP 172.16.0.46 > 172.16.0.62: ICMP 172.16.0.46 udp port 8888 unreachable, length 37
17:01:17.927480 IP 172.16.0.46 > 172.16.0.62: ICMP 172.16.0.46 udp port 8888 unreachable, length 37
17:01:18.489560 IP 172.16.0.46 > 172.16.0.62: ICMP 172.16.0.46 udp port 8888 unreachable, length 37

还需要注意的是 telnet 不支持 udp,只支持 tcp,建议使用 nc 来探测 udp。

各种case的测试

case小结

  • 当 ip 无法连通时,udp 客户端连接时,通常会显示成功。

  • 当 udp 服务端程序关闭,但系统还存在时,对方系统会 `icmp ECONNREFUSE 错误。

  • 当对方有操作 iptables udp port drop 时,通常客户端也会显示成功。

IP 无法联通时:

[root@host-46 ~ ]$ ping 172.16.0.65
PING 172.16.0.65 (172.16.0.65) 56(84) bytes of data.
From 172.16.0.46 icmp_seq=1 Destination Host Unreachable
From 172.16.0.46 icmp_seq=2 Destination Host Unreachable
From 172.16.0.46 icmp_seq=3 Destination Host Unreachable
From 172.16.0.46 icmp_seq=4 Destination Host Unreachable
From 172.16.0.46 icmp_seq=5 Destination Host Unreachable
From 172.16.0.46 icmp_seq=6 Destination Host Unreachable
^C
--- 172.16.0.65 ping statistics ---
6 packets transmitted, 0 received, +6 errors, 100% packet loss, time 4999ms
pipe 4[root@host-46 ~ ]$ nc -vzu 172.16.0.65 8888
Ncat: Version 7.50 ( https://nmap.org/ncat )
Ncat: Connected to 172.16.0.65:8888.
Ncat: UDP packet sent successfully
Ncat: 1 bytes sent, 0 bytes received in 2.02 seconds.

另外再次明确一点 udp 没有类似 tcp 那样的状态报文,所以单纯对 UDP 抓包是看不到啥异常信息。

那么当 IP 不通时,为啥 NC UDP 命令显示成功?

netcat nc udp 的逻辑

为什么当 ip 不连通或者报文被 DROP 时,返回连接成功?

因为 nc 默认的探测逻辑很简单,只要在 2 秒钟内没有收到 icmp ECONNREFUSED 异常报文,那么就认为 UDP 连接成功。

让人迷糊的 socket udp 连接问题相关推荐

  1. 网络编程懒人入门(八):手把手教你写基于TCP的Socket长连接

    转自即时通讯网:http://www.52im.net/ 本文原作者:"水晶虾饺",原文由"玉刚说"写作平台提供写作赞助,原文版权归"玉刚说" ...

  2. Python多人聊天室-基于socket UDP协议

    简介 使用Python编写的基于socket UDP通信的多功能即时聊天室,包含Tkinter编写的图形化聊天界面,功能包括有账号注册和登录,登录成功后可以查看在线用户,并和聊天室内的其他在线用户聊天 ...

  3. android socket 长连接_TCP/IP,http,socket,长连接,短连接

    点击上方蓝色字体,选择"标星公众号" 优质文章,第一时间送达 上一篇:这300G的Java资料是我师傅当年给我的,免费分享给大家 下一篇:这200G的Java实战资料是我师傅当年教 ...

  4. python382怎么用_用python做UDP连接

    写个客户端 #!/usr/bin/env python from socket import * HOST = '10.2.167.115' PORT = 20001 BUFSIZE = 1024 A ...

  5. python网络编程自学_五分钟搞定Python网络编程实现TCP和UDP连接

    Python网络编程实现TCP和UDP连接, 使用socket模块, 所有代码在python3下测试通过. 实现TCP#!/usr/bin/env python3 # -*- coding: utf- ...

  6. Sql语句中两个比较迷糊的概念:“连接查询” 与 “外键约束”

    Sql语句中两个比较迷糊的概念:"连接查询" 与 "外键约束 Sql 中的连接查询:就是为了避免笛卡尔积,因为涉及到多表查询的化,不使用连接查询,会先将多个互相乘,求出笛 ...

  7. c++语言socket udp聊天程序,使用C/C++实现Socket聊天程序

    使用C/C++实现Socket聊天程序 Initsock.h文件 // initsock.h文件 #include #include #include #include #pragma comment ...

  8. Python socket UDP

    UDP连接 服务端 import socket server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) server.bind(('', 8 ...

  9. Socket UDP、TCP 简介

    文章目录 Socket UDP.TCP 简介 1.1 Java 获取 IP.URL 1.2 UDP 服务端\客户端 1.3 TCP 服务端/客户端 Socket UDP.TCP 简介 1.1 Java ...

最新文章

  1. linux cpu漏洞,【图片】为什么linux mint上cpu漏洞直到现在也没完全修复?_linux吧_百度贴吧...
  2. phpcms ——模板标签详细使用说明
  3. 实验 3 简单的分支与循环结构
  4. JS-为金额添加千分位逗号分割符
  5. Mac免费软件推荐:Wireshark for Mac(网络分析器)
  6. Django项目搭建(基础)
  7. 外呼机器人起名_智能外呼机器人十大厂商
  8. Linux驱动开发经典书籍
  9. 优分享VR开源啦,优分享VR是基于Google VR开发的一款手机VR视频资源的聚合软件...
  10. ElasticSearch 2 (30) - 信息聚合系列之条形图
  11. 反编译工具Reflector下载(转)
  12. 三种近距离通信技术(WIFI、蓝牙、NFC)
  13. oracle 客户端怎样配置,oracle 之客户端配置
  14. QT 简单实现自定义标题栏
  15. Oracle数据库基本使用
  16. OData介绍 (SAP)
  17. 微信小程序开发流程指南
  18. 任意字符使用UE自带AES加密解密
  19. 海康工业相机排雷笔记-01-分辨率设置
  20. cfa的pv怎么用计算机算,CFA一级考试标配计算器使用功能详解

热门文章

  1. 我什么计算机作文600字,我家的电脑作文600字
  2. mysql设置字段为空字符串_mysql数据类型字段插入空字符串自动填充为0报错
  3. mybatis中mapUnderscoreToCamelCase自动驼峰命名转换
  4. 拦截器,过滤器,监听器原理
  5. 利用 LotusScript 灵活操作 Lotus Notes 富文本域
  6. CodeForces - 1607D Blue-Red Permutation(贪心)
  7. POJ - 3693 Maximum repetition substring(后缀数组+RMQ)
  8. HDU - 1584 蜘蛛牌(dfs+最优性剪枝)
  9. Java接口四个类四则运算_用JAVA设计一个接口,声明有关算术运行的方法,并创建四个应用该接口的类,分别进行+-*/四则运算...
  10. android判断参数非空,Android Studio注释模板Live Templates参数获取不到为null的一些