C# UDP Socket ReceiveFrom 远程主机强迫关闭了一个现有的连接。

(经过反复研究,下述情况的原因终于搞清楚了,是"ICMP port unreachable"的问题,即:若向一个没有相应UDP监听端口的本机地址(比如127.0.0.1)发送UDP数据包,会回复ICMP port unreachable包,而这个包会被C#的UDP Socket ReceiveFrom函数得到,并报错为“远程主机强迫关闭了一个现有连接”!)

(而为什么向存在的另一个ip(另一台主机)发送不会报错?因为防火墙!win10的防火墙把外部回复的ICMP port unreachable给屏蔽掉了。经实验,把防火墙关掉后,就会出现上述报错了。)

(而为什么向一个不存在的ip地址发送不会报错?因为主机不存在,所以不会回复ICMP port unreachable)

详见:c# - An existing connection was forcibly closed by the remote host - Stack Overflowhttps://stackoverflow.com/questions/7201862/an-existing-connection-was-forcibly-closed-by-the-remote-host

具体描述:

Microsoft Article 263823 said this on the subject: [hard to find as of 2019]

SYMPTOMS In Windows 2000, a User Datagram Protocol (UDP) program may not work and may generate a WSAECONNRESET response.

CAUSE If sending a datagram using the sendto function results in an "ICMP port unreachable" response and the select function is set for readfds, the program returns 1 and the subsequent call to the recvfrom function does not work with a WSAECONNRESET (10054) error response. In Microsoft Windows NT 4.0, this situation causes the select function to block or time out.

RESOLUTION A new sockets IOCTL called "SIO_UDP_CONNRESET" has been introduced in Windows 2000. When this IOCTL is used, the program must be rewritten specifically for Windows 2000 to obtain the original Windows NT 4.0 behavior. Windows NT 4.0, Microsoft Windows 95, and Microsoft Windows 98 have no support for this new IOCTL. In addition to rewriting your application, you will need the hotfix referenced further down in this article.

解决方法:

在创建的socket上配置以下参数:

//配置socket参数,避免ICMP包导致的异常
uint IOC_IN = 0x80000000;
uint IOC_VENDOR = 0x18000000;
uint SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12;
ServerSocket.IOControl((int)SIO_UDP_CONNRESET, new byte[] { Convert.ToByte(false) }, null);

以下为原文

——————————————————————————————————————

原以为UDP就是往一个端口上扔数据,对方接收就行了,但经测试,发现没那么简单。肯定是我对UDP的理解不深刻……

前提:

程序A,绑定192.168.100.1(本机地址)的8000端口,向192.168.100.1(本机地址)的9000端口发消息。

程序B,绑定192.168.100.1的9000端口,向192.168.100.1的8000端口发消息。

情况1:

A和B均开始运行,可以互相发送消息(多线程或者单线程),运行正常!符合预期!

情况2:

A运行,但B不运行,则A在ReceiveFrom函数处会报错误:远程主机强迫关闭了一个现有的连接为什么?B不运行,A收不到数据不应该阻塞么?为什么会报错?

情况3:

继续测试:A运行,B不运行,但A改为向192.168.100.2(地址并不存在)的9000端口发送消息,则在ReceiveFrom函数处阻塞。符合预期!为什么?和情况2有什么本质不同么?

情况4:

A和B均开始运行,但B的绑定地址由192.168.100.1:9000,改为了127.0.0.1:9000。结果A和B均在ReceiveFrom函数处报错误:远程主机强迫关闭了一个现有的连接为什么?不都是本机地址么?

我要去看UDP的基础知识去了。

当然也可以就这么小心的用着,别掉坑里就行,但是为什么???哪位大佬给点提示???

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值