Непрочитано (unget) для сокета BSD? - PullRequest
1 голос
/ 31 декабря 2011

Моя программа на C прочитала (используя read (2) или recv (2) ) несколько байтов из сокета TCP в Linux. Можно ли отодвинуть эти байты назад, чтобы последующие вызовы read (2) и recv (2) (издаваемые глубоко внутри библиотеки, которой я не управляю) будут читать их снова

Я знаю о MSG_PEEK флаге recv (2) , и я собираюсь использовать его в качестве обходного пути, если откат назад оказывается невозможным.

Ответы [ 2 ]

2 голосов
/ 15 января 2012

То, что я прошу, кажется невозможным. В итоге я вызвал recv () с флагом MSG_PEEK. Это заставит последующие вызовы recv () или recvmsg () в библиотеке читать те же данные.

Без каких-либо других вызовов я могу использовать его для удобного просмотра только одного байта. Давайте предположим, что мне нужно посмотреть вперед 2 байта. Я бы позвонил recv(fd, buf, 2, MSG_PEEK). Если 1 из 2 байтов уже прибыл, то recv немедленно вернется, независимо от того, сколько раз я его называю. Я могу использовать epoll_ctl с EPOLLIN | EPOLLET для ожидания второго байта. Если я хочу узнать, был ли EOF впоследствии, мне нужно EOPLLIN | EPOLLET | EPOLLRDHUP. (Обратите внимание, что EPOLLHUP не будет возвращено в EOF.) Поэтому, используя epoll_ctl, я могу избежать вызова recv в занятом цикле опроса для чтения 2-го байта.

Я только что проверил в своей системе Linux, что по умолчанию я могу посмотреть примерно 900 КБ в сокет. (SO_RECVBUF для меня составляет 1 МБ по умолчанию, уменьшение его с помощью setsockopt , кажется, уменьшает, сколько можно получить, но не на постоянную сумму. Может быть, я уменьшу это слишком поздно?)

Даже комбинация MSG_PEEK и EPOLLET - это обходной путь, потому что они все еще не позволяют мне читать непроизвольные байты в сокете. Все, что они позволяют мне, - это смотреть уже прибывшие байты, не потребляя их.

2 голосов
/ 31 декабря 2011

Лучшим вариантом будет изменить рабочий процесс так, чтобы вам не нужно было читать, а затем возвращать данные назад. Просто кажется уродливым читать что-то дважды (я согласен, что это может быть законно).

Но если это невозможно или очень сложно, вы можете перехватить системные вызовы read и recv, используя LD_PRELOAD (dlsym).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...