2011-12-31 2 views
1

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

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

+4

Вы должны сделать это в буферизации внутри вашего приложения, а не просить ядро ​​linux сделать это. –

+0

@Basile Starynkevitch: Ваше предложение невозможно реализовать в моем случае использования. см. *, изданный глубоко внутри библиотеки, которую я не контролирую * в вопросе. – pts

+0

Если вы управляете вызовом «recv» api, то почему вы не можете обернуть эти вызовы своим собственным уровнем буферизации (в соответствии с тем, что сказал Базиле)? Если у вас есть возможность передать MSG_PEEK на вызов recv, вы должны иметь возможность реализовать свою собственную оболочку поверх recv? Правильно? – selbie

ответ

2

То, что я прошу, кажется невозможным. В итоге я вызвал 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 - это обходной путь, поскольку они до сих пор не позволяют мне считывать произвольные байты в сокет. Все, что они мне позволяли, - это заглянуть в уже полученные байты, не потребляя их.

+1

Возможно, вы сможете добавить fd к набору epoll в режиме EPOLLET (edge-triggered), чтобы дождаться N байтов - если вам не нравится то, что вы recv, дождитесь следующего события epoll, прежде чем повторять попытку recv. – anthonyrisinger

+0

@anthonyrisinger: Спасибо, что предложили EPOLLET, он работает так, как вы его описали. – pts

2

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

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

+0

+1, Wow, я никогда раньше не слышал о LD_PRELOAD, приятно знать, что существует (хотя я согласен с вами о лучшем варианте) –

+0

Благодарим вас за предложение 'LD_PRELOAD', это может спасти день в некоторых случаях. Однако в моем случае вывод должен быть статически связанным двоичным кодом, поэтому 'LD_PRELOAD' не имеет никакого значения. – pts

+0

@pts У меня не так много опыта с уловками-линкерами, но вы уверены, что не можете обмануть эту библиотеку, чтобы называть символ своим? – cnicutar

Смежные вопросы