4

When I compile this code on a machine with Windows 7 Ultimate and .NET 4 installed, it works just fine but when I try it on one with Windows 8 RTM and .NET 4.5 installed, Complete event never fires.

class Program
{
    private static Socket _Socket = new Socket(
        AddressFamily.InterNetwork,
        SocketType.Stream,
        ProtocolType.Tcp);

    private static void Main(string[] args)
    {
        _Socket.Bind(new IPEndPoint(IPAddress.Any, 5012));
        _Socket.Listen(100);

        var arguments = new SocketAsyncEventArgs();
        arguments.Completed += OnAccepted;
        Accept(arguments);

        Console.ReadLine();
    }

    private static void Accept(SocketAsyncEventArgs args)
    {
        args.AcceptSocket = null;
        if (!_Socket.AcceptAsync(args))
            OnAccepted(null, args);
    }

    private static void OnAccepted(object sender, SocketAsyncEventArgs e)
    {
        Console.WriteLine("Accepted.");
        Accept(e);
    }
}

The interesting thing here is if I put a breakpoint at this line and debug it:

var arguments = new SocketAsyncEventArgs();

And connect this server using Hercules before continuing execution, it works like a charm. I do this at the start and then magically, OnAccepted gets called and writes "Accepted." to the console on every single connection. I use the same code and same program (Hercules) on the machine with Windows 7 and .NET 4 but it always works.

  • Am I doing something wrong?
  • If not, is it a known bug of my OS or .NET Framework version 4.5?
  • Can anyone reproduce this?

Edit: Both operating systems are 64 bit.
Edit 2: I reported this as a bug on Microsoft Connect, here.
Edit 3: Found a workaround and post it to Connect (Simply by creating a fake, first connection).
Edit 4: If anyone can reproduce this, please join the issue in Connect.
Edit 5: I saw the question Thomas has mentioned and I tested whether Console.ReadLine was causing this or not. Turned out it was. If I add Thread.Sleep(3000) before my Console.ReadLine call and make a connection attempt in 3 seconds after I run the program, it works like a charm. Again, the odd thing is that I need to do this only once before calling Console.ReadLine. If I make one connection before calling Console.ReadLine then every consecutive connection works, even after Console.ReadLine is called. I'll mention this in the Conect page.
Edit 6: I added the link to the other question to the Connect page and added another workaround that involves calling Thread.Sleep before calling Console.ReadLine like I mentioned in the above edit.

4

1 に答える 1

1

Windows 8 のバグであることが判明しました。これまでに見つけた最善の回避策は、別のスレッドで IOCP 操作を開始することです。

したがって、質問に示されているコード サンプルで行うべきことは、次の行を変更することです。

Accept(arguments);

メソッドのこの行にMain:

Task.Run(() => Accept(arguments)).Wait();

これによりConsole.ReadLine()、IOCP 操作をブロックする呼び出しが防止されます。

余談ですが、これはオペレーティング システムのバグに対する単なる回避策であり、更新によって修正される可能性が高く、この回避策が不要になることを願っています。

この問題は、最新バージョンの Windows 8 で修正されています。


編集: Connect に投稿したフィードバック アイテムのステータスが"By Design" に変更されました。
また、次の内容の電子メールも受け取りました。

この動作の根本的な問題は、Windows 8 での IO 完了ポートの処理方法に関係しています。.NET は完了ポートを使用して動作します。それらの動作が変更されたとき、.NET の動作も変更されました。

編集 2:フィードバックのステータスは、詳細なしで「アクティブ」に再度変更されます。

編集 3:フィードバックはマイクロソフトから別の回答を受け取り、次のように述べています。

Windows 8 の最新バージョンでは、これが修正されているはずです。これは .NET の問題ではなく、OS の問題であることに注意してください。最新バージョンの OS を使用していることを確認する必要があります。この問題を引き起こしたり修正したりするための .NET への変更は行われていません。」

于 2012-11-09T13:55:20.367 に答える