Двусторонняя связь сокетов Unix

Я пытаюсь создать сервер, который устанавливает сокет Unix и прослушивает клиентов, которые отправляют/получают данные. Я создал небольшой репозиторий, чтобы воссоздать проблему.

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

Я закомментировал проблемный код на клиенте и сервер . Раскомментируйте оба, чтобы воссоздать проблему.

Когда код для ответа клиенту раскомментирован, я получаю эту ошибку на сервере:

поток '' запаниковал при 'вызванном Result::unwrap() со значением Err: Os { код: 11, тип: WillBlock, сообщение: ресурс временно недоступен }', src/main.rs:77:42

Ссылка на MRE


person mattlennon3    schedule 08.03.2021    source источник
comment
Трудно ответить на ваш вопрос, потому что он не включает минимально воспроизводимый пример. Мы не можем сказать, какие крейты (и их версии), типы, трейты, поля и т. д. присутствуют в коде. Нам будет легче помочь вам, если вы попытаетесь воспроизвести ошибку на Rust Playground, если возможно, в противном случае в новом проекте Cargo отредактируйте свой вопрос, чтобы включить дополнительную информацию. Существуют советы по MRE для Rust, которые вы можете использовать, чтобы уменьшить исходный код для публикации здесь. Спасибо!   -  person Shepmaster    schedule 08.03.2021
comment
Чтобы сделать Stack Overflow полезным ресурсом для будущих посетителей вне контекста вашего репозитория, отредактируйте свой вопрос, чтобы добавить минимальный воспроизводимый пример в самом вопросе, помимо ссылки на ваш репозиторий.   -  person Shepmaster    schedule 08.03.2021


Ответы (1)


Ваш код вызывает set_read_timeout, чтобы установить время ожидания. на розетке. В его документации указано, что в Unix это приводит к ошибке WouldBlock в случае тайм-аута, что и происходит с вами.

Что касается тайм-аута вашего клиента, вероятной причиной является то, что сервер вызывает stream.read_to_string(&mut response), который считывает поток до конца файла. С другой стороны, ваш клиент вызывает write_all(), за которым следует flush(), и (после раскомментирования кода нарушения) пытается прочитать ответ. Но попытка прочитать ответ означает, что поток не закрыт, поэтому сервер будет ждать EOF, а у вас на руках дедлок. Обратите внимание, что ничего из этого не относится к Rust; у вас будет точно такая же проблема на C++ или Python.

Чтобы решить эту проблему, вам нужно использовать протокол в общении. Очень простой протокол может состоять из отправки сначала размера сообщения (в фиксированном формате, возможно, 4 байта в длину), а только затем фактического сообщения. Код, который читает из потока, будет делать то же самое: сначала считывать размер сообщения, а затем само сообщение. Даже лучше, чем изобретать собственный протокол, было бы использовать существующий, например. для обмена сообщениями с помощью serde.

person user4815162342    schedule 08.03.2021
comment
@Shepmaster По сути, это похоже на одну и ту же проблему, только в деталях - например. код в старом вопросе не смог сбросить BufWriter. - person user4815162342; 08.03.2021
comment
Я собирался перейти к serde, когда дошел до отправки фактических структур данных. Я подумал, что отправку строки будет проще начать с :/. Если я уберу set_read_timeout, я получу ошибку broken pipe. Это потому, что я вызываю .flush() на клиенте, а сервер не находит EOF? Это просто странно, потому что он действительно печатает полученную строку. - person mattlennon3; 08.03.2021
comment
@ mattlennon3 Сломанная труба обычно означает, что запись не удалась, потому что другая сторона отключилась. Трудно сказать, почему это происходит с вами, не видя точный источник, который вы используете. И даже это не стоит потраченных усилий, потому что нынешний подход в корне ошибочен, как утверждается в моем ответе и в ответах на вопросы, на которые Шепмастер ссылается в комментариях. Я предлагаю вместо того, чтобы пытаться спасти несовершенный дизайн, изучить проблему и структурировать свой код вокруг лучшего варианта. - person user4815162342; 08.03.2021
comment
@user4815162342 Вернуться к чертежной доске! Большое спасибо за ваше время. Должен ли я удалить этот вопрос или просто пометить его как ответ? - person mattlennon3; 08.03.2021
comment
@mattlennon3 Это зависит от вас - если вы считаете, что это не улучшает сайт (также в свете предыдущих вопросов, поднятых Шепмастером), не стесняйтесь удалять его. - person user4815162342; 08.03.2021