Ньюбский вопрос про сокеты в C#

smit1

Имеется тред, ждущий появления данных на нескольких сокетах с помощью Socket.Select. Иногда по некоторому внешнему событию, с сетью никак не связанному (из другого треда надо этот селект прервать, так вот я нифига не понимаю, как можно это сделать. (И, как ни удивительно, гугл не помог) Я, наверно, что-то очевидное упускаю. Или select - это нифига не C# way и есть какой-то альтернативный "правильный" способ решения подобных задач? Ткните куда копнуть.

Dasar

как вариант можно добавить еще один внутренний управляющий сокет. и посылкой в него пакета разблокировать Select

smit1

как вариант можно добавить еще один внутренний управляющий сокет. и посылкой в него пакета разблокировать Select

Да, думал о таком. Коряво. Если ничего лучше нет, то это пиздец, пиздец как странно. (Авторы библиотек С# того же java.nio не видели, что ли?)

Dasar

не видели, конечно.
java.nio - это где-то 2003 год
а Socket.Select - это где-то 1999 год

smit1

А сколько версий фреймворка после 2003 вышло?

Dasar

штуки 4 вышло.
но политика развития .net-а больше в развитии высокоуровневых надстроек, чем в развитии нижнего уровня.

FRider

Или select - это нифига не C# way и есть какой-то альтернативный "правильный" способ решения подобных задач?
asynchronous io.
Socket.BeginRead/Socket.BeginWrite

Dasar

а как ждать ответа допустим от 100 сокетов в одном потоке?

FRider

а как ждать ответа допустим от 100 сокетов в одном потоке?
Это уже вопрос к конкретному приложению. Вообще данная модель предполагает обработку в отдельном потоке из пула в котором запустится AsyncCallback callback, переданный в Begin...
На вскидку могу придумать, что в callback ты добавишь сокет в синхронную очередь, которую обрабатывает твой один поток-процессор. Он там и вызовет EndRead/EndWrite

smit1

asynchronous io.Socket.BeginRead/Socket.BeginWrite
Хочется добиться следующего - если внешнее событие произошло, то данные из сокетов больше не выбираются. Тогда надо как-то уметь отменять уже запущенные асинхронные операции :) Это как-то можно?

FRider

Тогда надо как-то уметь отменять уже запущенные асинхронные операции :) Это как-то можно?
сами операции отменить нельзя, но можно:
1. В callback проверять состояние - произошло ли событие и выходить из коллбека, не читая данные.
2. Если совсем не надо читать, то просто прибить процесс нах :)
3. В моделе с очередью, которую я написал выше, в очереди обработки проверять на событие и там прекращать чтение.

Dasar

согласен. таким образом основные проблемы снимаются.

Dasar

в документации советуют BeginRequest отменять через Close

smit1

1. В callback проверять состояние - произошло ли событие и выходить из коллбека, не читая данные.
Э-э-э... Я, может быть, неправильно докумекнтацию понял, но вроде как коллбэк вызывается, когда данные уже вычитаны из сокета в указанный при старте async-операции буфер, т.е. состояние канала изменилось. Разве не так?

FRider

но вроде как коллбэк вызывается, когда данные уже вычитаны из сокета в указанный при старте async-операции буфер, т.е. состояние канала изменилось. Разве не так?
насколько я помню, то нет. В указанный ТОБОЙ буфер они будут вычитаны после вызова EndRequest(хотя ты конечно перепроверь). Будут ли они вычитаны из сокета в какой либо внутренний буфер - тут хз. А в чем проблема если даже будут вычитаны?

Marinavo_0507

А в чем проблема если даже будут вычитаны?
Ну например, для 1000 сокетов потребуется 1000 буферов - увеличение расхода памяти, неэффективное использование кеша.

FRider

1000 буферов
он их уже выделит, ДО вызова BeginRead/Write
Независимо от того, будут они заполнены или нет

smit1

насколько я помню, то нет. В указанный ТОБОЙ буфер они будут вычитаны после вызова EndRequest(хотя ты конечно перепроверь).
MSDN - ссаное говно, щас поищу по сети чо там точно происходит
Будут ли они вычитаны из сокета в какой либо внутренний буфер - тут хз. А в чем проблема если даже будут вычитаны?
1) Изменилось состояние канала (а я бы, например, хотел, чтобы данные мог вычитать кто-то другой, позже)
2) Ожидание этих данных может потребовать неопределённого количества времени, тогда как я уже знаю, что вот прямо сейчас я их не хочу

FRider

2) Ожидание этих данных может потребовать неопределённого количества времени, тогда как я уже знаю, что вот прямо сейчас я их не хочу
ну тогда закрывай все сокеты Close, как выше написал ДГ, при наступлении события. Тут фишка в том, что после вызова BeginRead ты не тратишь процессорное время, пока данные не прийдут. Т.к. юзается механизм асинхронного ввода-вывода.
1) Изменилось состояние канала (а я бы, например, хотел, чтобы данные мог вычитать кто-то другой, позже)
Вот тут несовсем понятно. Этим другим может быть вроде как только твоя программа(или у нас винда может шарить дескрипторы между процессами?). Так прочти все что есть, по факту наступления события, и сохрани их во внутренний буфер, потом заюзаешь, когда надо. По вызову Close сокет закроется и все данные проебуться.

Dasar

> насколько я помню, то нет. В указанный ТОБОЙ буфер они будут вычитаны после вызова EndRequest(хотя ты конечно перепроверь).
скорее все-таки: гарантированно данные будут вычитаны в буфер при вызове EndRequest
при вызове колбака - часть данных может быть уже в буфере, а часть еще нет.
потому что было бы странно ожидать, что при чтении в гигабайтный буфер, где-то выделится еще один вспомогательный буфер на ГБ

FRider

да, логично. Я просто не очень понимаю чего хочет ТС. На мой взгляд странно оставлять данные в сокете "про запас" и что он имеет ввиду под "состоянием канала". На мой взгляд надо делать так - вычитывать все что есть и обрабатывать, проверяя, не наступило ли событие. Потом все останавливать. Сокеты закрывать. Если нужно будет - то сокеты открывать, клиент должен быть в состоянии реконнкетнуться и послать повторно то, что недообработалось.

smit1

А я не хочу close. Я хочу поддерживать соединения, и спустя какое-то время, по другому стороннему событию, начать получать данные с места остановки.

FRider

Я хочу поддерживать соединения, и спустя какое-то время, по другому стороннему событию, начать получать данные с места остановки.
Есть мнение, что это не есть верная архитектура распределенной системы :) Ты в любом случае должен быть готов к ситуациям обрыва связи.

smit1

Есть мнение, что это не есть верная архитектура распределенной системы Ты в любом случае должен быть готов к ситуациям обрыва связи.
Очень спорно, зависит от конкретной прикладной задачи

FRider

Ну как бе в программировании тогда любая тема спорна :) Однако есть типовые подходы.
Например для сетевой системы стоит предусмотреть ситуацию разрыва связи в любой момент.
И если уж держишь постоянное соединение(что само по себе не самый лучший вариант, хотя и бывает нужный! то будь готов его восстановить.

FRider

и кстати. ТЫ вот прекратил вычитку из своих сокетов по событию, но сокет не закрыл. Твои клиенты будут продолжать слать данные? Так у тебя сетевые буфера переполняться и будет ай-ай-ай. :)

smit1

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

На уровне "сервер не упал и освободил все связанные с данным клиентом ресурсы" - конечно. Что-то большее - зависит от задачи.
И если уж держишь постоянное соединение(что само по себе не самый лучший вариант, хотя и бывает нужный! то будь готов его восстановить.
Во многих весьма и весьма распространённых приложениях проблема реконнекта решается на уровне пользователя, и всех это до сих пор устраивает

FRider

я хотел сказать, что для программы не должно быть столь важно - продолжаешь ты держать сокеты с данными, после того как они тебе "не нужны", или закрыл их, а потом клиенты переконнектились и дослали данные.
А так, пиши как хочешь конечно :)

smit1

и кстати. ТЫ вот прекратил вычитку из своих сокетов по событию, но сокет не закрыл. Твои клиенты будут продолжать слать данные? Так у тебя сетевые буфера переполняться и будет ай-ай-ай.
1) В TCP есть flow control
2) Можно на прикладном уровне иметь соотв протокол

bleyman

Чисто чтобы убить флейм не по теме: то, что ты хочешь, называется polling server. Твоя проблема в том, что ты хочешь обычный юниксовый single-threaded select-dispatch сервер, но при этом у тебя есть какие-то непонятные "внешние события", которые могут прервать как минимум очередной селект, а как максимум — все диспатчнутые в данный момент реквесты. Ну так и расскажи же для начала, откуда появляются "внешние события", например.

Marinavo_0507

но при этом у тебя есть какие-то непонятные "внешние события", которые могут прервать как минимум очередной селект, а как максимум — все диспатчнутые в данный момент реквесты. Ну так и расскажи же для начала, откуда появляются "внешние события", например.
Ну например соседний тред что-то считает на соседних ядрах, и уведомляет об окончании блока расчётов.
Но я бы сделал служебный сокет для таких уведомлений.

Marinavo_0507

он их уже выделит, ДО вызова BeginRead/Write
Независимо от того, будут они заполнены или нет
Ну вот этим и плоха предлагаемая тобой архитектура.

kokoc88

Ну вот этим и плоха предлагаемая тобой архитектура.
Можно поллить с буфером нулевого размера для получения события доступности на чтение.

FRider

Ну вот этим и плоха предлагаемая тобой архитектура.
эта архитектура рекомендуемая мс. Так я с тобой совершенно согласен. Но мы же говорим о конкретно .нет
АПД: Или вон Майк выше предложил нормальную тему
Оставить комментарий
Имя или ник:
Комментарий: