Блокирующие сокеты
От: artgonch  
Дата: 02.08.04 08:27
Оценка:
Здравствуйте!
Только начал разбираться с сокетами, и возник такой вопрос.
Я использую блокирующий сокет. Посылаю данные серверу, он мне отвечает. Ответа я жду с помощью метода Receive. Тут все в порядке. Вот кусок кода:

int len;
while ((len = s.Receive(buf)) > 0)
{
....
}


При последнем вызове этого метода сокет блокируется, хотя больше данных не должно приходить. Если же использовать неблокирующий сокет, то можно и проскочить, не дождавшись ответа. А первый раз подождать надо, потому что ответ гарантирован.
Здесь есть стандартное решение, которое известно всем, но я что-то туплю.
Заранее спасибо.
Re: Блокирующие сокеты
От: DimV Россия  
Дата: 02.08.04 08:42
Оценка:
Здравствуйте, artgonch, Вы писали:

A>При последнем вызове этого метода сокет блокируется, хотя больше данных не должно приходить.


Но ведь вы же должны знать, что больше ничего не должно приходить и соответсвенно можно просто выйти из while.

A>Если же использовать неблокирующий сокет, то можно и проскочить, не дождавшись ответа.


Почему же, в случае неблокирующего сокета все в ваших руках, делать select в том же цикле и анализировать его результаты.
Re[2]: Блокирующие сокеты
От: artgonch  
Дата: 02.08.04 11:51
Оценка:
Здравствуйте, DimV, Вы писали:

DV>Здравствуйте, artgonch, Вы писали:


A>>При последнем вызове этого метода сокет блокируется, хотя больше данных не должно приходить.


DV>Но ведь вы же должны знать, что больше ничего не должно приходить и соответсвенно можно просто выйти из while.


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

A>>Если же использовать неблокирующий сокет, то можно и проскочить, не дождавшись ответа.


DV>Почему же, в случае неблокирующего сокета все в ваших руках, делать select в том же цикле и анализировать его результаты.

Попробую обойтись без select. У него слишком большая мощь для моей задачки.
Re[3]: Блокирующие сокеты
От: Andrbig  
Дата: 02.08.04 12:04
Оценка:
Здравствуйте, artgonch, Вы писали:

A>Нет, я имел в виду те случаи, когда либо размер буфера больше размера принимаемых данных, либо данные целиком умещаются. При этом метод вернет значение, большее нуля. Но его повторный вызов заблокирует сокет, т. к. данные больше не приходят.


Socket.Available — не?
Re[4]: Блокирующие сокеты
От: DimV Россия  
Дата: 02.08.04 12:29
Оценка:
Здравствуйте, Andrbig, Вы писали:

A>Здравствуйте, artgonch, Вы писали:


A>>Нет, я имел в виду те случаи, когда либо размер буфера больше размера принимаемых данных, либо данные целиком умещаются. При этом метод вернет значение, большее нуля. Но его повторный вызов заблокирует сокет, т. к. данные больше не приходят.


A>Socket.Available — не?


Да.
Еще вариант делать чтение с флагом Peek.
Re[4]: Блокирующие сокеты
От: artgonch  
Дата: 02.08.04 15:31
Оценка:
Здравствуйте, Andrbig, Вы писали:

A>Здравствуйте, artgonch, Вы писали:


A>>Нет, я имел в виду те случаи, когда либо размер буфера больше размера принимаемых данных, либо данные целиком умещаются. При этом метод вернет значение, большее нуля. Но его повторный вызов заблокирует сокет, т. к. данные больше не приходят.


A>Socket.Available — не? :)

Но, если я пароверю своцство Available, а данные еще не пришли, то я опять проскочу мимо. Или придется крутиться в цикле. А ведь это потеря процессорного времени. Нужен такой способ, чтобы операционная система блокировала нить (блокирующий сокет), но при этом послкдний холостой вызов Receive не блокирвал нить. Или так сделать нельзя?
Re[5]: Блокирующие сокеты
От: artgonch  
Дата: 02.08.04 15:34
Оценка:
Здравствуйте, DimV, Вы писали:


DV>Да.

DV>Еще вариант делать чтение с флагом Peek.

А как потом удалить данные, которые я уже скопировал в свой буффер?
Re[5]: Блокирующие сокеты
От: Sergino Россия  
Дата: 02.08.04 15:44
Оценка:
Здравствуйте, artgonch, Вы писали:

A>>Socket.Available — не?

A>Но, если я пароверю своцство Available, а данные еще не пришли, то я опять проскочу мимо. Или придется крутиться в цикле. А ведь это потеря процессорного времени. Нужен такой способ, чтобы операционная система блокировала нить (блокирующий сокет), но при этом послкдний холостой вызов Receive не блокирвал нить. Или так сделать нельзя?

А как сокет определит, будут еще данные приходить или уже нет? Блокирующие сокеты можно использовать, только если ты заранее знаешь, сколько данных будет. И то это не совсем правильно, так как если отправляющий конец по какой-то причине отвалится, ты будешь бесконечно ждать ответа. Правильным решением при использовании блокирующих сокетов было бы создание таймаутов. Хотя я например вообще против использования блокирующих сокетов.
Re[6]: Блокирующие сокеты
От: DimV Россия  
Дата: 02.08.04 15:56
Оценка:
Здравствуйте, artgonch, Вы писали:

A>Здравствуйте, DimV, Вы писали:



DV>>Да.

DV>>Еще вариант делать чтение с флагом Peek.

A>А как потом удалить данные, которые я уже скопировал в свой буффер?


Peek использовать только для проверки есть буфере что-нибудь или нет а читать как обычно. Правда такой подход не рекомендуется применять.

Можно чтение с блокирующим сокетом поместить в отдельный поток.

Но все таки проще использовать неблокирующие, там сложностей же абсолютно никаких нет.
Re[7]: Блокирующие сокеты
От: artgonch  
Дата: 03.08.04 02:59
Оценка:
Здравствуйте, DimV, Вы писали:

DV>Здравствуйте, artgonch, Вы писали:


A>>Здравствуйте, DimV, Вы писали:



DV>>>Да.

DV>>>Еще вариант делать чтение с флагом Peek.

A>>А как потом удалить данные, которые я уже скопировал в свой буффер?


DV>Peek использовать только для проверки есть буфере что-нибудь или нет а читать как обычно. Правда такой подход не рекомендуется применять.

А если я передам в метод Receive нулевую ссылку на бефер, 0 байтов для чтения и флаг Peek, буде ли это правильно?

DV>Можно чтение с блокирующим сокетом поместить в отдельный поток.

У меня он и работает в отдельном потоке. Вот как я хочу сделать:

Byte[] buf = new Byte[ 1024 ];
s.Receive(buf,           // Buffer
     0,                  // Прочиать 0 байт
     SocketFlags.Peek);  // Не удалять из буфреа
int len = 0;
int total = s.Available;
while ((len + s.Receive(buf)) < total)
{
...
}



DV>Но все таки проще использовать неблокирующие, там сложностей же абсолютно никаких нет.

А можно привести простой пример? Буду очень рад и благодарен.
Re[8]: Блокирующие сокеты
От: Андрюха  
Дата: 03.08.04 08:46
Оценка:
Здравствуйте, artgonch, Вы писали:

Я сделал так(хотя некоторые критикуют такой подход):

DateTime    dtStopWaiting = DateTime.Now.AddMinutes(1);
while ((handler.Available == 0) && ( dtStopWaiting.CompareTo(DateTime.Now) >= 0 ) )
{
       Thread.Sleep(50);
}

int    bytesAvailable = handler.Available;
                
while (bytesAvailable > 0)
{
        byte[] bytes = new byte[1024];
        int bytesRec = handler.Receive(bytes);
        bytesAvailable -= bytesRec;
    data += Encoding.UTF8.GetString(bytes,0,bytesRec);
}
myLog.WriteEntry( String.Format("Received data: {0} , data), EventLogEntryType.Information);
Re[9]: Блокирующие сокеты
От: artgonch  
Дата: 03.08.04 11:10
Оценка:
Здравствуйте, Андрюха, Вы писали:

А>Здравствуйте, artgonch, Вы писали:


А>Я сделал так(хотя некоторые критикуют такой подход):


А>
А>DateTime    dtStopWaiting = DateTime.Now.AddMinutes(1);
А>while ((handler.Available == 0) && ( dtStopWaiting.CompareTo(DateTime.Now) >= 0 ) )
А>{
А>       Thread.Sleep(50);
А>}

А>int    bytesAvailable = handler.Available;
                
А>while (bytesAvailable > 0)
А>{
А>        byte[] bytes = new byte[1024];
А>        int bytesRec = handler.Receive(bytes);
А>        bytesAvailable -= bytesRec;
А>    data += Encoding.UTF8.GetString(bytes,0,bytesRec);
А>}
А>myLog.WriteEntry( String.Format("Received data: {0} , data), EventLogEntryType.Information);

А>


А что в нем неправильного? По-моему накладные расходы времени процессора минимальны. Но ведь насколько я понимаю, протокол TCP сам реализует систему таймаутов и проверок. Зачем же жедать это самому?
А какого типа объект myLog?
Re[10]: Блокирующие сокеты
От: Андрюха  
Дата: 04.08.04 09:01
Оценка:
Здравствуйте, artgonch, Вы писали:


A>А что в нем неправильного? По-моему накладные расходы времени процессора минимальны. Но ведь насколько я понимаю, протокол TCP сам реализует систему таймаутов и проверок. Зачем же жедать это самому?

A>А какого типа объект myLog?

myLog к сокетам не относится — это объект типа EventLog.
Просто я встречал замечания, что использовать Available не совсем "прилично" с блокирующими сокетами.
А таймауты я сделал потому, что заметил когда данные уже получены, Available еще некоторое время продолжает быть равным 0. Так что после того как данные получены я жду пока размер данных станет доступным.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.