Работа с сокетом WINSOCK - PullRequest
       9

Работа с сокетом WINSOCK

0 голосов
/ 09 ноября 2010

Вот метод класса (все методы и переменные объявлены общедоступными). ПРИМЕЧАНИЕ. DiscoverWinsockLib выполняет WSAStartup, и я знаю, что эта часть работает.Он также выполняет LoadLibrary и находит точки входа DLL для перечисленных ниже функций, переименованный с префиксом lpfn_.

Независимо от того, что я делаю, я не могу решить, почему я получаю условие ошибки при работе сокета наnon-socket в теме.

Любая помощь будет принята с благодарностью.

bool __fastcall TRANSPORT::Establish (const char *host, int port, int timeout)
{
bool rFlag;
int rval;

rFlag = false;
DiscoverWinsockLib();

if( WSH )
{
    hostEntry = gethostbyname(host);

    if( !hostEntry )
    {
        LastErrorCode = lpfn_WSAGetLastError();
        lpfn_WSACleanup();
        SetErrorMsg();
    }
    else
    {
        CSocket = lpfn_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

        if (CSocket == INVALID_SOCKET)
        {
            LastErrorCode = lpfn_WSAGetLastError();
            SetErrorMsg();
            lpfn_WSACleanup();
        }
        else
        {

            RxDataBuf.len = RXDATA_BUFSIZE;
            RxDataBuf.buf = RxBuffer;
            RxOverlapped.hEvent = lpfn_WSACreateEvent();

            if(RxOverlapped.hEvent == WSA_INVALID_EVENT)
            {
                LastErrorCode = lpfn_WSAGetLastError();
                SetErrorMsg();
                SocketShutdown();
                //lpfn_closesocket(CSocket);
            }
            else
            {
                if(lpfn_WSAEventSelect(CSocket, RxOverlapped.hEvent, FD_ALL_EVENTS) == SOCKET_ERROR)
                {
                    LastErrorCode = lpfn_WSAGetLastError();
                    SetErrorMsg();
                    lpfn_closesocket(CSocket);
                    lpfn_WSACloseEvent(RxOverlapped.hEvent);
                }
                else
                {
                    hThreadIO = CreateThread(0, 0, ProcessEvents, (void *)this, 0, &ThreadID);

                    // Try to connect to the server
                    serverInfo.sin_family = AF_INET;
                    serverInfo.sin_addr = *((LPIN_ADDR)*hostEntry->h_addr_list);
                    serverInfo.sin_port = htons(port);

                    if( lpfn_connect(CSocket, (LPSOCKADDR)&serverInfo, sizeof(struct sockaddr)) == SOCKET_ERROR  )
                    {
                        LastErrorCode = lpfn_WSAGetLastError();
                        if( LastErrorCode != WSAEWOULDBLOCK )
                        {
                            SetErrorMsg();
                            SocketShutdown();
                        }
                        else
            rFlag = true;
                    }
                    else
                        rFlag = true;
                }
            }
        }
    }
}
return(rFlag);
}

А вот упомянутая выше тема:

DWORD WINAPI ProcessEvents(void *pParam)
{

TRANSPORT *T;
WSANETWORKEVENTS NetEvents;
DWORD EIndex;
DWORD  rc;
bool Failure;


T = (TRANSPORT *)pParam;
Failure = false;

do
{
    EIndex = T->lpfn_WSAWaitForMultipleEvents( 1, &T->RxOverlapped.hEvent, false, 3000, true );

    if( EIndex == WSA_WAIT_FAILED )
    {
        T->LastErrorCode = T->lpfn_WSAGetLastError();
        T->SetErrorMsg();
        Failure = true;
    }

    if( EIndex == WSA_WAIT_TIMEOUT )
    {
        if( T->OnConnectTimeout )
            T->OnConnectTimeout(T);

        Failure = true;
    }

}while( EIndex != WAIT_IO_COMPLETION && !Failure );

if( Failure )
    return(EIndex);

// Get the event(s) that occurred and their associated error array
if(T->lpfn_WSAEnumNetworkEvents(T->CSocket, T->RxOverlapped.hEvent, &NetEvents) == SOCKET_ERROR)
{
    T->LastErrorCode = T->lpfn_WSAGetLastError();
    T->SetErrorMsg();
    return(EIndex);
}

// =================================================================
// Code above fetches the event that woke this thread up
// Code below deals with the events as they are detected
// =================================================================

if( NetEvents.lNetworkEvents & FD_CONNECT  )
{
    if( T->OnConnect )
        T->OnConnect(T);

    T->lpfn_WSAResetEvent(T->RxOverlapped.hEvent);
}
else if( ( NetEvents.lNetworkEvents & FD_READ) )
{
    rc = T->lpfn_WSARecv(T->CSocket, &T->RxDataBuf, 1, &T->RxBytes, &T->Flags, &T->RxOverlapped, NULL);
    EIndex = T->lpfn_WSAGetLastError();

    if( (rc == SOCKET_ERROR) && (EIndex != WSA_IO_PENDING || EIndex != WSAEWOULDBLOCK ) )
    {
        T->LastErrorCode = EIndex;
        T->SetErrorMsg();
    }
    else
    {
        rc = T->lpfn_WSAWaitForMultipleEvents(1, &T->RxOverlapped.hEvent, true, INFINITE, true);

        if(rc == WSA_WAIT_FAILED)
        {
            T->LastErrorCode = T->lpfn_WSAGetLastError();
            T->SetErrorMsg();
        }
        else
        {
            rc = T->lpfn_WSAGetOverlappedResult(T->CSocket, &T->RxOverlapped, &T->RxBytes, false, &T->Flags);
            if(!rc)
            {
                T->LastErrorCode = T->lpfn_WSAGetLastError();
                T->SetErrorMsg();
            }
            else
            {
                if( T->RxBytes > 0 && T->OnReceive )
                    T->OnReceive(T);

                T->lpfn_WSAResetEvent(T->RxOverlapped.hEvent);
            }
        }
    }
}

return(rc);
}

** ОБНОВЛЕНИЕ **Я обнаружил, что вызов EIndex = T-> lpfn_WSAWaitForMultipleEvents (1, & T-> RxOverlapped.hEvent, false, 3000, true);внутри функции Thread возвращается WSA_WAIT_FAILED

И если я отключаю функцию потока и проверяю возвращаемое значение lpfn_WSAWaitForMultipleEvents, вне потока сразу после вызова соединения я получаю действительное возвращаемое значение WSAEWOULDBLOCK.

Думая, что у меня может быть проблема с получением адреса изнутри потока, я изменил код потока следующим образом:

DWORD WINAPI ProcessEvents(void *pParam)
{
 ...

WSAEVENT events[1];

T = (TRANSPORT *)pParam;
Failure = false;


do
{
    events[0] = T->RxOverlapped.hEvent;
    EIndex = T->lpfn_WSAWaitForMultipleEvents( 1, events, false, 3000, true );

            ....

и мне все еще не удается сделать WSAWaitForMultipleEvents счастливым!

какие-либо мысли / предложения по этому поводу?

1 Ответ

0 голосов
/ 09 ноября 2010

Если connect () не удается, вы звоните SocketShutdown(). Предположительно, он закрывает сокет (вы не показывали этот код), но сначала он завершает поток, если он работает? В противном случае вы можете закрыть сокет за спиной нити.

...