非套接字上的WINSOCK套接字操作

时间:2010-11-09 19:45:44

标签: asynchronous winsock

这是类方法(所有方法和变量都声明为public) 注意:DiscoverWinsockLib执行WSAStartup的东西,我知道该部分有效。它还执行LoadLibrary并找到以下函数的DLL入口点,使用lpfn_ prefix重命名。

无论我做什么,我似乎无法解决为什么我在线程中的非套接字上获得套接字操作的错误条件。

非常感谢任何帮助。

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,在线程之外,在connect调用之后,我得到一个有效的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 :(得分:0)

如果connect()失败,则调用SocketShutdown()。据推测,它会关闭套接字(你没有显示该代码),但如果它正在运行,它会先终止该线程吗?否则,您可能正在关闭线程后面的套接字。