У меня есть простой сервер TCP / IP, написанные на C ++ на Linux. Я использую асинхронные сокеты и epoll. Можно ли узнать, сколько байтов доступно для чтения, когда я получу событие EPOLLIN?
От 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;
}
Других решений пока нет …