Таймаут сокета .NET - блокировка по методу Close - PullRequest
1 голос
/ 04 июня 2010

У меня проблемы с реализацией таймаута подключения с использованием асинхронных вызовов сокетов.

Идея заключается в том, что я вызываю BeginConnect для объекта Socket, а затем использую таймер для вызова Close () в сокете после истечения времени ожидания.

Это прекрасно работает, пока в потоке GUI создается сокет - метод Close немедленно возвращается и выполняется метод обратного вызова. Однако если сокет создается в каком-либо другом потоке, метод Close блокируется, пока не истечет время ожидания IP-адреса по умолчанию.

Код для воспроизведения:

private Socket client;

private void button1_Click(object sender, EventArgs e) {
    // Creating the socket on a threadpool thread causes Close to block.
    ThreadPool.QueueUserWorkItem((object state) => {
        client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        IAsyncResult result = client.BeginConnect(IPAddress.Parse("144.1.1.1"), 23, new AsyncCallback(CallbackMethod), client);

        // Wait for 2 seconds before closing the socket.
        if (result.AsyncWaitHandle.WaitOne(2000)) {
            MessageBox.Show("Connected.");
        } else {
            MessageBox.Show("Timed out. Closing socket...");
            client.Close();
            MessageBox.Show("Socket closed.");
        }
    });
}

private void CallbackMethod(IAsyncResult result) {
    MessageBox.Show("Callback started.");
    Socket client = result.AsyncState as Socket;
    try {
        client.EndConnect(result);
    } catch (ObjectDisposedException) {
    }
    MessageBox.Show("Callback finished.");
}

Если вы удалите строку QueueUserWorkItem, создав сокет в потоке GUI, сокет мгновенно закроется без блокировки.

Может кто-нибудь пролить свет на то, что происходит?
Спасибо.

Редактировать - Вывод трассировки System.Net может отличаться в зависимости от того, подключен ли он к потоку графического интерфейса или к другому потоку:

Ответы [ 2 ]

0 голосов
/ 05 июня 2010

Чего я не могу понять, так это того, почему он немедленно закрывается в потоке графического интерфейса. Я бы попробовал вызвать client.Shutdown () перед вызовом client.Close ().

Я бы также попытался запустить объект сокета в обычном потоке (Thread.Start ()) вместо использования ThreadPool. Таким образом, вы можете сохранить ссылку на поток и вызывать Thread.Interrupt () и / или Thread.Abort () самостоятельно.

0 голосов
/ 05 июня 2010

Вы пытались удалить вызовы "MessageBox.Show", которые у вас есть вокруг вызова Socket.Close ()?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...