Как я могу получить количество байтов, доступных для чтения на асинхронном сокете в Linux?

У меня есть простой сервер TCP / IP, написанные на C ++ на Linux. Я использую асинхронные сокеты и epoll. Можно ли узнать, сколько байтов доступно для чтения, когда я получу событие EPOLLIN?

2

Решение

От man 7 tcp:

int value;
error = ioctl(sock, FIONREAD, &value);

Или в качестве альтернативы SIOCINQ, который является синонимом FIONREAD,

Во всяком случае, я бы рекомендовал просто использовать recv в неблокирующем режиме в цикле, пока не вернется EWOULDBLOCK,

ОБНОВИТЬ:

Из ваших комментариев ниже я думаю, что это не подходящее решение для вашей проблемы.

Представьте, что ваш заголовок имеет 8 байтов, а вы получаете только 4; тогда ваш poll/select вернусь EPOLLIN, вы проверите FIONREADПосмотрите, что заголовок еще не завершен и еще больше байтов. Но эти байты никогда не приходят, поэтому вы продолжаете получать EPOLLIN на каждый звонок poll/select и у вас есть неактивная занятая петля. То есть, poll/select являются Уровень запускаемых. Не то, чтобы функция, инициируемая ребром, тоже решала вашу проблему.

В конце вы гораздо лучше выполняете небольшую работу, добавляя буфер для каждого соединения и ставя байты в очередь, пока у вас не будет достаточно. Это не так сложно, как кажется, и работает гораздо лучше. Например, что-то вроде этого:

struct ConnectionData
{
int sck;
std::vector<uint8_t> buffer;
size_t offset, pending;
};

void OnPollIn(ConnectionData *d)
{
int res = recv(d->sck, d->buffer.data() + offset, d->pending);
if (res < 0)
handle_error();
d->offset += res;
d->pending -= res;

if (d->pending == 0)
DoSomethingUseful(d);
}

И всякий раз, когда вы хотите получить количество байтов:

void PrepareToRecv(ConnectionData *d, size_t size)
{
d->buffer.resize(size);
d->offset = 0;
d->pending = size;
}
7

Другие решения

Других решений пока нет …