SocketAsyncEventArgs.Completed не срабатывает в Windows 8

Когда я компилирую этот код на компьютере с установленными Windows 7 Ultimate и .NET 4, он работает просто отлично, но когда я пытаюсь выполнить его на компьютере с установленными Windows 8 RTM и .NET 4.5, событие Complete никогда не срабатывает.

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);
    }
}

Здесь интересно, если я поставлю точку останова на эту строку и отлажу ее:

var arguments = new SocketAsyncEventArgs();

Подключите этот сервер с помощью Hercules до продолжая выполнение, это работает как шарм. Я делаю это в начале, а затем волшебным образом вызывается OnAccepted и пишет «Принято». в консоль при каждом подключении. Я использую тот же код и ту же программу (Hercules) на машине с Windows 7 и .NET 4, но она всегда работает.

  • Я делаю что-то неправильно?
  • Если нет, то является ли это известной ошибкой моей ОС или .NET Framework версии 4.5?
  • Кто-нибудь может воспроизвести это?

Изменить: обе операционные системы 64-разрядные.
Изменить 2: я сообщил об этом как об ошибке в Microsoft Connect, здесь.
Редактировать 3: найти обходной путь и опубликовать его в Connect (просто создав поддельное первое подключение).
Редактировать 4< /strong>: Если кто-то может воспроизвести это, присоединитесь к проблеме в Connect.
Редактировать 5: я видел вопрос, упомянутый Томасом, и я проверил, вызывает ли это Console.ReadLine или нет. Оказалось, что это было. Если я добавлю Thread.Sleep(3000) перед моим вызовом Console.ReadLine и сделаю попытку подключения через 3 секунды после запуска программы, это сработает как шарм. Опять же, странно то, что мне нужно сделать это только один раз перед вызовом Console.ReadLine. Если я сделаю одно соединение перед вызовом Console.ReadLine, то все последующие соединения будут работать, даже после вызова Console.ReadLine. Я упомяну об этом на странице подключения.
Редактировать 6: я добавил ссылку на другой вопрос на страницу подключения и добавил еще один обходной путь, который включает вызов Thread.Sleep перед вызовом Console.ReadLine, как я упоминал в вышеуказанное редактирование.


person Şafak Gür    schedule 27.08.2012    source источник
comment
Вы проверили, что это не просто брандмауэр / и т. д.? Работает ли это с Socket.Accept? (моя точка зрения здесь: это проблема с AcceptAsync или вообще с сетью?)   -  person Marc Gravell    schedule 27.08.2012
comment
@Marc: Принять работы. AcceptAsync тоже работает, но только если я пытаюсь подключиться до вызова AcceptAsync. Странная вещь делает, что исправляет все. Все последующие соединения работают без проблем, если я просто ставлю точку останова после Listen и перед AcceptAsync. Когда выполнение остановилось, я просто подключаюсь к этому сокету с помощью Hercules и нажимаю F5: Bang, каждое последующее подключение работает как шарм.   -  person Şafak Gür    schedule 27.08.2012
comment
Мне не ясно одно: в случае, когда Completed никогда не срабатывает, OnAccept все еще вызывается?   -  person Peter Ritchie    schedule 14.09.2012
comment
@Peter: Нет. AcceptAsync возвращает true, поэтому код не вызывает OnAccepted синхронно, а новые подключения не запускают событие Completed, поэтому OnAccepted не вызывается в этом экземпляре.   -  person Şafak Gür    schedule 15.09.2012
comment
У меня та же проблема, что обсуждалась здесь: stackoverflow.com/questions/12464185/ Присоединится к Microsoft Connect   -  person TJF    schedule 17.09.2012
comment
@Thomas: Спасибо, я обновил это после того, как увидел ваш вопрос, и я собираюсь обновить проблему в Connect через минуту.   -  person Şafak Gür    schedule 18.09.2012
comment
У меня такая же проблема с .Net4 с VS2012 и запуском на Win8RTM. Чтобы выполнить задачу AcceptAsync, мне нужно активировать/переключиться в окно, содержащее серверный процесс.   -  person Monroe Thomas    schedule 09.11.2012


Ответы (1)


Оказалось, что это ошибка Windows 8. Лучший обходной путь, который я смог найти, — запустить операцию IOCP в другом потоке.

Итак, то, что я должен сделать в примере кода, приведенном в вопросе, меняет эту строку:

Accept(arguments);

К этой строке в методе Main:

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

Это предотвращает вызов Console.ReadLine() для блокировки операции IOCP.

В качестве примечания: это всего лишь обходной путь для ошибки операционной системы, которая, скорее всего, будет исправлена ​​​​через обновление и, надеюсь, сделает этот обходной путь излишним.

Эта проблема исправлена ​​в последней версии Windows 8.


Изменить: статус элемента отзыва, который я разместил в Connect изменено на "By Design".
Я также получил электронное письмо, содержащее следующее:

Основная проблема такого поведения связана с тем, как порты завершения ввода-вывода обрабатываются в Windows 8. .NET работает с использованием портов завершения; когда изменилось их поведение, изменилось и поведение .NET.

Изменить 2: статус отзыва снова меняется на "Активный" без подробностей.

Редактировать 3: На отзыв был получен еще один ответ от Microsoft, в котором говорилось:

В последней версии Windows 8 это должно быть исправлено. Обратите внимание, что это проблема ОС, а не проблема .NET: вам нужно убедиться, что у вас установлена ​​последняя версия ОС. В .NET не было внесено никаких изменений, которые могли бы вызвать или устранить эту проблему».

person Şafak Gür    schedule 09.11.2012
comment
есть ли официальный отчет об ошибке Microsoft, который кто-либо может отслеживать публично? - person mizi_sk; 07.01.2013
comment
@mizi_sk: Я ничего не нашел. Я нашел ссылку на MS Connect, упомянутую в это сообщение на форуме TechNet, но оно больше не работает. На той же странице Лен Холгейт прокомментировал ответ Microsoft, поскольку мы передали это команде базовой ОС, и они учтут это для будущего обновления. Я решаю это отложить. так что нет точной даты или активного отчета об ошибке, чтобы отслеживать afaik. - person Şafak Gür; 08.01.2013
comment
@mizi_sk: Они закрыли дело, заявив, что такое поведение является преднамеренным. - person Şafak Gür; 27.02.2013
comment
@mizi_sk: Проблема исправлена ​​​​с обновлением до Windows 8. Я отредактировал ответ с подробностями. - person Şafak Gür; 02.11.2013