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

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Помогите найти ошибку в клиенте, Проблемы с приемом данных (асинхронным) 
V
    Опции темы
quard
  Дата 25.6.2007, 00:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



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

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



Здравствуйте!
По задумке, после соединения с сервером создаётся поток, в котором происходит ожидание данных от сервера.

Соединение происходит нормально, но после начала цикла ожидания данных мой комп начинает глючить (100% CPU).

Что делать? smile 

я полагаю, что ошибка в функции OnReceive:

Код

    virtual void OnReceive( void ) { /* Получение данных */
        fd_set set;

        while (1)
        {
            FD_ZERO(&set);
            FD_SET(m_sBase, &set);

            if ( select(0, &set, NULL, NULL, 0) > 0 )
            {
                if ( FD_ISSET(m_sBase, &set) )
                { 
                    int c = recv(m_sBase, (char*)pRecvBuf, Pack, 0);

                    if ( c > 0 ) 
                    {
                        pRecvBuf[c] = NULL;
                        MessageBox(0, (LPSTR)pRecvBuf, 0, 0);
                    } 
                }
            } else 
                OnException(E_FUNC_SELECT_);
        }
    }


но на всякий случай полный код клиента:

Код

#ifndef _CLIENT_H_
#define _CLIENT_H_

#if defined (_MSC_VER) && (_MSC_VER >= 1020)
#pragma once
#endif

#define CLIENT_VER 1.0

#include <winsock.h>
#include <memory.h>

// возможные исключения:
#define E_FUNC_SOCKET_  0
#define E_FUNC_ASYNC_   1
#define E_FUNC_THREAD_  2
#define E_FUNC_SELECT_  3
#define E_FUNC_ADDRESS_ 4

//////////////////////////////////////////////////
//                                              //
//       Асинхронный TCP/IP Клиент (v1.0)       //
//                                              //
//////////////////////////////////////////////////

DWORD WINAPI ReceiveThread_TCP( LPVOID pTCPClient );

class CTCPClient {
    friend DWORD WINAPI ReceiveThread_TCP( LPVOID pTCPClient );
private:
    SOCKET m_sBase; // сокет клиента
    BOOL m_bActive; // true: запущен | false: остановлен
    HANDLE m_hThrd; // главный поток
protected:
    virtual void OnException( u_long Ecode ) { /* [event] Исключение */
        char *Emap[] = {
            "Неудаётся создать сокет",
            "Неудаётся перейти в асинхронный режим",
            "Ошибка создания потока",
            "Ошибка функции select",
            "Неверный адрес сервера"
        };
// сообщение об ошибке:
        MessageBox(0, Emap[Ecode], "TCP/IP Client Exception", MB_ICONERROR);

        if ( m_bActive ) Disconnect();
    }
    virtual void OnReceive( void ) { /* [event] Получение данных */
        fd_set set;

        while (1)
        {
            FD_ZERO(&set);
            FD_SET(m_sBase, &set);

            if ( select(0, &set, NULL, NULL, 0) > 0 )
            {
                if ( FD_ISSET(m_sBase, &set) )
                { 
                    int c = recv(m_sBase, (char*)pRecvBuf, Pack, 0);

                    if ( c > 0 ) 
                    {
                        pRecvBuf[c] = NULL;
                        MessageBox(0, (LPSTR)pRecvBuf, 0, 0);
                    } 
                }
            } else 
                OnException(E_FUNC_SELECT_);
        }
    }
public:
    u_short Pack; 
    timeval TimeOut; // максимальное время ожидания

    byte *pRecvBuf; // буффер получаемых данных 
    byte *pSendBuf; // буффер отправляемый данных
// --------------------------------------------
    bool Connect( LPCSTR Address, u_short Port ) { /* Соединение */
// создание асинхронного сокета:
        m_sBase = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        
        if ( m_sBase == SOCKET_ERROR )
        {
            OnException(E_FUNC_SOCKET_);
            return FALSE;
        }

        u_long state = true;

        if ( ioctlsocket(m_sBase, FIONBIO, &state) != 0 )
        {
            OnException(E_FUNC_ASYNC_);
            return FALSE;
        }

// адрес:
        sockaddr_in server_address;
        server_address.sin_family = AF_INET;
        server_address.sin_addr.s_addr = inet_addr(Address);
        server_address.sin_port = htons(Port);
        memset(server_address.sin_zero, 0, 8);
        
        if ( server_address.sin_addr.s_addr == INADDR_NONE )
        {
            hostent *pHost = NULL;
            pHost = gethostbyname(Address);

            if ( pHost == NULL )
            {
                OnException(E_FUNC_ADDRESS_);
                return FALSE;
            } 
            else 
                memcpy(&server_address.sin_addr, pHost->h_addr_list[0], pHost->h_length);
        }

// соединение:
        fd_set set;

        FD_ZERO(&set);
        FD_SET(m_sBase, &set);
        
        connect(m_sBase, (sockaddr*)&server_address, sizeof(server_address));

        if ( select(0, &set, NULL, NULL, &TimeOut) != SOCKET_ERROR )
        {
            if ( FD_ISSET(m_sBase, &set) )
            {
// создание главного потока:
                DWORD dwThreadID;

                m_hThrd = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&ReceiveThread_TCP, this, 0, &dwThreadID);

                if ( m_hThrd == NULL )
                    OnException(E_FUNC_THREAD_);
                else
                    m_bActive = TRUE;
            }
            else
                Disconnect();
        }
        else
            OnException(E_FUNC_SELECT_);

        return m_bActive;
    }
    void Disconnect( void ) { /* Разрыв соединения */
        if ( m_sBase != INVALID_SOCKET )
        {
            if ( m_hThrd != NULL )
            {
                TerminateThread(m_hThrd, 0);
                CloseHandle(m_hThrd);
                m_hThrd = NULL;
            }
            u_long state = false;
            ioctlsocket(m_sBase, FIONBIO, &state);
            closesocket(m_sBase);
            m_sBase = INVALID_SOCKET;
            m_bActive = FALSE;
        }
    }
    bool IsConnected( void ) { return m_bActive; }
// --------------------------------------------
    CTCPClient( void ) {
        m_bActive = FALSE;
        m_sBase = INVALID_SOCKET;
        TimeOut.tv_sec = 1;
        TimeOut.tv_usec = 0;
        m_hThrd = NULL;
        Pack = 32;

        pRecvBuf = new BYTE[Pack];
        pSendBuf = new BYTE[Pack];
    }
    ~CTCPClient( void ) {
        Disconnect();

        delete [] pRecvBuf;
        delete [] pSendBuf;
    }
};

DWORD WINAPI ReceiveThread_TCP( LPVOID pTCPClient )
{
    ((CTCPClient*)pTCPClient)->OnReceive();

    return 0;
}

#endif


Зараннее спасибо....
PM MAIL   Вверх
ptr
Дата 25.6.2007, 07:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 661
Регистрация: 31.5.2006
Где: Новосибирск

Репутация: 9
Всего: 14



1. Асинхронный режим это немного другое. У тебя многопоточность + мультиплексирование + неблокирующий режим.
2. Видимо неблокирующий режим сделан для connect. Иначе зачем? Тогда после connect надо бы  сделать обратное преобразование.
3.
Код

connect(m_sBase, (sockaddr*)&server_address, sizeof(server_address));

        if ( select(0, &set, NULL, NULL, &TimeOut) != SOCKET_ERROR )

Для connect сокет должен находиться в writeset, а не в  readset.
4. Оно вообще работает?


--------------------
Единственный способ определить границы возможного - это выйти за эти границы, в невозможное.
Артур Кларк.
PM MAIL ICQ   Вверх
quard
Дата 25.6.2007, 11:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



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

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



Всё сделал как ты сказал и всё также. почему-то функция recv всегда возвращает 0, хотя с сервером соединяется.

Может я что-то неправильно делаю.
Вот я написал самый простой код клиента и в нём таже ошибка:


Код


#include <winsock.h>

DWORD WINAPI ReceiveThread_TCP( LPVOID lpParam )
{
    SOCKET m_sBase = (SOCKET)lpParam;

    char pRecvBuf[32];
    int c;

    while (1) 
    {
            c = recv(m_sBase, pRecvBuf, 32, 0);

            if ( c > 0 ) 
            {
                pRecvBuf[c] = NULL;
                MessageBox(0, (LPSTR)pRecvBuf, 0, 0);
                continue;
            }

            if ( c == 0 )
            {
                MessageBox(0, "Соединение разорвано", 0, 0);
                return 0;
            }

            if ( c == SOCKET_ERROR )
            {
                MessageBox(0, "Ошибка приёма", 0, 0);
                return 0;
            }
    }

    return 0;
}

void main ( void )
{
    WSADATA wsd;
    if ( WSAStartup(MAKEWORD(1,0), &wsd) != 0 )
        return;

    SOCKET m_sBase = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        
    u_long state = 1;
    ioctlsocket(m_sBase, FIONBIO, &state);

    sockaddr_in server_address;
    server_address.sin_family = AF_INET;
    server_address.sin_addr.s_addr = inet_addr("127.0.0.1");
    server_address.sin_port = htons(7319);
    memset(server_address.sin_zero, 0, 8);
        
    HANDLE m_hThread = 0;
    timeval TimeOut = { 2, 0 };
    fd_set set;
    
    FD_ZERO(&set);
    FD_SET(m_sBase, &set);
    
    connect(m_sBase, (sockaddr*)&server_address, sizeof(server_address));

    if ( select(0, NULL, &set, NULL, &TimeOut) != SOCKET_ERROR )
    {
        if ( FD_ISSET(m_sBase, &set) )
        {
                u_long state = 0;
                ioctlsocket(m_sBase, FIONBIO, &state);

                DWORD dwThreadID;
                m_hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&ReceiveThread_TCP, (LPVOID)m_sBase, 0, &dwThreadID);

//                WaitForSingleObject(m_hThread, INFINITE);
        }
    }

    MessageBox(0, "Идёт ожидание приёма данных...", 0, 0);

    TerminateThread(m_hThread, 0);
    closesocket(m_sBase);

    WSACleanup();
}


Цитата

Оно вообще работает? 

Да ладно тебе, я ведь не каждый день клиент пишу  smile 

PM MAIL   Вверх
ptr
Дата 26.6.2007, 08:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 661
Регистрация: 31.5.2006
Где: Новосибирск

Репутация: 9
Всего: 14



recv возвращает 0, когда соединение закрыто (например другая сторона его закрыла). Т.е. вторую проверку c==0 надо поставить в самое начало.

Цитата(quard @  25.6.2007,  14:37 Найти цитируемый пост)
Да ладно тебе, я ведь не каждый день клиент пишу  

Да не, просто у меня оно заработало после некоторого тюнинга.


--------------------
Единственный способ определить границы возможного - это выйти за эти границы, в невозможное.
Артур Кларк.
PM MAIL ICQ   Вверх
Goganchic
Дата 26.6.2007, 08:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Цитата(ptr @  26.6.2007,  08:28 Найти цитируемый пост)
recv возвращает 0, когда соединение закрыто (например другая сторона его закрыла). Т.е. вторую проверку c==0 надо поставить в самое начало.

и что это даст? логика-то будет абсолютно такой же: что он сначала пропустит инструкцию и перейдет ко второй, что сразу же начнет с нее...
Чего-то я  не понимаю
PM Jabber   Вверх
quard
Дата 26.6.2007, 16:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



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

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



Всем спасибо! 
Ошибка была в сервере.... smile 
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Сети | Следующая тема »


 




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


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

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