【问题标题】:Strange socket behavior in Windws Server 2008Windows Server 2008 中的奇怪套接字行为
【发布时间】:2012-07-05 18:32:17
【问题描述】:

很早以前我就用这段代码的原理做了一个基于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 数据包标头中的Time-To-Live 参数)被设置为 1来自我的服务的所有回复数据包,实际上导致它们在遇到的第一个路由器上被丢弃。

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

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

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

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

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

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

马丁。

【问题讨论】:

    标签: c# .net windows sockets tcp


    【解决方案1】:

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

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

    ...

    为什么是 ReuseAddress 而不是 IpTimeToLive?

    事实上:

    SocketOptionName.IpTimeToLive == SocketOptionName.ReuseAddress == 4

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

    【讨论】:

    • 你看起来很准!实际上,IpTimeToLiveReuseAddress both 的值为 4。但是,为了使系统将 4 解释为 ReuseAddress,必须使用SocketOptionLevel.Socket - 如果他使用SocketOptionLevel.IP,它被解释为IpTimeToLive!结论:我犯了一个编程错误,MS 一切正常(幸运的是!)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多