Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Системное программирование и WinAPI > Ассинхронная работа socket'ов WinSock2


Автор: VID 5.7.2006, 08:37
 Привет!
 Появилась проблема с чтением данных с сокета, в режиме SOCK_DGRAM (без соединения) через функцию WSARecvFrom. Я читаю с указанием адреса процедуры завершения, которая должна будет вызваться системой при окончании приема датаграммы, но не вызывается  smile .
 Может кто сталкивался с подобной проблемой. MSDN примеров на эту тему не дает, инет тоже не кишит подобной информацией.
 Ниже привожу код, что и как вызывается. Прога - консольное приложение, далее планируется всю начинку запихнуть в dll

Код

#include "stdafx.h"
#include "winsock2.h"

WSADATA m_wsaData;
SOCKET sckt;
in_addr s;
sockaddr_in socketAddress, recvAddr;
WSABUF recvBuf;
WSAOVERLAPPED overlapped;
char buf[1024];

void CALLBACK CompletionRoutine(DWORD dwError, DWORD dwTransfered, LPWSAOVERLAPPED overlapped, DWORD dwFlags)
{
    // Processing received DHCP message;
    cout << "Gets a message on Client UDP port number of: " << 68 << endl;
    cout << "Received bytes number: " << dwTransfered << endl;
    cout << "Received buffer: " << recvBuf.buf << endl;
}

int main(int argc, char* argv[])
{
    // Check out socket asynchronous operation with CompletionRoutine
    {
    // Инициализируем WinSock2
        int iResult = WSAStartup(WINSOCK_VERSION, &m_wsaData);
        if (iResult != NO_ERROR)
        {
            cout << "Error at WSAStartup()" << endl;
            return 0;
        }

        // Создаем SOCKET об'ект
        sckt = WSASocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP, NULL, 0, WSA_FLAG_OVERLAPPED);

        // Enable broadcast address and allow other process binds to the same port.
        BOOL bOptVal = TRUE;
        int bOptLen = sizeof(BOOL);
        if (setsockopt(sckt, SOL_SOCKET, SO_BROADCAST, (char*)&bOptVal, bOptLen) == SOCKET_ERROR)// ||
            //setsockopt(sckt, SOL_SOCKET, SO_REUSEADDR, (char*)&bOptVal, bOptLen) == SOCKET_ERROR)
        {
            cout << "Error occur while set up socket options!!!" << endl;
            return -1;
        }

        // Set up the sockaddr structure.
        socketAddress.sin_family = AF_INET;
        socketAddress.sin_addr.s_addr = inet_addr("Мой Ip адрес");
        socketAddress.sin_port = htons(68); // Слушаем порт 68
        
        if (bind(sckt,(SOCKADDR*) &socketAddress, sizeof(socketAddress) ) == SOCKET_ERROR)
        {
            cout << "Error occur while bind socket!!!" << endl;
            return -1;
        }

        DWORD recvBytesNumber = 0,
              flags = 0;
        int fromLen = sizeof(recvAddr);
        overlapped.hEvent = NULL;
        recvBuf.buf = buf;
        recvBuf.len = 1024;
        int rc = WSARecvFrom(sckt, &recvBuf, 1, &recvBytesNumber, &flags, (SOCKADDR*) &recvAddr,
            &fromLen, &overlapped, &CompletionRoutine);
        if (rc == SOCKET_ERROR)
        {
            if (WSAGetLastError() == WSA_IO_PENDING)
            {
                cout << "Wait until data arrived" << endl;
            }
            else
            {
                cout << "Error occure while listening port 68" << endl;
                return -1;
            }
        }
        else
        {
            cout << "Gets a message on Client UDP port number of: 68" << endl;
            cout << "Received buffer: " << recvBuf.buf << endl;
        }
    }
    closesocket(sckt);
    WSACleanup();
    return 0;
}


Далее в другом месте посылаем сообщение в порт 68.
В блокирующем режиме я его получаю, а в неблокирующем функция обратного вызова CompletionRoutine не вызывается  smile Почему? 

Автор: maxim1000 5.7.2006, 09:11
а где происходит ожидание прочтения?
а то он только начал читать, а программа переходит на closesocket, WSACleanup и вообще завершает процесс... 

Автор: VID 5.7.2006, 09:43
Мда, тут я урезал программку, поэтому некрасиво получилось, грубо говоря там бесконечный цикл перед закрытием сокета, то есть примерно так:
Код

char value = 0; // Переменная для служебных целей
bool exit = false;
while(!exit)
{
     value = getchar();
     switch(value)
     {
          case '1': // и так далее
          case '5' exit = true; break;
     }
}
closesocket(socket);


Примерно так это выглядит, на деле сложнее, но суть не меняется я просто ожидаю. Делал и в отдельном потоке прослушивание совета и т.д и т.п, но результат один. 

Автор: maxim1000 5.7.2006, 12:22
на самом деле всё именно зависит от того, как ждать
если бы Windows прерывала поток в любом месте и выполняла бы CompletionRoutine, наверняка, рано или поздно бы произошёл сбой - никакой ведь синхронизации
поэтому делается по-другому:
процедура окончания вызывается только, если поток находится в прерываемом состоянии
для этого можно использовать, например, функцию SleepEx 

Автор: VID 5.7.2006, 12:59
maxim1000 спасибо, на самом деле так и оказалось. Я и думать забыл про синхронизацию  smile 
Спасибо. 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)