2012-04-20 4 views
2

в систему получил следующую задачу:Проверка на наличие ошибок перед RECV() называемых

Я сделал сервер, который способен обрабатывать несколько подключение с помощью выберите(). Но выбрать возвращает клиент (индекс FD_SET), также если сокет только что получил ошибку, например, «отключение клиента» или что-то еще.

Можно ли проверить розетку без вызова recv(). Потому что получить мне нужно, чтобы получить буфер из моего «BUFFERPOOL»

Пример кода:

int ret = recv(client, buffer_pool->get(), BUFFER_SIZE, 0); 
if(ret == -1) ... // something went wrong 

Ну тогда я должен освободить буфер снова, и это было довольно много отходов одного буфера в моем пуле. (В течение короткого промежутка времени)

Так не возможно проверить сокет без вызова ПРИЕМА()

ответ

0

После нескольких минут работы и вашей помощи я просто получать 1 байт до получения полной суммы:

SOCKET client = ...; 

char temp = 0x00; 
int len = recv(client, &temp, 1, 0); 
if(len == 0) 
{ 
    // .. client error handling 
    return; 
} 

char* buffer = m_memory_pool->Get(); 
len = recv(client, buffer + 1, m_memory_pool->buffer_size() - 1, 0); 
buffer[0] = temp; 

// data handling 
1

Нет, нет никакого способа, чтобы избежать recv() вызова. Если select() сообщает, что сокет читается, вам необходимо прочитать его из сокета, чтобы определить его новое состояние. Если клиент отключен изящно, recv() вернет 0, а не -1. Если вы не хотите тратить пул буферов, вам сначала нужно будет прочитать временный локальный буфер, а затем, если recv() вернет любые данные, вы можете получить объединенный буфер и скопировать в него прочитанные данные.

0

Вызов функции recv и аналогичной функции не работает напрямую с сетевыми устройствами или чем-то подобным. Когда вы отправляете или получаете данные, все, что вы делаете, это допрос ОС для доступных данных или помещать данные в очередь для отправки. Тогда ОС выполнит другое задание, когда ваш код уже пойдет дальше. Вот почему вы получаете ошибки после следующего вызова функции сокета, которые будут «связываться» с сетевыми слоями ОС.

Это нормально, чтобы получить ошибки в этой точке, и вам приходится иметь дело с ними.

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

Кроме того, это не очень хорошая техника для получения большого количества данных за один раз, потому что вы столкнетесь с проблемами с объединенными или разломанными данными через уровень TCP, потому что это потоковый уровень. Рекомендуется иметь заголовок в пакетах (несколько байтов) и получать их, поэтому вам не нужно тянуть для заголовка, но только после заголовка вы хотите прочитать остальное сообщение на основе длины, указанной в заголовке. Это просто пример.

3

Я не уверен в Windows, но с использованием getsockopt() работает как шарм на POSIX-совместимых системах. Хотя прежде, чем вы его используете, убедитесь, что получение буфера из пула дороже, чем дополнительный системный вызов.Вот фрагмент кода:

int my_get_socket_error(int fd) 
{ 
     int err_code; 
     socklen_t len = sizeof(err_code); 

     if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err_code, &len) != 0) 
       err_code = errno; 
     else 
       errno = err_code; 
     return err_code; 
} 

UPDATE:

По this document, похоже, Windows, поддерживает его тоже.

+0

, к сожалению, err_code 0 каждый раз, и если RECV() возвращает 0 (ошибка) – Aurus

+0

@Aurus: если он возвращает 0, а recv возвращает 0, тогда вы, вероятно, получили EOF (т.е. другая сторона закрыла соединение). –

+0

, но они также равны 0, если клиентское соединение все еще живое. – Aurus