На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
  
    > непонятки с клиент-серверным приложением (работа recv) , работа функции recv
      Приветствую

      стоит задача - создать код, получающий информацию

      создал так:

      ExpandedWrap disabled
            int nNetOpResult;
         
            // инициализировать WSA
            WSADATA wsaData;
            nNetOpResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
         
            if (NO_ERROR != nNetOpResult)
                return -1;
         
            // открыть сокет
            SOCKET pClientServerSocket = socket(AF_INET, SOCK_STREAM, 0);
         
            if (INVALID_SOCKET == pClientServerSocket)
            {
                // деинициализировать WSA
                WSACleanup();
         
                return -1;
            }
         
            sockaddr_in pSocketAddress;
            pSocketAddress.sin_family = AF_INET;
            pSocketAddress.sin_addr.s_addr = inet_addr(strAddress);
            pSocketAddress.sin_port = htons(nPort);
         
            // соединиться по сокету
            nNetOpResult = connect(pClientServerSocket, (sockaddr*)&pSocketAddress, sizeof(pSocketAddress));
         
            if (SOCKET_ERROR == nNetOpResult)
            {
                // закрыть сокет
                closesocket(pClientServerSocket);
         
                // деинициализировать WSA
                WSACleanup();
         
                return -1;
            }
         
            while (::WaitForSingleObject(m_hClientServerEvent, 0) == WAIT_OBJECT_0)
            {
                char* pCBData = NULL;
         
                do
                {
                    // получить размер буфера
                    size_t szCBDataSize;
                    if (recv(pClientServerSocket, (char*)&szCBDataSize, sizeof(szCBDataSize), 0) == SOCKET_ERROR)
                        break;
         
                    // выделить память под буфер
                    pCBData = new char [szCBDataSize];
         
                    // получить непосредственно данные
                    if (recv(pClientServerSocket, (char*)&nCBDataType, sizeof(nCBDataType), 0) == SOCKET_ERROR)
                        break;
         
                    // обработать данные
         
                    // очистить память
                    delete [] pCBData;
                    pCBData = NULL;
         
                } while (false);
         
                // очистить память
                if (pCBData != NULL)
                    delete [] pCBData;
            }
         
            // закрыть сокет
            closesocket(pClientServerSocket);
         
            // деинициализировать WSA
            WSACleanup();


      Проверил - все работает, кроме функции recv, которая постоянно возвращает SOCKET_ERROR
      Я так понимаю это потому что, на другой стороне никто не работает, никто не шлет информацию

      Тогда пара вопросов:
      1) чтобы постоянно не гонять цикл можно ли определить что соединение установлено
      2) или в самой логике работы клиентского приложения есть ошибка?
        а что WSAGetLastError возвращает?
          ExpandedWrap disabled
                while (::WaitForSingleObject(m_hClientServerEvent, 0) == WAIT_OBJECT_0)
                {
                    char* pCBData = NULL;
             
                    do
                    {
                        // получить размер буфера
                        size_t szCBDataSize;
                        if (recv(pClientServerSocket, (char*)&szCBDataSize, sizeof(szCBDataSize), 0) == SOCKET_ERROR)
                            break;
             
                        // выделить память под буфер
                        pCBData = new char [szCBDataSize];

          // Непонятно это место: строкой выше память выделяется для одного буфера, а ниже чтение
          // выполняется в другой
          ExpandedWrap disabled
                        // получить непосредственно данные
                        if (recv(pClientServerSocket, (char*)&nCBDataType, sizeof(nCBDataType), 0) == SOCKET_ERROR)
                            break;
             
                        // обработать данные
             
                        // очистить память
                        delete [] pCBData;
                        pCBData = NULL;
             
                    } while (false);
             
                    // очистить память
                    if (pCBData != NULL)
                        delete [] pCBData;
                }
            dikdik, да это непонятно, но по идее не должно приводить к SOCKET_ERROR..
              похоже у меня ошибка в логике работы :(
              попробовал реализовать простой случай

              приложение является клиентом и сервером - и работает через адрес 127.0.0.1:1234
              т.е. одна часть программы будет отсылать по этому адресу команды вторая часть - получать

              код выглядит так:

              ExpandedWrap disabled
                class CNetEngine
                {
                protected:
                    HANDLE  m_hClientServerThread;
                    HANDLE  m_hClientServerEvent;
                 
                    SOCKET  m_pServerClientSocket;
                 
                protected:
                    static DWORD WINAPI ClientServerThread(LPVOID pParams);
                    DWORD _ClientServerThread();
                 
                public:
                            CNetEngine();
                            ~CNetEngine();
                 
                    void    StartClientServer();
                    void    StopClientServer();
                 
                    int     StartServerClient();
                    int     StopServerClient();
                };
                 
                // поток для обработки соединения клиент-сервер
                DWORD WINAPI CNetEngine::ClientServerThread(LPVOID pParams)
                {
                    return ((CNetEngine*)pParams)->_ClientServerThread();
                }
                 
                DWORD CNetEngine::_ClientServerThread()
                {
                    CDataStorage* pStorageData = CDataStorage::GetInstance();
                 
                    char strServerAddress[64];
                    sprintf_s(strServerAddress, "%d.%d.%d.%d", pStorageData->m_pClientIP[0], pStorageData->m_pClientIP[1], pStorageData->m_pClientIP[2], pStorageData->m_pClientIP[3]);
                 
                    int nNetOpResult;
                 
                    // инициализировать WSA
                    WSADATA wsaData;
                    nNetOpResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
                 
                    if (NO_ERROR != nNetOpResult)
                        return -1;
                 
                    // открыть сокет
                    SOCKET pClientServerSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
                 
                    if (INVALID_SOCKET == pClientServerSocket)
                    {
                        // деинициализировать WSA
                        WSACleanup();
                 
                        return -1;
                    }
                 
                    // соединиться по сокету
                    sockaddr_in pSocketAddress;
                    pSocketAddress.sin_family = AF_INET;
                    pSocketAddress.sin_addr.s_addr = inet_addr(strServerAddress);
                    pSocketAddress.sin_port = htons(pStorageData->m_nClientPort);
                 
                    while (::WaitForSingleObject(m_hClientServerEvent, 0) == WAIT_OBJECT_0)
                    {
                        nNetOpResult = connect(pClientServerSocket, (sockaddr*)&pSocketAddress, sizeof(pSocketAddress));
                 
                        ::Sleep(1000);
                    }
                 
                    while (::WaitForSingleObject(m_hClientServerEvent, 0) == WAIT_OBJECT_0)
                    {
                        char* pCBData = NULL;
                 
                        do
                        {
                            // получить размер буфера
                            size_t szCBDataSize;
                            if (recv(pClientServerSocket, (char*)&szCBDataSize, sizeof(szCBDataSize), 0) == SOCKET_ERROR)
                            {
                                int nError = WSAGetLastError();
                                break;
                            }
                 
                            // получить тип данных
                            UINT nCBDataType;
                            if (recv(pClientServerSocket, (char*)&nCBDataType, sizeof(nCBDataType), 0) == SOCKET_ERROR)
                                break;
                 
                            // выделить память под буфер
                            pCBData = new char [szCBDataSize];
                 
                            // получить непосредственно данные
                            if (recv(pClientServerSocket, (char*)&nCBDataType, sizeof(nCBDataType), 0) == SOCKET_ERROR)
                                break;
                 
                        } while (false);
                 
                        // очистить память
                        if (pCBData != NULL)
                            delete [] pCBData;
                    }
                 
                    // закрыть сокет
                    closesocket(pClientServerSocket);
                 
                    // деинициализировать WSA
                    WSACleanup();
                 
                    return 0;
                }
                 
                // запустить соединения клиент-сервер, сервер-клиент
                void CNetEngine::StartClientServer()
                {
                    // запустить поток клиент-сервер
                    m_hClientServerThread = ::CreateThread(NULL, 0, ClientServerThread, this, CREATE_SUSPENDED, NULL);
                    m_hClientServerEvent = ::CreateEvent(NULL, TRUE, TRUE, _T("ClientServerEvent"));
                 
                    ::ResumeThread(m_hClientServerThread);
                }
                 
                // остановить соединения клиент-сервер, сервер-клиент
                void CNetEngine::StopClientServer()
                {
                    // остановить поток клиент-сервер
                    ::CloseHandle(m_hClientServerEvent);
                 
                    if (::WaitForSingleObject(m_hClientServerThread, 2000) == WAIT_TIMEOUT)
                        ::TerminateThread(m_hClientServerThread, 0);
                 
                    ::CloseHandle(m_hClientServerThread);
                 
                    m_hClientServerThread = NULL;
                    m_hClientServerEvent = NULL;
                }
                 
                // запустить поток сервер-клиент
                int CNetEngine::StartServerClient()
                {
                    CDataStorage* pStorageData = CDataStorage::GetInstance();
                 
                    char strServerAddress[64];
                    sprintf_s(strServerAddress, "%d.%d.%d.%d", pStorageData->m_pClientIP[0], pStorageData->m_pClientIP[1], pStorageData->m_pClientIP[2], pStorageData->m_pClientIP[3]);
                 
                    int nNetOpResult;
                 
                    // инициализировать WSA
                    WSADATA wsaData;
                    nNetOpResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
                 
                    if (NO_ERROR != nNetOpResult)
                        return -1;
                 
                    // открыть сокет
                    m_pServerClientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
                 
                    if (INVALID_SOCKET == m_pServerClientSocket)
                    {
                        // деинициализировать WSA
                        WSACleanup();
                 
                        return -1;
                    }
                 
                    // соединиться по сокету
                    sockaddr_in pSocketAddress;
                    pSocketAddress.sin_family = AF_INET;
                    pSocketAddress.sin_addr.s_addr = inet_addr(strServerAddress);
                    pSocketAddress.sin_port = htons(pStorageData->m_nClientPort);
                 
                    nNetOpResult = bind(m_pServerClientSocket, (sockaddr*)&pSocketAddress, sizeof(pSocketAddress));
                 
                    if (SOCKET_ERROR == nNetOpResult)
                    {
                        // закрыть сокет
                        closesocket(m_pServerClientSocket);
                 
                        // деинициализировать WSA
                        WSACleanup();
                 
                        return -1;
                    }
                 
                    nNetOpResult = listen(m_pServerClientSocket, SOMAXCONN);
                 
                    if (SOCKET_ERROR == nNetOpResult)
                    {
                        // закрыть сокет
                        closesocket(m_pServerClientSocket);
                 
                        // деинициализировать WSA
                        WSACleanup();
                 
                        return -1;
                    }
                 
                    return 0;
                }
                 
                // остановить поток сервер-клиент
                int CNetEngine::StopServerClient()
                {
                    // закрыть сокет
                    closesocket(m_pServerClientSocket);
                 
                    // деинициализировать WSA
                    WSACleanup();
                 
                    return 0;
                }



              Запускаю StartClientServer и StartServerClient - и ничего не происходит - т.е. connect у клиента не происходит
              Мне кажется что у меня ошибка в общей логике работы приложения
                а где вызовы bind и accept?
                  CreateThread не есть гуд
                    Цитата =MOHAX= @
                    а где вызовы bind и accept?

                    в функции CNetEngine::StartServerClient()


                    Цитата Alca @
                    CreateThread не есть гуд

                    а как еще - та часть которая должна получать сообщения должна в отдельном потоке крутиться, а как же иначе?
                      _beginthreadex
                        Цитата Alca @
                        _beginthreadex

                        Не замечал проблем при совместном использовании CreateThread и сокетов.
                        Fireman, отладчиком пройдись и посмотри, встает ли сервер на accept(), одинаков ли порт и адресс у клиента и сервера, код ошибки(WSAGetLastError()).
                          Цитата
                          Не замечал проблем при совместном использовании CreateThread и сокетов

                          А если CreateThread и CRT?
                            у меня с CreateThread тоже проблем никогда не было
                              Вот я дурак - взялся за это _beginthreadex. Поставьте мне - 1. :ph34r:
                                инициализация серверной и клиентской части прошли без ошибок
                                на recv подвисла (так и должно быть поскольку recv ожидает или закрытия сокета или прихода пакета)

                                но вот когда пытаюсь сделать send получаю ошибку 10057 - Socket is not connected.
                                  кстати,
                                  ExpandedWrap disabled
                                     m_hClientServerEvent = ::CreateEvent(NULL, TRUE, TRUE, _T("ClientServerEvent"));
                                     
                                    //случаем не бесконечный цикл то выходит?
                                    //Event всегда в сигнальном состоянии + создаеться с ManualReset, т.е чтобы сбросить, нужно вызвать ResetEvent().
                                    while (::WaitForSingleObject(m_hClientServerEvent, 0) == WAIT_OBJECT_0)
                                        {
                                            nNetOpResult = connect(pClientServerSocket, (sockaddr*)&pSocketAddress, sizeof(pSocketAddress));
                                     
                                            ::Sleep(1000);
                                        }
                                    вот проект-примерчик созданный на данном коде (VC9.0):
                                    сначала происходит инициализация сервера, потом клиента, потом серверу посылаются числа 10, 20, 30
                                    ничего не происходит - они не доходят

                                    адрес 127.0.0.1:1234
                                    Сообщение отредактировано: Fireman -

                                    Прикреплённый файлПрикреплённый файлclient_server.zip (8.21 Кбайт, скачиваний: 171)
                                      а accept где? :o
                                        1. Не рекомендуется убивать поток извне
                                        ExpandedWrap disabled
                                              if (::WaitForSingleObject(m_hClientServerThread, 2000) == WAIT_TIMEOUT)
                                                  ::TerminateThread(m_hClientServerThread, 0);


                                        2. А где сопоставление сокета и Eventa? По моему, должно быть как-то так:
                                        ExpandedWrap disabled
                                             Event = WSACreateEvent();
                                             WSAEventSelect(Sock, Event, (FD_READ | FD_WRITE));

                                        А в цикле:
                                        ExpandedWrap disabled
                                          DWORD ret = WaitForMultipleObjects(3, evEvents, FALSE, INFINITE);
                                             status = WSAEnumNetworkEvents(Sock, SockEvent, &NetworkEvents);
                                             if (status == SOCKET_ERROR) {
                                              // ошибка
                                              DebugBreak();
                                             } else {
                                                 if ((NetworkEvents.lNetworkEvents & FD_READ) &&
                                                 (NetworkEvents.iErrorCode[FD_READ_BIT] == 0)) {
                                                 // есть данные для чтения - читаем
                                                 status = RecvHandler(port);
                                                 }
                                                 if ((NetworkEvents.lNetworkEvents & FD_WRITE) &&
                                                 (NetworkEvents.iErrorCode[FD_WRITE_BIT] == 0)) {
                                                 // возможна запись в сокет - записываем
                                                 status = XmitHandler(port);
                                                 }
                                             }


                                        Добавлено
                                        1. Не рекомендуется убивать поток извне
                                        ExpandedWrap disabled
                                              if (::WaitForSingleObject(m_hClientServerThread, 2000) == WAIT_TIMEOUT)
                                                  ::TerminateThread(m_hClientServerThread, 0);


                                        2. А где сопоставление сокета и Eventa? По моему, должно быть как-то так:
                                        ExpandedWrap disabled
                                             Event = WSACreateEvent();
                                             WSAEventSelect(Sock, Event, (FD_READ | FD_WRITE));

                                        А в цикле:
                                        ExpandedWrap disabled
                                             ...
                                             DWORD ret = WaitForSingleeObject(Event, FALSE, INFINITE);
                                             ...
                                             status = WSAEnumNetworkEvents(Sock, SockEvent, &NetworkEvents);
                                             if (status == SOCKET_ERROR) {
                                              // ошибка
                                              DebugBreak();
                                             } else {
                                                 if ((NetworkEvents.lNetworkEvents & FD_READ) &&
                                                 (NetworkEvents.iErrorCode[FD_READ_BIT] == 0)) {
                                                 // есть данные для чтения - читаем
                                                 status = RecvHandler();
                                                 }
                                                 if ((NetworkEvents.lNetworkEvents & FD_WRITE) &&
                                                 (NetworkEvents.iErrorCode[FD_WRITE_BIT] == 0)) {
                                                 // возможна запись в сокет - записываем
                                                 status = XmitHandler();
                                                 }
                                             }
                                          потоки - это все мелочи
                                          в конце концов они не влияют на работоспособность остального кода

                                          главный вопрос - почему код не работает как надо

                                          Добавлено
                                          popsa, точно !
                                          добавил после Listen accept

                                          ExpandedWrap disabled
                                                m_pServerClientSocket2 = accept(m_pServerClientSocket, NULL, NULL);

                                          и send переделал в

                                          ExpandedWrap disabled
                                                nNetOpResult = send(m_pServerClientSocket2, (char*)&szDataSize, sizeof(szDataSize), 0);


                                          все равно не работает :(

                                          Добавлено
                                          о - заработало

                                          1) пришлось и инициализацию сервера сунуть в отдельный поток (чтобы не висеть на accept)
                                          2) при неудачном recv не выходить из потока а крутиться в цикле

                                          теперь надо по-умному потоки прикрутить
                                          0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                          0 пользователей:


                                          Рейтинг@Mail.ru
                                          [ Script execution time: 0,0673 ]   [ 16 queries used ]   [ Generated: 27.04.24, 16:32 GMT ]