Модераторы: feodorv

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Сокеты: виснет recv 
:(
    Опции темы
Alca
Дата 24.6.2009, 00:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3993
Регистрация: 14.6.2006

Репутация: 1
Всего: 50



Работаю с POP3. Если получен весь ответ сервера (т.е. строка [server_answer\r\n]), то recv виснет, а потом отваливается по таймауту (:recv возвращяет 0). Можно как-то отловить конец ответки - "\r\n"?
Что здесь можно сделать? Желательно без BOOST.
Код

std::string sRecvBytes() {   
    std::string  sRes      = "";
  
    const size_t cuiInSize = 20;
    std::string  sIn(cuiInSize, '\0');

    for (;;) {   
        INT iRes = ::recv(&sIn[0], cuiInSize, 0);   //здесь виснет
        assert(iRes >= 0);
        if (0 == iRes) {
            break;
        }    

        sRes.append( std::string(sIn.begin(), sIn.begin() + iRes) );
    } 

    return sRes;    


Такая же проблема http://www.cyberforum.ru/visual-cpp/thread11542.html


--------------------
PM WWW ICQ Skype Jabber   Вверх
Lazin
Дата 24.6.2009, 05:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3820
Регистрация: 11.12.2006
Где: paranoid oil empi re

Репутация: 5
Всего: 154



оно не виснет, оно ждет, передающая сторона скорее всего передает меньше 20 байт
PM MAIL Skype GTalk   Вверх
Alca
Дата 24.6.2009, 08:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3993
Регистрация: 14.6.2006

Репутация: 1
Всего: 50



Цитата

оно не виснет, оно ждет, передающая сторона скорее всего передает меньше 20 байт

Я согласен, так оно и есть. Мне надо, чтоб ::recv сразу вернула управление программы, а не ждало.


--------------------
PM WWW ICQ Skype Jabber   Вверх
azesmcar
Дата 24.6.2009, 08:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 3
Всего: 211



Цитата(Alca @  24.6.2009,  08:49 Найти цитируемый пост)
Я согласен, так оно и есть. Мне надо, чтоб ::recv сразу вернула управление программы, а не ждало. 

используй неблокирующий сокет.
Код

//ulong_t mode = 0; //blocking mode
ulong_t mode = 1; //non-blocking mode
ioctlsocket( socket, FIONBIO, &mode );

PM   Вверх
Alca
Дата 24.6.2009, 09:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3993
Регистрация: 14.6.2006

Репутация: 1
Всего: 50



Типа так?
Код

std::string CXTcpClientSocket::sRecvBytes() {   
    std::string  sRes      = "";
    INT          iRes      = SOCKET_ERROR;   
    BOOL         bRes      = FALSE;   
    const size_t cuiInSize = 20;
    std::string  sIn(cuiInSize, '\0');
    
    //установка величины таймаута
    timeval      ReceiveTimeout = {0};
    ReceiveTimeout.tv_sec  = 2;
    ReceiveTimeout.tv_usec = SOCKET_TIMEOUT;              

    fd_set fds = {0};
    FD_ZERO(&fds);
    FD_SET(m_puiSocket, &fds);
    
    
    for (;;) {   
        //entering non blocking
        ULONG block = 1;
        iRes = ::ioctlsocket(m_puiSocket, FIONBIO, (ULONG FAR*) &block);
        assert(0 == iRes);
        
        iRes = ::select(0, &fds, NULL, NULL, &ReceiveTimeout);
        if (0 == iRes) {
            break;
        }
        
        iRes = ::recv(m_puiSocket, &sIn[0], cuiInSize, 0);  
        assert(iRes >= 0);
        if (0 == iRes) {
            break;
        }    

        sRes.append( std::string(sIn.begin(), sIn.begin() + iRes) );
    } 

    return sRes;    



Добавлено @ 09:49
Какой порядок вызовов:
Цитата

::ioctlsocket
::select
::rcv
 ???

Это сообщение отредактировал(а) Alca - 24.6.2009, 09:53


--------------------
PM WWW ICQ Skype Jabber   Вверх
azesmcar
Дата 24.6.2009, 09:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 3
Всего: 211



Alca

Установить можно 1 раз, после accept -а, он таким и останется.
PM   Вверх
Alca
Дата 24.6.2009, 09:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3993
Регистрация: 14.6.2006

Репутация: 1
Всего: 50



Цитата

после accept -а

accept -а у меня нет.

Добавлено через 3 минуты и 20 секунд
::ioctlsocket после этого? после того как создал сокет?
Код

m_puiSocket = ::socket(iAf, iType, iProtocol);  
/*... ::ioctlsocket ... ???*/




--------------------
PM WWW ICQ Skype Jabber   Вверх
azesmcar
Дата 24.6.2009, 09:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 3
Всего: 211



Alca

не важно где, можно устанавливать 1 раз, после этого сокет станет неблокирующим.
PM   Вверх
GrayCardinal
Дата 24.6.2009, 15:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Фигасе
****


Профиль
Группа: Завсегдатай
Сообщений: 3039
Регистрация: 9.11.2003

Репутация: 3
Всего: 58



Код

__export int DIONREAD (int fd)
{
    int ret = -1;
    if (ioctl (fd, FIONREAD, &ret) != 0)
        return -1;
    return ret;
}

Вертает количество доступных байт для чтения... В топку неблокирующие сокеты...

Это сообщение отредактировал(а) GrayCardinal - 24.6.2009, 15:10


--------------------
PM MAIL WWW   Вверх
Alca
Дата 24.6.2009, 17:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3993
Регистрация: 14.6.2006

Репутация: 1
Всего: 50



Цитата

Вертает количество доступных байт для чтения... В топку неблокирующие сокеты..

Прикольно


--------------------
PM WWW ICQ Skype Jabber   Вверх
fry
Дата 24.6.2009, 17:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 257
Регистрация: 4.10.2006

Репутация: нет
Всего: 3



Цитата

__export int DIONREAD (int fd)
{
    int ret = -1;
    if (ioctl (fd, FIONREAD, &ret) != 0)
        return -1;
    return ret;
}

Вертает количество доступных байт для чтения... В топку неблокирующие сокеты...


В топку тогда еще и ioctl с дополнительным системным вызовом.
PM MAIL   Вверх
SVN74
Дата 25.6.2009, 00:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 740
Регистрация: 5.5.2008
Где: Комсомольск на Дн епре

Репутация: 1
Всего: 18



Вот есть маленький примерчик (рабочий) принятия сообщений...
=====================================================
Код

bool TSockTCPServer::SendTCPMessage(SOCKET inSock, char* Buff)
{
    if(Buff == NULL) return false;
    if(strlen(Buff)==0) return false;
    int ChCount = strlen(Buff);
    if(!SendINT(inSock,&ChCount))
     {
        return false;
     }
    if(WriteBytesFull(inSock,Buff,ChCount) != ChCount)
     {
        return false;
     }
  return true;
}
//---------------------
bool TSockTCPServer::RecvTCPMessage(SOCKET inSock, char* Buff)
{
    if(Buff == NULL) return false;
    int ChCount = 0;
    if(!RecvINT(inSock,&ChCount))
     {
        return false;
     }
     memset(Buff,0,ChCount);
     if(ReadBytesFull(inSock,Buff,ChCount)!=ChCount)
     {
       return false;
     }
     Buff[ChCount] = 0;
  return true;
}
//---------------------------
int TSockTCPServer::ReadBytesFull(SOCKET inSock, char* Buff, int SizeBuff)
{
    if(Buff == NULL) return false;
    int rc;
    int x=0;
        memset(&Buff[0],0,SizeBuff);
        while(SizeBuff > 0)
        {
            rc = recv(inSock, &Buff[x], SizeBuff,0);
            if(rc == SOCKET_ERROR)
            {
               strcpy(ErrMess,GetWsaError());
               return rc;
            }
            if(rc == 0)    break;
           x += rc;
           SizeBuff -= rc;
        }
return x;
}

PM MAIL WWW   Вверх
Alca
Дата 25.6.2009, 10:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3993
Регистрация: 14.6.2006

Репутация: 1
Всего: 50



Можно по-подробнее про дополнительные системные вызова?


--------------------
PM WWW ICQ Skype Jabber   Вверх
vinick
Дата 25.6.2009, 13:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 285
Регистрация: 9.6.2005

Репутация: 6
Всего: 22



Цитата(Alca @  25.6.2009,  10:06 Найти цитируемый пост)
Можно по-подробнее про дополнительные системные вызова? 

При неблокирующих сокетах и select(), за один системный вызов можно проверить состояние множества сокетов. При использовании ioctl(FIONREAD), придется для каждого сокета делать системный вызов. 

При использовании select, процесс спит до наступления события. При использовании ioctl придется самому усыплять или как-то иначе занимать процесс и самому ловить момент когда сделать вызов.

Системный вызов это дорогая операция и лишний раз ее лучше не делать.
PM MAIL ICQ Jabber   Вверх
GrayCardinal
Дата 25.6.2009, 13:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Фигасе
****


Профиль
Группа: Завсегдатай
Сообщений: 3039
Регистрация: 9.11.2003

Репутация: 3
Всего: 58



vinick
Кто мешает делать select + FIONREAD на блокирующих ?

Добавлено через 2 минуты и 25 секунд
vinick
ИМХО, ты бредишь  smile  

Это сообщение отредактировал(а) GrayCardinal - 25.6.2009, 13:17


--------------------
PM MAIL WWW   Вверх
Alca
Дата 25.6.2009, 13:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3993
Регистрация: 14.6.2006

Репутация: 1
Всего: 50



Бывает такое, что функция возвращяет пустую строку.
При дисконнекте POP3 сервера, сокет (::recv) не успееват получить ответ, т.е. ответка сервака не приходит.
Что делать?
Код

std::string CXTcpClientSocket::sRecvBytes(INT iFlags) {   
    std::string  sRes      = "";
    INT          iRes      = SOCKET_ERROR;   
    BOOL         bRes      = FALSE;   
    const size_t cuiInSize = 20;
    std::string  sIn(cuiInSize, '\0');

    //-------------------------------------
    //enter non blocking
    ULONG ulNonblockingMode = (ULONG)TRUE;
    bRes = ::ioctlsocket(FIONBIO, (ULONG FAR*)&ulNonblockingMode);
    assert(FALSE != bRes); 

    //-------------------------------------
    //установка величины таймаута
    timeval ReceiveTimeout = {0};
    ReceiveTimeout.tv_sec  = 0;
    ReceiveTimeout.tv_usec = SOCKET_TIMEOUT/*1000000 / 10*/;              

    fd_set fds = {0};
    FD_ZERO(&fds);
    FD_SET(m_puiSocket, &fds);
        
    //-------------------------------------
    //читаем из сокета
    for (;;) {   
        iRes = ::select(0, &fds, NULL, NULL, &ReceiveTimeout);
        if (0 == iRes) {
            break;
        }
        
        iRes = ::recv(&sIn[0], cuiInSize, iFlags);  
        assert(iRes >= 0);
        if (0 == iRes) {
            break;
        }    

        sRes.append( std::string(sIn.begin(), sIn.begin() + iRes) );
    } 

    //-------------------------------------
    //leave non blocking
    ulNonblockingMode = (ULONG)FALSE;
    bRes = ::ioctlsocket(FIONBIO, (ULONG FAR*)&ulNonblockingMode);
    assert(FALSE != bRes); 

    return sRes;    



Это сообщение отредактировал(а) Alca - 25.6.2009, 13:26


--------------------
PM WWW ICQ Skype Jabber   Вверх
Alca
Дата 25.6.2009, 13:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3993
Регистрация: 14.6.2006

Репутация: 1
Всего: 50



Если таймаут больше (в 10 раз), то ответ приходит от сервера. Что делать?
Код

        enum {
            SOCKET_TIMEOUT = (1000000 / 10) * 10        //величина таймаута в микросекундах          
        };    



--------------------
PM WWW ICQ Skype Jabber   Вверх
Alca
Дата 25.6.2009, 14:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3993
Регистрация: 14.6.2006

Репутация: 1
Всего: 50



Пишу под винду. smile 


--------------------
PM WWW ICQ Skype Jabber   Вверх
GrayCardinal
Дата 25.6.2009, 14:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Фигасе
****


Профиль
Группа: Завсегдатай
Сообщений: 3039
Регистрация: 9.11.2003

Репутация: 3
Всего: 58



Цитата

Пишу под винду

 smile 


--------------------
PM MAIL WWW   Вверх
Alca
Дата 25.6.2009, 14:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3993
Регистрация: 14.6.2006

Репутация: 1
Всего: 50



Понял.

Добавлено @ 14:24
Код

__export int DIONREAD (int fd)
{
    int ret = -1;
    if (ioctl (fd, FIONREAD, &ret) != 0)
        return -1;
    return ret;
}

fd это чего?

Добавлено через 7 минут и 11 секунд
сокет?

Это сообщение отредактировал(а) Alca - 25.6.2009, 14:25


--------------------
PM WWW ICQ Skype Jabber   Вверх
vinick
Дата 25.6.2009, 14:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 285
Регистрация: 9.6.2005

Репутация: 6
Всего: 22



Цитата(GrayCardinal @  25.6.2009,  13:17 Найти цитируемый пост)
Кто мешает делать select + FIONREAD на блокирующих ?

Здравый смысл. Зачем делать столько лишних телодвижений? перевести сокет в неблокирующий режим достаточно 1 раз при создании. А FIONERAD надо будет дергать постоянно.


Цитата(GrayCardinal @  25.6.2009,  13:17 Найти цитируемый пост)
vinick, 
ИМХО, ты бредишь  smile  

Ага брежу я и толпы разработчиков сетевых библиотек. Лишь ты несешь нам свет истины.
PM MAIL ICQ Jabber   Вверх
fry
Дата 25.6.2009, 15:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 257
Регистрация: 4.10.2006

Репутация: нет
Всего: 3



Alca
Цитата

Понял.

Добавлено @ 14:24
__export int DIONREAD (int fd)
{
    int ret = -1;
    if (ioctl (fd, FIONREAD, &ret) != 0)
        return -1;
    return ret;
}

fd это чего?

Добавлено через 7 минут и 11 секунд
сокет?


Мой тебе совет: лучше не начинай писать того, что сам не понимаешь как работает. Вначале сам почитай книгу какую нибудь, тогда вопросы такого рода тебя уже мучить не будут. Данная тема не очень простая, в ней куча мелочей, без знания которых ты так и будешь задавать такого рода вопросы, а когда получишь готовое приложение у тебя не будет уверенности в его стабильной работе (иными словами "протянет ноги" в самый ненужный момент). 
Думаю полезно будет прочитать Стивенса, хотя бы начало. В ней изложены основные модели сетевых приложений.

Добавлено через 3 минуты и 8 секунд
Alca
Цитата

Бывает такое, что функция возвращяет пустую строку.
При дисконнекте POP3 сервера, сокет (::recv) не успееват получить ответ, т.е. ответка сервака не приходит.
Что делать?


Расшифруй пожалуйста.
PM MAIL   Вверх
Alca
Дата 25.6.2009, 15:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3993
Регистрация: 14.6.2006

Репутация: 1
Всего: 50



Цитата

Расшифруй пожалуйста.


После
Код

    //читаем из сокета
    for (;;) {   
        //...
        iRes = ::recv(&sIn[0], cuiInSize, iFlags);  
        //...
        sRes.append(........
    } 

sRes - пустая строка (должен быть ответ от POP3 сервера)

Добавлено через 3 минуты и 34 секунды
Если таймаут маленький (1000000 / 10) то нет ответки а если порядка (1000000 / 10) * 10 то все ок.


--------------------
PM WWW ICQ Skype Jabber   Вверх
fry
Дата 25.6.2009, 16:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 257
Регистрация: 4.10.2006

Репутация: нет
Всего: 3



А если данных еще нет в буфере сокета? (например пакет еще в сети)
По моему обработка ошибок вызова recv не очень правильная.
И потом recv не гарантирует изъятие всех данных из буфера, поэтому и возвращает их количество.

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

Это сообщение отредактировал(а) fry - 25.6.2009, 16:18
PM MAIL   Вверх
Alca
Дата 25.6.2009, 16:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3993
Регистрация: 14.6.2006

Репутация: 1
Всего: 50



del

Это сообщение отредактировал(а) Alca - 25.6.2009, 16:24


--------------------
PM WWW ICQ Skype Jabber   Вверх
GrayCardinal
Дата 25.6.2009, 16:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Фигасе
****


Профиль
Группа: Завсегдатай
Сообщений: 3039
Регистрация: 9.11.2003

Репутация: 3
Всего: 58



Цитата

А FIONERAD надо будет дергать постоянно.

Кому "надо будет" ?

Это сообщение отредактировал(а) GrayCardinal - 25.6.2009, 16:31


--------------------
PM MAIL WWW   Вверх
Alca
Дата 25.6.2009, 16:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3993
Регистрация: 14.6.2006

Репутация: 1
Всего: 50



Цитата

возвращенное из данного вызова.

В том то и дело, что при блокирующем сокете ф-я ::recv - не возвращает управление программе,
а при неблокирующем (если маленький таймаут), то ф-я ::recv не "успеевает" принять данные из сокета.


--------------------
PM WWW ICQ Skype Jabber   Вверх
fry
Дата 25.6.2009, 16:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 257
Регистрация: 4.10.2006

Репутация: нет
Всего: 3



Цитата

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


Почитай книгу Стивенса и посмотри как сделано. (Книга есть в инете)

Цитата

не возвращает управление программе


Возвращает, в случае блокировки по изменению состояния сокета.

Это сообщение отредактировал(а) fry - 25.6.2009, 16:49
PM MAIL   Вверх
Alca
Дата 25.6.2009, 16:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3993
Регистрация: 14.6.2006

Репутация: 1
Всего: 50



Накатай примерчик


--------------------
PM WWW ICQ Skype Jabber   Вверх
fry
Дата 25.6.2009, 16:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 257
Регистрация: 4.10.2006

Репутация: нет
Всего: 3



Цитата

Накатай примерчик


Накатал...

Примеров мля куча, загляни на allanswers.find

Повторяться не буду, почитай книгу.


PM MAIL   Вверх
Alca
Дата 25.6.2009, 20:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3993
Регистрация: 14.6.2006

Репутация: 1
Всего: 50



Код

std::string CXTcpClientSocket::sRecvBytes(INT iFlags) {
    std::string sRes             = "";
    CHAR        szBuff[1024 + 1] = {0};

    while (TRUE) {
        ULONG ulArg = 0;
        if (0 != ::ioctlsocket(m_puiSocket, FIONREAD, &ulArg)) {
            break;
        }

        if (0 == ulArg) {
            break;  //<-- сюда валиться
        }

        if (1024 < ulArg) {
            ulArg = 1024;
        }

        INT iRes = ::recv(m_puiSocket, szBuff, ulArg, 0);
        if (iRes <= 0) {
            break;
        }

        std::string sTemp;

        sTemp.assign(szBuff, iRes);
        sRes += sTemp;
    }

    return sRes;
}

Все равно нет ответа от сервера....  smile 

Это сообщение отредактировал(а) Alca - 25.6.2009, 21:14


--------------------
PM WWW ICQ Skype Jabber   Вверх
fry
Дата 26.6.2009, 08:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 257
Регистрация: 4.10.2006

Репутация: нет
Всего: 3



Alca, может данные просто дойти не успевают? 

Пробовал вызывать CXTcpClientSocket::sRecvBytes через некоторые промежутки времени?
PM MAIL   Вверх
Alca
Дата 26.6.2009, 09:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3993
Регистрация: 14.6.2006

Репутация: 1
Всего: 50



Цитата

Alca, может данные просто дойти не успевают? 

::ioctlsocket говорит что нет данных для чтения 
Код

        if (0 == ulArg) {
            break;  //<-- сюда валиться
        }

хотя ответ от сервера еще не пришел.
Цитата

Пробовал вызывать CXTcpClientSocket::sRecvBytes через некоторые промежутки времени?

До ::recv дело не доходит


--------------------
PM WWW ICQ Skype Jabber   Вверх
Alca
Дата 26.6.2009, 13:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3993
Регистрация: 14.6.2006

Репутация: 1
Всего: 50



Если я принимаю данные большого размера (файл) в буфер фиксированого размера:
Цитата

CHAR szBuf[8192];
INT iRes = ::recv(&szBuf[0], 8192, 0);

Кол-во принятых байт будет всегда равно размеру принимающего буфера или нет
(я не беру, тот факт, что концовка данных (файла) будет меньше размера буфера, это и так ясно) ?
Цитата

assert(iRes == 8192); //???




--------------------
PM WWW ICQ Skype Jabber   Вверх
fry
Дата 26.6.2009, 15:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 257
Регистрация: 4.10.2006

Репутация: нет
Всего: 3



нет, не так. 

Функция чтения из сокета не обязанна возвращать значение считанных байт, равное требуемому. Именно для обработки данного условия она это значение и возвращяет. 

Представь себе ситуацию, что ты передаешь фильму метров эдак на 500. Естественно она вся в буфер приема ОС для этого сокета не влезет. Тогда как спрашивается функция приема данных вернет тебе запрошенные у нее 500 метров?

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

Некоторые параметры работы данного алгоритма можно настаивать. Я уже посоветовал книгу ("UNIX. Разработка сетевых приложений", Стивенс) - в ней все есть.

Это сообщение отредактировал(а) fry - 26.6.2009, 15:08
PM MAIL   Вверх
Alca
Дата 26.6.2009, 15:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3993
Регистрация: 14.6.2006

Репутация: 1
Всего: 50



Хм.... Кажись я близок к цели..... smile 
Смотрю, я первую ответку сервера, которая пришла типа не полностью....
Как вы думаете, какой размер этих данных?
1024 байта. Следов. сервак шлет мне эти данные блоками по 1024 байт.
Ну поставил я у себя такой же размер буфера и все заработало.
Вот код:
Код

std::string CXTcpClientSocket::sRecvBytes() {   
    std::string  sRes      = "";
    INT          iRes      = etError;   
    BOOL         bRes      = FALSE;   
    const size_t cuiInSize = 1024; ///////////////////////
    std::string  sIn(cuiInSize, '\0');

    for (;;) {   
        iRes = iRecv(&sIn[0], cuiInSize, 0);  
        assert(iRes >= 0);
        assert(iRes <= cuiInSize);
        
        if (0 == iRes) {
            break;
        }    
        if (- 1 == iRes) {
            break;
        }

        std::string sTemp(sIn.begin(), sIn.begin() + iRes);
        sRes.append(sTemp);

        if (iRes < cuiInSize) {   
            ULONG ulArg = (ULONG)FALSE;    
            if (0 != ::ioctlsocket(_m_puiSocket, FIONREAD, &ulArg)) {
                break;
            }

            if (0 == ulArg) {
                break;
            }
        }
    } 

    return sRes;    



Добавлено через 1 минуту и 3 секунды
Но как быть если размер буфера у меня не 1024 байта?  smile 


--------------------
PM WWW ICQ Skype Jabber   Вверх
GrayCardinal
Дата 26.6.2009, 15:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Фигасе
****


Профиль
Группа: Завсегдатай
Сообщений: 3039
Регистрация: 9.11.2003

Репутация: 3
Всего: 58



Цитата

и все заработало.

Я рад за тебя...  smile  


--------------------
PM MAIL WWW   Вверх
fry
Дата 26.6.2009, 15:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 257
Регистрация: 4.10.2006

Репутация: нет
Всего: 3



в одном пакете TCP умещается около 1500 байт
PM MAIL   Вверх
Alca
Дата 26.6.2009, 15:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3993
Регистрация: 14.6.2006

Репутация: 1
Всего: 50



Цитата

Цитата
Цитата

и все заработало.

Я рад за тебя...

Но как быть если размер буфера у меня не 1024 байта?

Добавлено через 1 минуту и 23 секунды
Цитата

в одном пакете TCP умещается около 1500 байт
 и?


--------------------
PM WWW ICQ Skype Jabber   Вверх
GrayCardinal
Дата 26.6.2009, 15:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Фигасе
****


Профиль
Группа: Завсегдатай
Сообщений: 3039
Регистрация: 9.11.2003

Репутация: 3
Всего: 58



Alca
А в репу ?  smile

Добавлено через 19 секунд
ЗЫ
ради приличия хотя бы по RTF эмь


--------------------
PM MAIL WWW   Вверх
Alca
Дата 26.6.2009, 15:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3993
Регистрация: 14.6.2006

Репутация: 1
Всего: 50



Цитата

А в репу ? 
  smile 


--------------------
PM WWW ICQ Skype Jabber   Вверх
Страницы: (3) [Все] 1 2 3 
Ответ в темуСоздание новой темы Создание опроса
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Сети | Следующая тема »


 




[ Время генерации скрипта: 0.1992 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.