То, что я прошу, кажется невозможным. В итоге я вызвал recv() с флагом MSG_PEEK
. Это приведет к тому, что последующие вызовы recv() или recvmsg() в библиотеке будут считывать одни и те же данные.
Без каких-либо других вызовов я могу использовать его, чтобы удобно смотреть только на один байт. Предположим, мне нужно было смотреть вперед 2 байта. Я бы позвонил recv(fd, buf, 2, MSG_PEEK)
. Если 1 из 2 байтов уже прибыл, то recv вернется немедленно, независимо от того, сколько раз я его называю. Я могу использовать epoll_ctl с EPOLLIN | EPOLLET
, чтобы дождаться 2-го байта. Если я хочу знать, был ли тогда EOF, мне нужно EOPLLIN | EPOLLET | EPOLLRDHUP
. (Обратите внимание, что EPOLLHUP
не будет возвращен на EOF.) Поэтому, используя epoll_ctl
, я могу избежать вызова recv в занятом, опросном цикле, чтобы прочитать 2-й байт.
Я только что проверил в своей системе Linux, что по умолчанию могу посмотреть около 900 кБ на сокет. (SO_RECVBUF
1 МБ для меня по умолчанию, уменьшая его с setsockopt кажется уменьшить, насколько может быть получен, но не на постоянной суммы. Может быть, я уменьшить его слишком поздно?)
Даже сочетание MSG_PEEK
и EPOLLET
- это обходной путь, поскольку они до сих пор не позволяют мне считывать произвольные байты в сокет. Все, что они мне позволяли, - это заглянуть в уже полученные байты, не потребляя их.
Вы должны сделать это в буферизации внутри вашего приложения, а не просить ядро linux сделать это. –
@Basile Starynkevitch: Ваше предложение невозможно реализовать в моем случае использования. см. *, изданный глубоко внутри библиотеки, которую я не контролирую * в вопросе. – pts
Если вы управляете вызовом «recv» api, то почему вы не можете обернуть эти вызовы своим собственным уровнем буферизации (в соответствии с тем, что сказал Базиле)? Если у вас есть возможность передать MSG_PEEK на вызов recv, вы должны иметь возможность реализовать свою собственную оболочку поверх recv? Правильно? – selbie