Одновременно читать и писать в одном и том же сокете на C или С++
Я реализую простой сервер, который принимает одно соединение, а затем использует этот сокет для одновременного чтения и записи сообщений из потоков чтения и записи.
Каков безопасный и простой способ одновременного чтения и записи из одного и того же дескриптора сокета в c/С++ на linux?
Мне не нужно беспокоиться о чтении и записи нескольких потоков из одного и того же сокета, поскольку в сокет будет входить один выделенный поток чтения и одиночный выделенный поток записи.
В приведенном выше сценарии требуется какой-либо блокировки?
Требуется ли в вышеупомянутом сценарии неблокирующий сокет?
Есть ли библиотека с открытым исходным кодом, которая поможет в приведенном выше сценарии?
Ответы
Ответ 1
В приведенном выше сценарии требуется какой-либо блокировки?
Отсутствует.
Требуется ли в вышеупомянутом сценарии неблокирующий сокет?
Бит, о котором вы, вероятно, беспокоитесь - чтение и запись потоков в установленном соединении - не обязательно быть неблокирующимся, если вы довольны тем, чтобы те потоки сидели там, ожидая завершения. Обычно это одна из причин использования потоков, а не выбора или опроса или асинхронных операций... также упрощает код.
Если поток, принимающий новых клиентов, рад заблокировать в вызове accept()
, тогда вы тоже хорошо там.
Тем не менее, есть одна тонкая проблема с TCP-серверами, которые вы, возможно, захотите сохранить в своем сознании... если ваша программа растет, чтобы обрабатывать несколько клиентов и выполнять некоторую периодическую работу. Естественно и заманчиво использовать инструкцию select
с таймаутом для проверки на удобочитаемость в прослушивающем сокете - что указывает на попытку подключения клиента, а затем accept
соединение. Там есть условие гонки: попытка подключения клиента может упасть между select()
и accept()
, и в этом случае accept()
будет блокировать, если прослушивающий сокет не будет блокировать, и это может помешать своевременному возврату в select()
и остановите периодическую обработку по времени, пока не подключится другой клиент.
Есть ли библиотека с открытым исходным кодом, которая поможет в приведенном выше сценарии?
Существует сотни библиотек для написания базовых серверов, но в конечном итоге то, что вы просили, легко достигается на OS-предоставляемых сокетах BSD или их подсистеме Windows.
Ответ 2
Сокеты BI-DIRECTIONAL. Если вы когда-либо на самом деле разбирали кабель Ethernet или Serial или видели для них схему подключения к низкоуровневому оборудованию, на самом деле вы можете увидеть отдельные медные провода для линий передачи "TX" (передача) и "RX" (прием). Программное обеспечение для отправки сигналов от контроллера устройства до большинства OS API для "сокета" отражает это, и это ключевое различие между сокетом и обычным каналом в большинстве систем (например, Linux).
Чтобы получить максимальную отдачу от сокетов, вам необходимо:
1) Поддержка Async IO, которая использует IO Completion Ports, epoll() или некоторую аналогичную систему обратного вызова асинхронного вызова или события для "пробуждения", когда данные поступают в сокет. Затем этот вызов должен вызывать ваш API-интерфейс "ReadData" вашего нижнего уровня, чтобы прочитать сообщение от соединения сокета.
2) Второй API, поддерживающий низкоуровневую запись, "WriteData" (передача), которая толкает байты в сокет и не зависит от чего-либо, что требуется логике "ReadData" . Помните, что ваша передача и получение независимы даже на аппаратном уровне, поэтому не вводите блокировку или другую синхронизацию на этом уровне.
3) Пул потоков Socket IO, который слепо обрабатывает данные, которые считываются или записываются в сокет.
4) PROTOCOL CALLBACK: объект обратного вызова, к которому подключаются потоки сокетов. Он обрабатывает любой слой PROTOCOL, такой как разбор данных blob в реальном HTTP-запросе, который находится поверх основного сокетного соединения. Помните, что сокет - это всего лишь канал данных между компьютерами и переданные по нему данные, которые часто поступают в виде серии фрагментов - пакетов. В таких протоколах, как UDP, пакеты даже не в порядке. Низкоуровневые "ReadData" и "WriteData" будут обращать внимание на их потоки, потому что именно на самом деле начинается обработка информации с содержанием.
5) Любые обратные вызовы, которые сам обработчик протокола. Для HTTP вы помещаете необработанные буферы запросов в красивые объекты, которые вы передаете реальному сервлету, который должен возвращать хороший объект ответа, который может быть сериализован в HTTP-совместимый ответ.
Обратите внимание на базовый шаблон: вы должны сделать всю систему принципиально асинхронной ( "лук обратных вызовов" ), если вы хотите в полной мере использовать двунаправленные, асинхронные IO-сокеты. Единственный способ одновременного чтения и записи в сокет - это потоки, поэтому вы все равно можете синхронизировать поток "писатель" и "читатель", но я бы сделал это, только если протокол или другие соображения заставили мою руку. Хорошей новостью является то, что вы можете получить отличную производительность с помощью сокетов с использованием высокоасинхронной обработки, плохое в том, что создание такой системы надежным способом - это серьезное усилие.
Ответ 3
Вам не о чем беспокоиться. Одно чтение потока и одно нить записи будут работать, как вы ожидаете. Сокеты имеют полный дуплекс, поэтому вы можете читать, пока вы пишете, и наоборот. Вы должны были бы беспокоиться, если бы у вас было несколько авторов, но это не тот случай.