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

发布于 2024-10-01 09:45:59 字数 5930 浏览 2 评论 0原文

这是类方法(所有方法和变量都声明为公共) 注意:DiscoverWinsockLib 负责 WSAStartup 的工作,我知道该部分可以工作。它还执行 LoadLibrary 并查找以下函数的 DLL 入口点,并使用 lpfn_ 前缀重命名。

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

非常感谢任何帮助。

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 ); 线程函数内部返回 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 满意!

对此有什么想法/建议吗?

Here is the Class Method (all methods and vars are declared public)
NOTE: DiscoverWinsockLib does the WSAStartup stuff and I know that part works. It also does a LoadLibrary and finds the DLLs entry points for the functions below, renamed with lpfn_ prefix.

No matter what I do, I can't seem to resolve why I get the error condition of socket operation on non-socket in the Thread.

Any help is greatly appreciated.

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);
}

And here is the Thread referenced above:

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);
}

** UPDATE **
I'm finding that the call to
EIndex = T->lpfn_WSAWaitForMultipleEvents( 1, &T->RxOverlapped.hEvent, false, 3000, true );
inside the Thread function is returning WSA_WAIT_FAILED

And if I disable the thread function and check the return value of
lpfn_WSAWaitForMultipleEvents, outside the thread, right after the connect call, I get a valid return value of WSAEWOULDBLOCK.

Thinking I might have a problem taking the address-of from inside the thread, I changed the thread code to read as follows:

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 );

            ....

and I still cannot manage to make WSAWaitForMultipleEvents happy!

any thoughts/suggestions on this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

梦回梦里 2024-10-08 09:45:59

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

If connect() fails, you are calling SocketShutdown(). Presumably, it closes the socket (you did not show that code), but does it terminate the thread first if it is running? Otherwise, you could be closing the socket behind the thread's back.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文