问题
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.
回答1:
It turned out to be a Windows 8 bug. Best workaround I could find so far is to start the IOCP operation on a different thread.
So the thing I should do in the code sample that is given in the question is changing this line:
Accept(arguments);
To this line in the Main
method:
Task.Run(() => Accept(arguments)).Wait();
This prevents Console.ReadLine()
call to block the IOCP operation.
As a side note: This is just a workaround to an operating system bug which will most likely be fixed via an update and -hopefully- making this workaround redundant.
This issue is fixed with the latest version of Windows 8.
Edit: Status of the feedback item I have posted in Connect is changed to "By Design".
I also received an e-mail which contains the following:
The underlying issue for this behavior has to do with how IO Completion Ports are handled in Windows 8. .NET works using the completion ports; when their behavior changed, so did the .NET behavior.
Edit 2: Status of the feedback is changed again to "Active" with no details.
Edit 3: The feedback received another answer from Microsoft, stating:
The latest version of Windows 8 should have this fixed. Note that it's an OS issue, not a .NET issue: you need to make sure you have the latest version of the OS. No changes were made to .NET to either cause or fix this issue."
来源:https://stackoverflow.com/questions/12145378/socketasynceventargs-completed-doesnt-fire-in-windows-8