0

很久以前我就用这段代码的原理做了一个基于socket的服务端应用(IP地址和端口常量只做测试用):

   ...
   _mainSocket = new Socket(AddressFamily.InterNetwork, 
                            SocketType.Stream, ProtocolType.Tcp);

   _mainSocket.SetSocketOption(SocketOptionLevel.IP, 
                               SocketOptionName.ReuseAddress, 1);

   IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse("192.168.1.103"), 77);

   _mainSocket.Bind(endPoint);

   _mainSocket.Listen(5);

   _mainSocket.BeginAccept(new AsyncCallback(OnClientConnect), null);
   ...

它多年来一直运行良好,直到最近,当客户在 Windows Server 2008 机器上安装该服务并尝试从另一个网络(即通过一个或多个路由器)连接到它时。

令人惊讶的是,这是不可能的!

进一步分析显示,根本原因是我的服务的所有回复数据包中的TTL( IP 数据包标头中的生存时间参数)设置为1,从而有效地导致它们在遇到的第一个路由器上被丢弃。

有趣的是,如果我删除SetSocketOption(...)调用,TTL 会回到通常的 128!

这种奇怪的行为似乎只适用于 Windows Server 2008。Windows XP 和 Windows 7 都保持 TTL=128,正如我所期望的那样。我完全看不出为什么应该使用“ReuseAddress”选项更改 TTL。谁能解释一下?

我还可以通过在第一个调用之后添加第二个SetSocketOption(...) 调用将 TTL 恢复到 128:

_MainSocket.SetSocketOption( SocketOptionLevel.IP,
                             SocketOptionName.DontRoute, 0).

这有效地抵消了第一个 SetSocketOption(..) 调用的不良副作用......

请告诉我在这件事上我似乎不明白什么?

马丁。

4

1 回答 1

1

这个发布在 MSDN 页面上的简介SocketOptionName似乎有点启发性,尽管我还没有确认:

使用.NET Reflector阅读.NET Framework源码时的误区使用Red Gate的.NET Reflector解码.NET Framework v2.0中的类Socket...

...

为什么那是 ReuseAddress 而不是 IpTimeToLive?

实际上:

SocketOptionName.IpTimeToLive == SocketOptionName.ReuseAddress == 4

如果情况确实如此,那就可以解释为什么将TTL设置为1-这就是您传递给的值ReuseAddress

于 2012-07-05T11:00:44.287 回答