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

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> WinSock_v2.0 - WSA*Accept/Read/Send & Events; Использование WinSock с событиями; 
:(
    Опции темы
MuForum
  Дата 21.8.2009, 02:50 (ссылка) |    (голосов:3) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 427
Регистрация: 13.6.2007
Где: Молдова, Кишинев

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



WinSock_v2.0 - WSA*Accept/Read/Send & Events

Использование WinSock с событиями;

[hr][/hr]

Введение
Общие вопросы
Событийная модель в WinSock
Часть 1: Подключение WinSock_v2.0;
Часть 2: Инициализация начальных структуру/функций/событий; Подготовка к прослушиванию подключений;
Часть 3: Прослушивание подключений в отдельном потоке;
Часть 4: Установка соединения;
Часть 5: Обработка сообщений от клиента;
Часть 6: Дополнительные функции;
Заключение
Список использованной литературы и Интернет ресурсов;

------


# Введение:
Доброе время суток.
Достаточно долгое время я пытался перейти на WSA* функции, но постоянно сталкивался с разнообразными проблемами, ответы на которые в интернете не находил.
Так же, мягко говоря, расстраивал тот факт, что статей именно по WinSock_v2.0 (WSA*) нет, не одной нормально статьи, что собственно и побудило меня к написанию данной статьи.


# Общие вопросы:

# Вопрос: Под какую среду программрования написана статья?
# Ответ: C++ Builder, но переделать под любую другую среду программирования проблем не составит.


# Вопрос: Под какую операционную систему написан код?
# Ответ: Семейство Windows;


# Вопрос: Чем отличаются обычные функции от WSA*?
# Ответ:
- Обычные функции - это виндовская реализация интерфейса Беркли-сокетов.
- WSA*() - Это родные функции операционной системы Windows; (Windows Socket API)


# Вопрос: Что будет рассматриваться в данной статье?
# Ответ: В данной статье будет рассматриваться модель Windows Socket (WinSock) v2.0;
- WSA* функции.
- Использование событий.


# Вопрос: Какие проблемы поможет понять/решить данная статья?
# Ответ: Данная статья поможет вам решить следующие проблемы:
  1.  Проблемы с подключением к серверу через некоторое время после последнего подключения.
    - Accept/WSAAccept когда в режиме ожидания долгое время, то после возникают существенные проблемы с подключением.
  2.  Проблемы с принятием данных WSARecv() при помощи событий.
    - Проблема с возвратом WSARecv() значения -1;


# Событийная модель в WinSock:
Цитата(Gregory Liokumovich)

Сразу оговорюсь, что поскольку я занимаюсь программированием под Windows, то и говорить буду про реализацию сокетов под эту платформу.
WinSock позволяет работать с сокетами в рамках трех подходов, против двух классических. А именно:

  •  Обычная блокирующая передача данных;
  •  Ннеблокирующая передача данных;
  •  Событийно ориентированная передача данных.

Лично я предпочитаю третий метод, и ниже попытаюсь изложить основные причины.

# Немного вводной информации:

Основные функции:

  •  WSACreateEvent() --- создать новое событие;
  •  WSACloseEvent() --- удалить событие;
  •  WSAEventSelect() --- связать событие с сокетом и его внутренним событием (пришли новые данные, готов к передаче и т.д.);
  •  WSAWaitForMultipleEvents() --- ожидание событий;


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

Что интересно тип WSAEVENT является просто переопределением типа HANDLE со всеми вытекающими отсюда возможностями.

# Причина первая, эстетическая:

Общеизвестный факт, что все ПО развивается в сторону унификации интерфейса, это позволяет значительно упростить и ускорить его использование для пользователя. Вполне логично, что унификация программного API приводит к более эффективному и грамотному его использованию программистами, которые выступают в роли потребителей API. Так вот, с этой точки зрения событийный подход с известной всем windows программистам функцией WaitForMultipleObject (пусть даже с каким-то префиксом) явно упрощает использование сокетов.

Кроме того, лично мне следующий фрагмент кода:
Код

res = WSAWaitForMultipleObject(5, Events, FALSE, WSA_INFINITE, FALSE);
if (res == WSA_WAIT_FAILED)    
{
    //...
}
index = res;
WSAEnumNetworkEvents(sockets[index], Events[index], &info);
if (info.lNetworkEvents & FD_READ)
{
    // принимаем новые данные;
}

кажется намного более понятным и приятным чем этот:
Код

int res = select(0, &read, &write, &error, NULL);
if (res == SOCKET_ERROR)
{
    //...
}
for(int i = 0; i < socket.size(); i++) 
{
    if (FD_ISSET(socket[i], &read))
  // принимаем данные
}

Как видно и вышенаписанного в событийном подходе мы исходим от события, мы знаем для какого сокета есть новости. Во втором же случае, мы не знаем, что произошло и вынуждены перебирать все варианты. В первом случае мы оперируем массивами и событиями, во втором же случае неочевидными структурами и макросами.

# Причина вторая, элегантная:
Используя select или WSAWaitForMultipleEvents мы в любом случае не можем удалять или добавлять соединения во время работы данных функций, так как это приведет к сбою. А это наверняка придется делать.

Если в программе, только один поток то проблемы нет, но не надо забывать что обе эти функции поддерживают не более 64 сокетов. А если надо больше? писать select за select'ом и ставить выход по таймауту --- это очень некрасиво, но (что намного более важно) мы тут же теряем скорости реакции или скатываемся до элементарного опроса готов/не готов. А если надо поддерживать 500 соединений? Время реакции будет ужасным. В связи с этим хочу также отметить, что, по-моему, WSAWaitForMultipleEvents работает быстрее, чем select в режиме опроса, но это субъективное мнение --- цифрами подтвердить не могу.

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

Предположим поток 1 хочет добавить сокет в обработчик потока 2. В это время поток 2, выполняет select (или WSAWaitForMultipleEvents). Что прикажете делать? Что делать в случае select я, честно говоря, даже не знаю. При использовании событий я нашел, по-моему, неплохой и достаточно красивый выход. Создается одно пустое событие, которое не привязано к конкретному сокету. Это событие добавляется к остальным, которых дожидается WSAWaitForMultipleEvents (при этом число сокетов на поток уменьшается до 63). И вот в тот самый момент, когда мне надо вывести Поток два из "комотозного" состояния, я просто активирую это событие и все. То есть я использую события от сокета вместе и наравне с другими событиями. И отсюда вытекает еще одна более принципиальная причина.

# Причина третья, принципиальная:
Если задуматься на тему что такое поступление новых данных в сокет или, например, что такое закрытие сокета с другой стороны. Можно придти к простому выводу --- это события. Такие же события, как наступления времени Х или любое другое событие в программе. Более того, абсолютнозаконна постановка вопроса: "ждем пока произойдет какое-нибудь событие или пока придут данные от сокета". Поэтому это правильно и логично, что и работа с сокетами должна строится на событиях. 
 


# Часть 1: Подключение WinSock_v2.0;
Код

// Заметка: Данные строчки необходимо написать после всех подключений модулей;
#pragma comment(lib, "ws2_32.lib")
#include <winsock2.h>



# Часть 2: Инициализация начальных структуру/функций/событий; Подготовка к прослушиванию подключений;
Код

// Шаг 1: Инициализация дополнительных, нужных переменных;
int iRes = 0;
int iErrorCode = 0;
WSADATA wsaData;
SOCKET m_sListen; // Слушающий сокет;
WSAEVENT m_hEvent; // Событие FD_ACCEPT;
HANDLE m_hKillEvent;
bool m_bShouldStopListenThread = false;
HANDLE hThread; // Хэндел слушающего потока;
UINT threadID;
// Шаг 2: Инициализация WinSock_v2.0;
iRes = WSAStartup(MAKEWORD(2, 2), &wsaData);
if(iRes != 0)
{
    iErrorCode = WSAGetLastError();
    WLog("WSAStartup() failed with error: %d", iErrorCode);
    return Result;
}
// Шаг 3: Инициализация сокета;
m_sListen = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
if(m_sListen == INVALID_SOCKET)
{
    iErrorCode = WSAGetLastError();
    WLog("WSASocket() failed with error: %d", iErrorCode);
    return Result;
}
// Шаг 4: Создаем пустое событие;
m_hEvent = WSA_INVALID_EVENT;
m_hEvent = WSACreateEvent();
if (m_hEvent == WSA_INVALID_EVENT)
{
    iErrorCode = WSAGetLastError();
    closesocket(m_sListen);
    WLog("WSACreateEvent() failed with error: %d", iErrorCode);
    return Result;
}
// Шаг 5: Задаемое событие/я, которое/ые нужно будет обрабатывать;
iRes = WSAEventSelect(m_sListen, m_hEvent, FD_ACCEPT);
if (iRes == SOCKET_ERROR)
{
    iErrorCode = WSAGetLastError();
    closesocket(m_sListen);
    WLog("WSAEventSelect() failed with error: %d", iErrorCode);
    return Result;
}
// Шаг 6: Заполянем спец.структуру; IP-Адрес; Порт;
sockaddr_in a;
a.sin_family = AF_INET;
a.sin_port = htons(cPort); // Задаём прослушивающий порт;
a.sin_addr.S_un.S_addr = htonl(INADDR_ANY); // Для всех сетевых интерфейсов;
// Шаг 7: Занимаем порт в системе;
iRes = bind(m_sListen, (sockaddr*)&a, sizeof(sockaddr));
if(iRes == SOCKET_ERROR)
{
    iErrorCode = WSAGetLastError();
    closesocket(m_sListen);
    WLog("bind() to the port '%d' failed with error: %d", cPort, iErrorCode);
    return Result;
}
// Шаг 8: Устанавливаем количество одновременных прослушиваний для сокета;
iRes = listen(m_sListen, 5);
if(iRes == SOCKET_ERROR)
{
    iErrorCode = WSAGetLastError();
    closesocket(m_sListen);
    WLog("listen() failed with error: %d", iErrorCode);
    return Result;
}
// Шаг 9: Создаём спец.поток для прослушивания подключений;
hThread = (HANDLE)_beginthreadex(NULL, // Защита
    0, // Размер стэка - по умолчанию;
    ListenThreadProc, // Имя функции;
    (void*) this, // Передача указателя на данный класс;
    0, // Инициализация флага;
    &threadID); // Адрес потока;



# Часть 3: Прослушивание подключений в отдельном потоке;
Код

// Прототип функции;
unsigned __stdcall ListenThreadProc(LPVOID lParam);
...
WSANETWORKEVENTS    m_events;
...
unsigned __stdcall ListenThreadProc(LPVOID lParam)
{
    // Шаг 1: Приводим аргумент к классу, с которого было создание данного потока;
    TSocket* pThis = reinterpret_cast<TSocket*>(lParam);
    // Шаг 2: Инициализация дополнительных, нужных переменных;
    DWORD dwRes = 0;
    int iRes = 0;
    int iErrorCode = 0;
    bool bShouldStop = false;
    // Шаг 3: Создаём цикл для прослушивания сокета;
    while(!pThis->m_bShouldStopListenThread)
    {
        // Шаг 4: Делаем задержку на прослушивание события о выходе из цикла;
        // Если событие сработало, то мы выходим;
        if (WaitForSingleObject(pThis->m_hKillEvent, 100) == WAIT_OBJECT_0)
        {
            pThis->m_bShouldStopListenThread = true;
            break;
        }
        // ----
        // Шаг 4: Ожидаем какого-либо события;
        dwRes = WSAWaitForMultipleEvents(1, // Кол-во прослушивающих событий;
                                     &pThis->m_hEvent, // Указатель на событие;
                                     FALSE, // Ожидать пока случиться все события;
                                     100, // Кол-во мсек для прослушивания; (WSA_INFINITE - бесконечное ожидание)
                                     FALSE); // Используется для перекрытого ввода-ввыода;
        // ----
        // Шаг 5: Проверка возвращаемого значения;
        if (dwRes == WSA_WAIT_TIMEOUT) continue;
        // Шаг 6: Получения списка событий, которые произошли;
        iRes = WSAEnumNetworkEvents(pThis->m_sListen, pThis->m_hEvent, &pThis->m_events);
        if (iRes == SOCKET_ERROR)
        {
            iErrorCode = WSAGetLastError();
            WLog("[%s]  %s: %d", "ListenThreadProc", "WSAEnumNetworkEvents() failed with error", iErrorCode);
            pThis->m_bShouldStopListenThread = true;
            break;
        }
        // ----
        pThis->ProcessMessage();
    }
    // ----
    return 0; // Нормальный выход из потока;
}
//---------------------------------------------------------------------------

void __fastcall TSocket::ProcessMessage()
{
    // Шаг 7: Осуществляем выбор события;
    // Заметка: Не советую использовать switch(), так как если у вас несколько событий, то произойдёт обработка только одного события;
    if(m_events.lNetworkEvents & FD_ACCEPT)
    {
        if (m_events.iErrorCode[FD_ACCEPT_BIT] == 0)
        {
            OnAccept();
        }
        else
        {
            m_iErrorCode = WSAGetLastError();
            WLog("[%s->%s]  %s: %d", "TSocket", "ProcessMessage", "FD_ACCEPT failed with error", m_iErrorCode);
            m_bShouldStop = true;
        }
    }
}
//---------------------------------------------------------------------------




# Часть 4: Установка соединения;
Код

class TClientContext:
{
    friend class TSocket;
    friend DWORD WINAPI ServerWorkerThread(LPVOID lParam);
    // ----
    private:
        TSocket                *m_pSocket;
        // ----
        DWORD                m_dwWaitForSingleObjectValue;
        DWORD                m_dwWaitForMultipleEvents;
        DWORD                m_dwMaxSizeOfReadBuf;
        DWORD                m_dwWaitEventsCount;
        // Input Elements for Winsock
        WSABUF                m_wsaInBuf;
        BYTE                *m_pInBuf;
        DWORD                m_dwRecvBytes;
        DWORD                m_dwRecvFlags;
        int                    m_iRecvRes;
        WSAOVERLAPPED        m_WSARecvOverlapped;
        // ----
        HANDLE                m_ThreadHandle;
        DWORD                m_ThreadId;
        // ----
        int                    m_iRes;
        DWORD                m_dwRes;
        int                m_iErrorCode;
        // ---
        SOCKADDR_IN            m_SockAddr;
        IN_ADDR                m_SockInAddr;
        AnsiString            m_IPAddress;
        // ----
        WSAEVENT            m_EventArray[2];
        WSAEVENT            m_hEvent;
        WSANETWORKEVENTS    m_NetworkEvents;
        HANDLE                m_hKillEvent;
        // ----
        void __fastcall ProcessMessage();
        // ----
        void __fastcall OnRead();
        void __fastcall OnDisconnect();
        // ----
        void __fastcall PacketCore(LPBYTE Packet, int len);
        void __fastcall DisconnectUser();
    public:
        TClientContext() {};
        ~TClientContext() {};
        // ----
        void __fastcall InitializingClass();
        void __fastcall PrepareClass();
        bool __fastcall PrepareSocket();
        void __fastcall PrepareSocketToDelete();
        void __fastcall PrepareClassToDelete();
        void __fastcall StopListen() { m_bShouldStop = true; }
        bool __fastcall GetListenStatus() { return !m_bShouldStop; };
        // ----
        DWORD __fastcall GetWaitEventsCount() { return m_dwWaitEventsCount; };
        DWORD __fastcall GetWaitForSingleObjectValue() { return m_dwWaitForSingleObjectValue; }
        DWORD __fastcall GetWaitForMultipleEvents() { return m_dwWaitForMultipleEvents; }
        DWORD __fastcall GetMaxSizeOfReadBuf() { return m_dwMaxSizeOfReadBuf; };
}
//---------------------------------------------------------------------------

void __fastcall TSocket::OnAccept()
{
    // Шаг 1: Проверка глобальный переменных;
    if (g_bTimeToKill || g_bDisconnectAll) return;
    // Шаг 2: Инициализация дополнительных, нужных переменных;
    int nLen = sizeof(SOCKADDR_IN);
    // Шаг 3: Установка соединения;
    // Заметка: Советую использовать именно функцию Accept();
    // WSAAccept() возвращает управления потоку сразу, без проверки успошности;
    // Accept() возвращает настоящую проверку успешности;
    ClientSocket = accept(g_sListen_TCP, (LPSOCKADDR)&SockAddr, &nLen);
    if (ClientSocket == SOCKET_ERROR)
    {
        m_iErrorCode = WSAGetLastError();
        if (m_iErrorCode != WSAEWOULDBLOCK)
        {
            WLog("[%s->%s]  %s: %d", "TSocket", "OnAccept", "accept() failed with error", m_iErrorCode);
            return;
        }
    }
    // ----
    AddNewUser(ClientSocket, SockAddr);
}
//---------------------------------------------------------------------------

TClientContext* __fastcall TSocket::AddNewUser(SOCKET sSocket, SOCKADDR_IN SockAddr)
{
    TClientContext* pContext = new TClientContext();
    // ----
    pContext->PrepareClass();
    // ----
    pContext->m_sListen            = sSocket;
    pContext->m_SockAddr        = SockAddr;
    pContext->m_iProtocolMode    = m_iProtocolMode;
    // ----
    memcpy(&pContext->m_SockInAddr, &pContext->m_SockAddr.sin_addr, sizeof(IN_ADDR));
    pContext->m_IPAddress        = inet_ntoa(pContext->m_SockInAddr);
    // ----
    bResult = pContext->PrepareSocket();
    // ----
    if(bResult)
    {
        pContext->m_ThreadHandle = CreateThread(NULL, 0, ClientWorkerThread, (void*)pContext, 0, &pContext->m_ThreadId);
    }
    else
    {
        pContext->PrepareSocketToDelete();
        pContext->PrepareClassToDelete();
        delete pContext;
        pContext = NULL;
    }
    // ----
    return pContext;
}
//---------------------------------------------------------------------------




# Часть 5: Обработка сообщений от клиента;
Код

// Прототип функции;
DWORD WINAPI ServerWorkerThread(LPVOID lParam);
...
DWORD WINAPI ServerWorkerThread(LPVOID lParam)
{
    // Шаг 1: Получение указателя на класс от клиента;
    TClientContext *pThis = reinterpret_cast<TClientContext*>(lParam);
    // Шаг 2: Инициализация дополнительных, нужных переменных;
    int iRes            = 0;
    DWORD dwRet            = 0;
    int iErrorCode        = 0;
    // Шаг 3: Создаём цикл для прослушивания сокета;
    while(pThis->GetListenStatus())
    {
        if (WaitForSingleObject(pThis->m_hKillEvent, pThis->GetWaitForSingleObjectValue()) == WAIT_OBJECT_0)
        {
            pThis->StopListen();
            break;
        }
        // ----
        dwRes = WSAWaitForMultipleEvents(pThis->GetWaitEventsCount(),
                                        pThis->m_EventArray,
                                        FALSE,
                                        pThis->GetWaitForMultipleEvents(),
                                        FALSE);
        // ----
        switch(dwRes)
        {
            case WSA_WAIT_TIMEOUT:
            {
                continue;
            }
            break;
            case WSA_WAIT_FAILED:
            {
                iErrorCode = WSAGetLastError();
                // ----
                pThis->WLog(1, "[%s->%s] %s: %d; IP-Address: %s", "TClientContext", "ClientThreadProc",
                        "WSAWaitForMultipleEvents() failed with error", iErrorCode, pThis->m_IPAddress.c_str());
                // ----
                pThis->StopListen();
            }
            break;
        }
        // ----
        if(!pThis->GetListenStatus()) break;
        // ----
        dwEventIndex = dwRes - WSA_WAIT_EVENT_0;
        // ----
        iRes = WSAEnumNetworkEvents(pThis->m_sListen,
                                    pThis->m_EventArray[dwEventIndex],
                                    &pThis->m_NetworkEvents);
        // ----
        if (iRes == SOCKET_ERROR)
        {
            iErrorCode = WSAGetLastError();
            // ----
            pThis->WLog(1, "[%s->%s] %s: %d; IP-Address: %s", "TClientContext", "ClientThreadProc",
                        "WSAEnumNetworkEvents() failed with error", iErrorCode, pThis->m_IPAddress.c_str());
            // ----
            pThis->StopListen();
            // ----
            break;
        }
        // ----
        pThis->ProcessMessage();
    }
    // ----
    pThis->PrepareSocketToDelete();
    // ----
    // Шаг 9: Удаление записи из списка;
    pThis->m_pSocket->DisconnectUser(pThis->m_dwListIndex);
}
//---------------------------------------------------------------------------

void __fastcall TClientContext::ProcessMessage()
{
    // Шаг 11: Осуществляем выбор события;
    // Заметка: Не советую использовать switch(), так как если у вас несколько событий, то произойдёт обработка только первого события;
    if(m_NetworkEvents.lNetworkEvents & FD_READ)
    {
        if (m_NetworkEvents.iErrorCode[FD_READ_BIT] == 0)
        {
            OnRead();
        }
        else
        {
            WLog("[%s->%s] %s: %d; IP-Address: %s", "TClientContext", "ProcessMessage",
                    "FD_READ failes with error", m_NetworkEvents.iErrorCode[FD_READ_BIT], m_IPAddress);
        }
    }
    // ----
    if(m_NetworkEvents.lNetworkEvents & FD_CLOSE)
    {
        if (m_NetworkEvents.iErrorCode[FD_CLOSE_BIT] == 0)
        {
            OnDisconnect();
        }
        else
        {
            WLog("[%s->%s] %s: %d; IP-Address: %s", "TClientContext", "ProcessMessage",
                    "FD_CLOSE failes with error", m_NetworkEvents.iErrorCode[FD_CLOSE_BIT], m_IPAddress);
            m_bShouldStop = true;
        }
    }
}
//---------------------------------------------------------------------------

void __fastcall TClientContext::OnRead()
{
    ZeroMemory(&m_WSARecvOverlapped, sizeof(WSAOVERLAPPED));
    // -----
    m_wsaInBuf.len = GetMaxSizeOfReadBuf();
    m_wsaInBuf.buf = m_pInBuf;
    // ----
    m_iRecvRes = WSARecv(m_sListen, &m_wsaInBuf, 1, &m_dwRecvBytes, &m_dwRecvFlags, &m_WSARecvOverlapped, NULL);
    // ----
    if(m_iRecvRes == SOCKET_ERROR)
    {
        m_iErrorCode = WSAGetLastError();
        if(m_iErrorCode != WSA_IO_PENDING)
        {
            DisconnectUser();
        }
    }
    // ----
    if (m_dwRecvBytes > 0 && m_dwRecvBytes < GetMaxSizeOfReadBuf())
    {
        PacketCore(m_sListen, m_pInBuf, m_dwRecvBytes);
    }
}
//---------------------------------------------------------------------------

void __fastcall TClientContext::InitializingClass()
{
    m_dwMaxSizeOfReadBuf            = 1024;
    // ----
    m_pInBuf                        = new BYTE[GetMaxSizeOfReadBuf()];
    // ----
    m_wsaInBuf.buf                    = m_pInBuf;
    m_wsaInBuf.len                    = GetMaxSizeOfReadBuf();
    // ----
    m_dwWaitForSingleObjectValue    = 100;
    m_dwWaitForMultipleEvents        = 100;
    // ----
    m_dwWaitEventsCount                = 0;
    memset(m_EventArray, 0, sizeof(WSAEVENT) * 2);
    // ----
    m_hKillEvent                    = CreateEvent(NULL, TRUE, FALSE, NULL);
    // ----
    PrepareClass();
}
//---------------------------------------------------------------------------

void __fastcall TClientContext::PrepareClass()
{
    m_sListen                        = INVALID_SOCKET;
    // ----
    ZeroMemory(m_pInBuf, GetMaxSizeOfReadBuf());
    // ----
    m_iErrorCode                    = 0;
    m_dwRecvBytes                    = 0;
    m_iRecvRes                        = 0;
    // ----
    memset(&m_SockAddr, 0, sizeof(SOCKADDR_IN));
    memset(&m_SockInAddr, 0, sizeof(IN_ADDR));
    m_IPAddress                        = "";
    // ----
    m_hEvent                        = WSA_INVALID_EVENT;
    // ----
    m_bManualStop                    = false;
    m_bShouldStop                    = false;
}
//---------------------------------------------------------------------------

bool __fastcall TClientContext::PrepareSocket()
{
    m_hEvent = WSACreateEvent();
    if (m_hEvent == WSA_INVALID_EVENT)
    {
        m_iErrorCode = WSAGetLastError();
        WLog("[%s] %s: %d; IP-Address: %s", "TClientContext", "WSACreateEvent() failed with error", m_iErrorCode, m_IPAddress.c_str());
        m_bShouldStop = true;
    }
    // ----
    m_iRes = WSAEventSelect(m_sListen, m_hEvent, FD_READ | FD_CLOSE);
    if (m_iRes == SOCKET_ERROR)
    {
        m_iErrorCode = WSAGetLastError();
        WLog("[%s] %s: %d; IP-Address: %s", "TClientContext", "WSAEventSelect() failed with error", m_iErrorCode, m_IPAddress.c_str());
        m_bShouldStop = true;
    }
    // ----
    m_dwWaitEventsCount = 0;
    m_EventArray[m_dwWaitEventsCount] = m_hEvent;
    m_dwWaitEventsCount = 1;
    // ----
    return !m_bShouldStop;
}
//---------------------------------------------------------------------------

void __fastcall TClientContext::PrepareSocketToDelete()
{
    if(m_sListen != NULL && m_sListen != INVALID_SOCKET) TCloseSocket(m_sListen);
    m_sListen = INVALID_SOCKET;
    // ----
    if(m_hEvent != NULL && m_hEvent != WSA_INVALID_EVENT) WSACloseEvent(m_hEvent);
    m_hEvent = WSA_INVALID_EVENT;
}
//---------------------------------------------------------------------------

void __fastcall TClientContext::PrepareClassToDelete()
{
    m_bShouldStop = true;
    // ----
    if(m_sListen != NULL && m_sListen != INVALID_SOCKET) TCloseSocket(m_sListen);
    m_sListen = INVALID_SOCKET;
    // ----
    if(m_hEvent != NULL && m_hEvent != WSA_INVALID_EVENT) WSACloseEvent(m_hEvent);
    m_hEvent = WSA_INVALID_EVENT;
    // ----
    if(m_hKillEvent != NULL && m_hKillEvent != INVALID_HANDLE_VALUE) CloseHandle(m_hKillEvent);
    m_hKillEvent = INVALID_HANDLE_VALUE;
    // ----
    if(m_pInBuf != NULL)
    {
        delete[] m_pInBuf;
        m_pInBuf = NULL;
    }
}
//---------------------------------------------------------------------------




# Часть 6: Дополнительные функции;
Код

// Функция для закрытия сокета;
void TCloseSocket(SOCKET Socket)
{
    try
    {
        shutdown(Socket, SD_BOTH);
        closesocket(Socket);
    }
    catch(...) {}
}

// Функция отправки данных;
void SendBufWSA(SOCKET Socket, LPBYTE Packet, int len)
{
    try
    {
        WSABUF DataBuf;
        // ----
        DataBuf.len = len;
        DataBuf.buf = Packet;
        // ----
        DWORD SendBytes;
        WSAOVERLAPPED SendOverlapped;
        memset(&SendOverlapped, 0, sizeof(WSAOVERLAPPED));
        // ----
        WSASend(Socket, &DataBuf, 1, &SendBytes, 0, &SendOverlapped, NULL);
    }
    catch(...) {}
}



# Заключение:
Цитата

В выше изложенном материале изложены основные, не все, принципы написания серверного приложения используемого WinSock_v2.0 с использованием событий.
Мы рассмотрели некоторые важные моменты, сделали акцент на некоторых нюансах.
Подытоживая, можно сказать, что мы научились использовать асинхронные функции WinSock и работать с событиями.



# Список использованной литературы и Интернет ресурсов:
Цитата


  1.  MSDN;
  2.  Google;
  3.  Wiki;
  4.  CodeProject;
  5.  Событийная модель в WinSock;
  6.  Э. Джонс, Д. Оланд - Программирование в сетях Microsoft® Windows; (МАСТЕР-КЛАСС); (2002 год)
  7.  Джеффри Рихтер, Джейсон Кларк - Программирование серверных приложений для Windows 2000; (МАСТЕР-КЛАСС); (2001 год)
  8.  Джонсон М.Харт - Системное программирование в среде Windows; (Третье издание); (2005 год)




P.S. -> Статья будет по мере возможности дописываться.


Автор статьи Дамьян Александр, 21.08.2009.
-- Отредактировано 13.10.2009

Это сообщение отредактировал(а) MuForum - 13.10.2009, 10:27


--------------------
"Чтобы правильно задать вопрос, нужно знать большую часть ответа!" (Р. Шекли)
PM MAIL WWW ICQ Skype MSN   Вверх
J0ker
Дата 21.8.2009, 04:16 (ссылка)  | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Цитата(MuForum @  21.8.2009,  02:50 Найти цитируемый пост)
WSAWaitForMultipleEvents работает быстрее, чем select в режиме опроса, но это субъективное мнение --- цифрами подтвердить не могу

не на много, т.к.
Цитата(MuForum @  21.8.2009,  02:50 Найти цитируемый пост)
# Вопрос: Чем отличаются обычные функции от WSA*?
# Ответ:
- Обычные функции - это виндовская реализация интерфейса Беркли-сокетов.
- WSA*() - Это родные функции операционной системы Windows; (Windows Socket API)

системные POSIX функции винды - это обычно надстройка над winAPI

Цитата(MuForum @  21.8.2009,  02:50 Найти цитируемый пост)
Так вот, единственный разумный выход из описанной ситуации который мне видится --- это многопоточность. Каждый поток работает со своими соединениями и все замечательно. Но тут возникает (как это всегда бывает с потоками) проблемы взаимной синхронизации.

...и прочее блаблабла
а I/O completion ports заюзать не судьба?

Цитата(MuForum @  21.8.2009,  02:50 Найти цитируемый пост)
Проблемы с подключением к серверу через некоторое время после последнего подключения.
- Accept/WSAAccept когда в режиме ожидания долгое время, то после возникают существенные проблемы с подключением.

какие проблемы? я не думаю, что проблемы эти связаны с реализацией ОС функциональности - скорее тут что-то от ваших кривых ручек ломается


Цитата(MuForum @  21.8.2009,  02:50 Найти цитируемый пост)
Проблемы с принятием данных WSARecv() при помощи событий.
- Проблема с возвратом WSARecv() значения -1;

бредить изволите? SOCKET_ERROR (т.е., как вы выразились, -1) данная функция возвращает в случае ошибки - это не является проблемой - проверьте код WSAGetLastError и будет вам щастье

ЗЫЖ код не читал, но осуждаю  smile - не можете вы написать ничего путного с таким "пониманием" winAPI



Это сообщение отредактировал(а) J0ker - 21.8.2009, 04:29


--------------------
user posted image
PM MAIL   Вверх
MuForum
Дата 21.8.2009, 04:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 427
Регистрация: 13.6.2007
Где: Молдова, Кишинев

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



Цитата(J0ker)

Цитата(MuForum @  21.8.2009,  02:50 Найти цитируемый пост)
Так вот, единственный разумный выход из описанной ситуации который мне видится --- это многопоточность. Каждый поток работает со своими соединениями и все замечательно. Но тут возникает (как это всегда бывает с потоками) проблемы взаимной синхронизации.

...и прочее блаблабла
а I/O completion ports заюзать не судьба?

Вы бы для начала заглянули в смежные темы, а затем уже умничали...
+ Вам не мешало бы прочить заголовок темы!


Цитата(J0ker)

Цитата(MuForum @  21.8.2009,  02:50 Найти цитируемый пост)
Проблемы с принятием данных WSARecv() при помощи событий.
- Проблема с возвратом WSARecv() значения -1;

бредить изволите? SOCKET_ERROR (т.е., как вы выразились, -1) данная функция возвращает в случае ошибки - это не является проблемой - проверьте код WSAGetLastError и будет вам щастье
ЗЫЖ код не читал, но осуждаю  smile - не можете вы написать ничего путного с таким "пониманием" winAPI

Во-первых: Для того чтобы дать полную оценку, нужно ознакомится со всем материалам.
Во-вторых: Тон у вас не уместный, так как я вам ничего не обязан....
В-третьих: Статья пишется в 4 часа ночи...
В-четвертых: От вас ни одной статьи на данном форуме не увидел.
В-пятых: Я потратил кучу времени на оформление данной статьи...

Цитата(J0ker)

Цитата(MuForum @  21.8.2009,  02:50 Найти цитируемый пост)
Проблемы с подключением к серверу через некоторое время после последнего подключения.
- Accept/WSAAccept когда в режиме ожидания долгое время, то после возникают существенные проблемы с подключением.

какие проблемы? я не думаю, что проблемы эти связаны с реализацией ОС функциональности - скорее тут что-то от ваших кривых ручек ломается

А вы попробуйте простую схему, когда после Listen(), создаёте поток, в котором поток передаёт управление функции Accept().
А через несколько суток попробуйте подключится...


P.S. -> Хотите помочь улучшению статьи, как делайте "адекватные" замечания, а не умничайте, что вы великий "Гуру", в противном случае покиньте тему...
- Гагарин не с первого раза полетел...

Это сообщение отредактировал(а) MuForum - 21.8.2009, 04:49


--------------------
"Чтобы правильно задать вопрос, нужно знать большую часть ответа!" (Р. Шекли)
PM MAIL WWW ICQ Skype MSN   Вверх
J0ker
Дата 21.8.2009, 05:56 (ссылка)   | (голосов:4) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Цитата(MuForum @  21.8.2009,  04:31 Найти цитируемый пост)
Вы бы для начала заглянули в смежные темы, а затем уже умничали...

не думаю, что это изменит мое отношение к данной статье, поэтому и заглядывать не буду

Цитата(MuForum @  21.8.2009,  04:31 Найти цитируемый пост)
+ Вам не мешало бы прочить заголовок темы!

а вы напишете статью на тему забивания гвоздей микроскопом  smile 

Цитата(MuForum @  21.8.2009,  04:31 Найти цитируемый пост)
Во-первых: Для того чтобы дать полную оценку, нужно ознакомится со всем материалам.

я не собираюсь знакомиться со всем бредом, что льется на меня из сети
вводной части вполне достаточно, что-бы составить впечатление

Цитата(MuForum @  21.8.2009,  04:31 Найти цитируемый пост)
В-третьих: Статья пишется в 4 часа ночи...

вы так полагаете, тем она ценнее?  smile 

Цитата(MuForum @  21.8.2009,  04:31 Найти цитируемый пост)
В-четвертых: От вас ни одной статьи на данном форуме не увидел.

критики пишут только критические статьи - чем я сейчас и занимаюсь smile 

Цитата(MuForum @  21.8.2009,  04:31 Найти цитируемый пост)
В-пятых: Я потратил кучу времени на оформление данной статьи...

вы так полагаете, тем она ценнее?  smile 

Цитата(MuForum @  21.8.2009,  04:31 Найти цитируемый пост)
А вы попробуйте простую схему, когда после Listen(), создаёте поток, в котором поток передаёт управление функции Accept().
А через несколько суток попробуйте подключится...

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

Цитата(MuForum @  21.8.2009,  04:31 Найти цитируемый пост)
Хотите помочь улучшению статьи, как делайте "адекватные" замечания

нет, не хочу
замечания адекватные
прежде чем заявлять о проблеме в ОС необходимо свериться со спецификацией, поискать баги в своей реализации, поискать ссылку на данную проблему у производителя ОС и в сети и привести ее здесь если найдете, а если нет - посоветоваться с людьми и попытаться выяснить вопрос у производителя и только после того, как вы выяснили, что это ДЕЙСТВИТЕЛЬНО баг ОС заявлять об этом с вашей уверенностью


Это сообщение отредактировал(а) J0ker - 21.8.2009, 05:58


--------------------
user posted image
PM MAIL   Вверх
Олег2005
Дата 21.8.2009, 20:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Прошу автора и оппонента быть толерантнее - все таки первый опыт, и конечно же есть необоснованные заявления - select и WSAwaitForMultiple........это по сути очень равноценные функции - и там и там есть таймаут, и программа висит(ждет) того или иного события.
И насчет приема собщений сервером и тд.
Короче - по каждому пункту критики автору надо добиваться ясности от оппонента, а не посылать его лесом......
Иначе статья не получится - после первых же трудностей опускать руки.......
Ну и гляньте сюда:
http://forum.vingrad.ru/forum/topic-248292...lect/index.html
PM MAIL WWW MSN   Вверх
linya
Дата 22.8.2009, 17:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



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

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



   // Шаг 1: Приводим аргумент к классу, с которого было создание данного потока;
    TSocket* pThis = reinterpret_cast<TSocket*>(lParam);

поясните данную строку более подробно пожалуйста... точнее что такое TSocket , потому что дальше все понятно....

то есть вся реализация происходи в классе?

к примеру 
Код

class CServer{

public:
    CServer();
    virtual ~CServer();
    
    WSAEVENT Event;
//function
};


Код

CServer* pThis = reinterpret_cast<CServer*>(lParam);

// Шаг 5: Ожидаем какого-либо события;
        dwRet = WSAWaitForMultipleEvents(1, // Кол-во прослушивающих событий;
            &pThis->Event, // Указатель на событие;


я правильно понял?

2)непонятный  String
3)обрабочик ошибок.... да хотя бы такой

Код

             res = WSAStartup(MAKEWORD(2, 2),&wsadata);
        
    if(res!=0)
    {
        errorCode = WSAGetLastError();
        char buffer[255];
        sprintf(buffer,"%d",errorCode);

        string str = (string)"WSAStartup() failed with error: "  + buffer;
        MessageBoxA(0,(LPCSTR)str.c_str(),(LPCSTR)"Error",MB_ICONERROR);
    }



4) ClientWorkerThread простенький пример плиз...не перепутали c ServerWorkerThread?

Это сообщение отредактировал(а) linya - 22.8.2009, 21:07
PM MAIL   Вверх
MuForum
Дата 12.10.2009, 08:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 427
Регистрация: 13.6.2007
Где: Молдова, Кишинев

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



linya, ниже будет показан рабочий код под C++ Builder.

#  .cpp:
Код

DWORD WINAPI ClientThreadProc(LPVOID lParam)
{
    TClientContext *pThis = reinterpret_cast<TClientContext*>(lParam);
    // ----
    int        iRes            = 0;
    DWORD    dwRes            = 0;
    int        iErrorCode        = 0;
    DWORD    dwEventIndex    = 0;
    // ----
    try
    {
        while(pThis->GetListenStatus())
        {
            if (WaitForSingleObject(pThis->m_hKillEvent, pThis->GetWaitForSingleObjectValue()) == WAIT_OBJECT_0)
            {
                pThis->StopListen();
                break;
            }
            // ----
            dwRes = WSAWaitForMultipleEvents(pThis->GetWaitEventsCount(),
                                            pThis->m_EventArray,
                                            FALSE,
                                            pThis->GetWaitForMultipleEvents(),
                                            FALSE);
            // ----
            switch(dwRes)
            {
                case WSA_WAIT_TIMEOUT:
                {
                    continue;
                }
                break;
                case WSA_WAIT_FAILED:
                {
                    iErrorCode = WSAGetLastError();
                    // ----
                    pThis->WLog(1, "[%s->%s] %s: %d; IP-Address: %s", "TClientContext", "ClientThreadProc",
                            "WSAWaitForMultipleEvents() failed with error", iErrorCode, pThis->m_IPAddress.c_str());
                    // ----
                    pThis->StopListen();
                }
                break;
            }
            // ----
            if(!pThis->GetListenStatus()) break;
            // ----
            dwEventIndex = dwRes - WSA_WAIT_EVENT_0;
            // ----
            iRes = WSAEnumNetworkEvents(pThis->m_sListen,
                                        pThis->m_EventArray[dwEventIndex],
                                        &pThis->m_NetworkEvents);
            // ----
            if (iRes == SOCKET_ERROR)
            {
                iErrorCode = WSAGetLastError();
                // ----
                pThis->WLog(1, "[%s->%s] %s: %d; IP-Address: %s", "TClientContext", "ClientThreadProc",
                            "WSAEnumNetworkEvents() failed with error", iErrorCode, pThis->m_IPAddress.c_str());
                // ----
                pThis->StopListen();
                // ----
                break;
            }
            // ----
            pThis->ProcessMessage();
        }
        // ----
        pThis->PrepareSocketToDelete();
    }
    catch(exception &e)
    {
        pThis->WLog(1, "[%s->%s] %s: %s", "TClientContext", "ClientThreadProc", "try/catch", e.what());
    }
    // ----
    if(!pThis->m_bManualStop && pThis->m_pTCP != NULL) pThis->m_pTCP->DisconnectUser(pThis->m_dwListIndex);
    // ----
    // Normal Thread Exit Code;
    return 0;
}
//---------------------------------------------------------------------------

void __fastcall TClientContext::ProcessMessage()
{
    WLogDebug("[%s->%s] %s; %d;", "TClientContext", "ProcessMessage", "Enter", m_sListen);
    // ----
    if(m_bShouldStop) return;
    // ----
    if(m_NetworkEvents.lNetworkEvents & FD_READ)
    {
        if (m_NetworkEvents.iErrorCode[FD_READ_BIT] == 0)
        {
            OnRead();
        }
        else
        {
            WLog(1, "[%s->%s] %s: %d; IP-Address: %s", "TClientContext", "ProcessMessage",
                    "FD_READ failes with error", m_NetworkEvents.iErrorCode[FD_READ_BIT], m_IPAddress);
        }
    }
    // ----
    if(m_NetworkEvents.lNetworkEvents & FD_CLOSE)
    {
        if (m_NetworkEvents.iErrorCode[FD_CLOSE_BIT] == 0)
        {
            OnDisconnect();
        }
        else
        {
            /*
            WLogF("[%s->%s] %s: %d; IP-Address: %s", "TClientContext", "ProcessMessage",
                    "FD_CLOSE failes with error", m_NetworkEvents.iErrorCode[FD_CLOSE_BIT], m_IPAddress);
            */
            m_bShouldStop = true;
        }
    }
    // ----
    WLogDebug("[%s->%s] %s; %d;", "TClientContext", "ProcessMessage", "Exit", m_sListen);
}
//---------------------------------------------------------------------------

void __fastcall TClientContext::OnRead()
{
    WLogDebug("[%s->%s] %s; %d;", "TClientContext", "OnRead", "Enter", m_sListen);
    // ----
    try
    {
        ZeroMemory(&m_WSARecvOverlapped, sizeof(WSAOVERLAPPED));
        // -----
        m_wsaInBuf.len = GetMaxSizeOfReadBuf();
        m_wsaInBuf.buf = m_pInBuf;
        // ----
        m_iRecvRes = WSARecv(m_sListen, &m_wsaInBuf, 1, &m_dwRecvBytes, &m_dwRecvFlags, &m_WSARecvOverlapped, NULL);
        // ----
        if(m_iRecvRes == SOCKET_ERROR)
        {
            m_iErrorCode = WSAGetLastError();
            if(m_iErrorCode != WSA_IO_PENDING)
            {
                if(!m_bShouldStop && !m_bManualStop)
                {
                    DisconnectUser();
                }
            }
        }
        // ----
        if(m_dwRecvBytes > 0) SendDisassemblePacket(m_dwRecvBytes);
    }
    catch(exception &e)
    {
        WLog(1, "[%s->%s] %s: %s", "TClientContext", "OnRead", "try/catch", e.what());
    }
    // ----
    WLogDebug("[%s->%s] %s; %d", "TClientContext", "OnRead", "Exit", m_sListen);
}
//---------------------------------------------------------------------------

void __fastcall TClientContext::InitializingClass()
{
    m_dwMaxSizeOfReadBuf            = 10240;
    // ----
    m_pInBuf                        = new BYTE[GetMaxSizeOfReadBuf()];
    // ----
    m_wsaInBuf.buf                    = m_pInBuf;
    m_wsaInBuf.len                    = GetMaxSizeOfReadBuf();
    // ----
    m_dwWaitForSingleObjectValue    = 100;
    m_dwWaitForMultipleEvents        = 100;
    // ----
    m_dwWaitEventsCount                = 0;
    memset(m_EventArray, 0, sizeof(WSAEVENT) * 2);
    // ----
    m_hKillEvent                    = CreateEvent(NULL, TRUE, FALSE, NULL);
    // ----
    PrepareClass();
}
//---------------------------------------------------------------------------

bool __fastcall TClientContext::PrepareSocket()
{
    m_hEvent = WSACreateEvent();
    if (m_hEvent == WSA_INVALID_EVENT)
    {
        m_iErrorCode = WSAGetLastError();
        WLog(1, "[%s] %s: %d; IP-Address: %s", "TClientContext", "WSACreateEvent() failed with error", m_iErrorCode, m_IPAddress.c_str());
        m_bShouldStop = true;
    }
    // ----
    m_iRes = WSAEventSelect(m_sListen, m_hEvent, FD_READ | FD_CLOSE);
    if (m_iRes == SOCKET_ERROR)
    {
        m_iErrorCode = WSAGetLastError();
        WLog(1, "[%s] %s: %d; IP-Address: %s", "TClientContext", "WSAEventSelect() failed with error", m_iErrorCode, m_IPAddress.c_str());
        m_bShouldStop = true;
    }
    // ----
    m_dwWaitEventsCount = 0;
    m_EventArray[m_dwWaitEventsCount] = m_hEvent;
    m_dwWaitEventsCount = 1;
    // ----
    return !m_bShouldStop;
}
//---------------------------------------------------------------------------

void __fastcall TClientContext::PrepareSocketToDelete()
{
    if(m_sListen != NULL && m_sListen != INVALID_SOCKET) TCloseSocket(m_sListen);
    m_sListen = INVALID_SOCKET;
    // ----
    if(m_hEvent != NULL && m_hEvent != WSA_INVALID_EVENT) WSACloseEvent(m_hEvent);
    m_hEvent = WSA_INVALID_EVENT;
}
//---------------------------------------------------------------------------




#  .h:
Код

#ifndef TClientContextH
#define TClientContextH
//---------------------------------------------------------------------------

class TClientContext
{
    friend DWORD WINAPI ClientThreadProc(LPVOID lParam);
    // ----
    private:
        DWORD                m_dwListIndex;
        // ----
        TWLog                *m_pLog;
        // ----
        SOCKET                m_sListen;
        bool                m_bShouldStop;
        bool                m_bManualStop;
        bool                m_bIsFree;
        // ----
        DWORD                m_dwWaitForSingleObjectValue;
        DWORD                m_dwWaitForMultipleEvents;
        DWORD                m_dwMaxSizeOfReadBuf;
        DWORD                m_dwWaitEventsCount;
        // Input Elements for Winsock
        WSABUF                m_wsaInBuf;
        BYTE                *m_pInBuf;
        DWORD                m_dwRecvBytes;
        DWORD                m_dwRecvFlags;
        int                    m_iRecvRes;
        WSAOVERLAPPED        m_WSARecvOverlapped;
        // ----
        HANDLE                m_ThreadHandle;
        DWORD                m_ThreadId;
        // ----
        int                    m_iRes;
        DWORD                m_dwRes;
        int                m_iErrorCode;
        // ---
        SOCKADDR_IN            m_SockAddr;
        IN_ADDR                m_SockInAddr;
        AnsiString            m_IPAddress;
        // ----
        WSAEVENT            m_EventArray[2];
        WSAEVENT            m_hEvent;
        WSANETWORKEVENTS    m_NetworkEvents;
        HANDLE                m_hKillEvent;
        // ----
        void __fastcall ProcessMessage();
        // ----
        void __fastcall OnRead();
        void __fastcall OnDisconnect();
        // ----
        void __fastcall SendDisassemblePacket(int len);
        void __fastcall PacketCore(LPBYTE Packet, int len);
        void __fastcall DisconnectUser();
        void __fastcall TCloseSocket(SOCKET sSocket);
        // ----
        void WINAPI WLog(int Index, char* fmt, ...);
        void WINAPI WLogDebug(char* fmt, ...);
    public:
        TClientContext() {};
        ~TClientContext() {};
        // ----
        void __fastcall InitializingClass();
        void __fastcall PrepareClass();
        bool __fastcall PrepareSocket();
        void __fastcall PrepareSocketToDelete();
        void __fastcall PrepareClassToDelete();
        // ----
        void __fastcall StopListen() { m_bShouldStop = true; }
        bool __fastcall GetListenStatus() { return !m_bShouldStop; };
        // ----
        DWORD __fastcall GetWaitEventsCount() { return m_dwWaitEventsCount; };
        DWORD __fastcall GetWaitForSingleObjectValue() { return m_dwWaitForSingleObjectValue; }
        DWORD __fastcall GetWaitForMultipleEvents() { return m_dwWaitForMultipleEvents; }
        DWORD __fastcall GetMaxSizeOfReadBuf() { return m_dwMaxSizeOfReadBuf; };
        // ----
        DWORD __fastcall GetIndexOfList() { return m_dwListIndex; };
        bool __fastcall GetStatusOfFree() { return m_bIsFree; };
        // ----
        void __fastcall SetIndexOfList(DWORD dwIndex) { m_dwListIndex = dwIndex; };
        void __fastcall SetStatusOfFree(bool bStatus) { m_bIsFree = bStatus; };
};
//---------------------------------------------------------------------------
DWORD WINAPI ClientThreadProc(LPVOID lParam);
//---------------------------------------------------------------------------
#endif
//---------------------------------------------------------------------------



--------------------
"Чтобы правильно задать вопрос, нужно знать большую часть ответа!" (Р. Шекли)
PM MAIL WWW ICQ Skype MSN   Вверх
leo84
Дата 13.10.2009, 04:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



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

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



Опять ругаетесь.

Это сообщение отредактировал(а) leo84 - 13.10.2009, 04:22
PM MAIL   Вверх
Comm
Дата 13.10.2009, 04:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



MuForum,здравствуйте..советую не обращать внимание на неадекватную критику с элементами оскорбления от J0ker-а и продолжать делать то что получается =) 
Из собственного опыта знаю чем все это закончится (взаимным понижением репутации)

От себя скажу что было время когда я нуждался в подобной информации,но нигде ничего небыло на привычном нам языке =) Всё проверял методом проб и ошибок,да и то осталось много нюансов на которые ответов я так и не получил,так что инфа очень полезная...

P.S. Была ещё такая идея написать статью с самого начала со всеми функциями и моделями сетевого взаимодействия с последующим построением класса,ну и создания их потомков =))
P.S2.Всё ещё жду выхода одной книги !!!!



--------------------
=)))))
user posted image
PM MAIL ICQ   Вверх
MuForum
Дата 13.10.2009, 09:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 427
Регистрация: 13.6.2007
Где: Молдова, Кишинев

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



Цитата(Comm @ 13.10.2009,  04:23)
MuForum,здравствуйте..советую не обращать внимание на неадекватную критику с элементами оскорбления от J0ker-а и продолжать делать то что получается =) 
Из собственного опыта знаю чем все это закончится (взаимным понижением репутации)

От себя скажу что было время когда я нуждался в подобной информации,но нигде ничего небыло на привычном нам языке =) Всё проверял методом проб и ошибок,да и то осталось много нюансов на которые ответов я так и не получил,так что инфа очень полезная...

P.S. Была ещё такая идея написать статью с самого начала со всеми функциями и моделями сетевого взаимодействия с последующим построением класса,ну и создания их потомков =))
P.S2.Всё ещё жду выхода одной книги !!!!

Буду рад, если кто-то проявит инициативу и поможет улучшить статью.
- Я уже сам нашел два скольких момента в моей начальной статье. 
- В коде что опубликовал выше эта проблема уже решена, но статью ещё не переделал.


P.S. -> Сейчас ещё играюсь с портами завершения. (Тоже куча нюансов, которые нигде не обсуждаются, даже в книгах...)
- Тоже есть желание по завершению написать статью. Может кто-то поддержит.


--------------------
"Чтобы правильно задать вопрос, нужно знать большую часть ответа!" (Р. Шекли)
PM MAIL WWW ICQ Skype MSN   Вверх
Олег2005
Дата 13.10.2009, 09:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Цитата(Comm @  13.10.2009,  03:23 Найти цитируемый пост)
P.S2.Всё ещё жду выхода одной книги !!!!

Я - тоже smile 
PM MAIL WWW MSN   Вверх
MuForum
Дата 13.10.2009, 10:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 427
Регистрация: 13.6.2007
Где: Молдова, Кишинев

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



CommОлег2005 - Я сделал изменения в статье. Привёл к божескому виду и учёл моменты, которые ещё всплыли.
- Прошу прочитать статью и прокоментировать. Может ещё что-то нужно изменить, либо добавить.

Цитата(Comm)

P.S2.Всё ещё жду выхода одной книги !!!!

- Можно поинтересоваться, какую книгу вы всё ещё ожидаете?

Это сообщение отредактировал(а) MuForum - 13.10.2009, 10:36


--------------------
"Чтобы правильно задать вопрос, нужно знать большую часть ответа!" (Р. Шекли)
PM MAIL WWW ICQ Skype MSN   Вверх
leo84
Дата 13.10.2009, 13:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



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

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



Какая какая книга ?

Это сообщение отредактировал(а) leo84 - 13.10.2009, 13:02
PM MAIL   Вверх
Comm
Дата 13.10.2009, 13:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Цитата

Можно поинтересоваться, какую книгу вы всё ещё ожидаете?

Да не сочтите за рекламу =)
Книга от уважаемого Олег2005,ознакомившись с содержанием я обнаружил что в книге есть почти все что когда либо меня интересовало в сетевом программировании.
Пользуясь случаем спрошу,где можно почитать о программировании сетевых карт ?  спасибо за внимание !!!!





--------------------
=)))))
user posted image
PM MAIL ICQ   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Сети | Следующая тема »


 




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


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

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