rc : Asynchronous http post

来源:互联网 发布:手机自动排班软件 编辑:程序博客网 时间:2024/06/06 08:58

同步HttpSendRequest执行时,会阻塞住。

在程序退出时,强杀线程问题很多. 不只是内存泄漏. 退出的时机不同,有时还会崩溃。

在被杀线程中使用主线程中的类成员e.g. map, 如果被杀时,正在操作那个map,  在主线程map free的时候崩溃了。

用http同步+退出程序时土法杀http线程的方法,问题多多。

还是得用优雅的异步http操作才行.


异步post的资料

Asynchronous Example Application (Windows) - MSDN

http://support.microsoft.com/kb/275046


#include<windows.h>#include<wininet.h>#include<iostream> // for cout, endlusing namespace std;HANDLE hConnectedEvent, hRequestOpenedEvent, hRequestCompleteEvent;HINTERNET hInstance, hConnect, hRequest;char *lpszUrl, *lpszServer;BOOL bAllDone = FALSE;BOOL bVerbose = FALSE;void __stdcall Callback(HINTERNET hInternet,              DWORD dwContext,              DWORD dwInternetStatus,              LPVOID lpStatusInfo,              DWORD dwStatusInfoLen);void main(int argc, char *argv[]){    if (argc != 3)    {        if ((argc == 4) && (argv[3][0] == 'v'))            bVerbose = TRUE;        else        {            cout << "Usage: asynchttp <server> <url> [v]" << endl;            cout << "   <server> is the hostname of the http server" << endl;            cout << "   <url> is the url of the object you are requesting (without the hostname)" << endl;            cout << "   'v' for verbose output" << endl << endl;            cout << "   Example: asynchttp www.domain.com /docs/readme.htm v" << endl;            return;        }    }    lpszServer = argv[1];    lpszUrl = argv[2];    hConnectedEvent = CreateEvent(NULL, FALSE, FALSE, NULL);    hRequestOpenedEvent = CreateEvent(NULL, FALSE, FALSE, NULL);    hRequestCompleteEvent = CreateEvent(NULL, FALSE, FALSE, NULL);    hInstance = InternetOpen("asynchttp",                              INTERNET_OPEN_TYPE_PRECONFIG,                             NULL,                             NULL,                             INTERNET_FLAG_ASYNC); // ASYNC Flag    if (hInstance == NULL)    {        cout << "InternetOpen failed, error " << GetLastError();        return;    }    // Setup callback function    if (InternetSetStatusCallback(hInstance,                                  (INTERNET_STATUS_CALLBACK)&Callback) == INTERNET_INVALID_STATUS_CALLBACK)    {        cout << "InternetSetStatusCallback failed, error " << GetLastError();        return;    }    // First call that will actually complete asynchronously even    // though there is no network traffic    hConnect = InternetConnect(hInstance,                                lpszServer,                                INTERNET_DEFAULT_HTTP_PORT,                               NULL,                               NULL,                               INTERNET_SERVICE_HTTP,                               0,                               1); // Connection handle's Context    if (hConnect == NULL)    {        if (GetLastError() != ERROR_IO_PENDING)        {            cout << "InternetConnect failed, error " << GetLastError();            return;        }        // Wait until we get the connection handle        WaitForSingleObject(hConnectedEvent, INFINITE);    }    // Open the request    // 如果使用同步http操作, 主要是在HttpOpenRequest处,阻塞住.    hRequest = HttpOpenRequest(hConnect,                                "GET",                                lpszUrl,                               NULL,                               NULL,                               NULL,                               INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_CACHE_WRITE,                               2);  // Request handle's context     if (hRequest == NULL)    {        if (GetLastError() != ERROR_IO_PENDING)        {            cout << "HttpOpenRequest failed, error " << GetLastError();            return;        }        // Wait until we get the request handle        WaitForSingleObject(hRequestOpenedEvent, INFINITE);    }    if (!HttpSendRequest(hRequest,                          NULL,                          0,                          NULL,                         0))    {        if (GetLastError() != ERROR_IO_PENDING)        {            cout << "HttpSendRequest failed, error " << GetLastError();            return;        }    }        if (bVerbose)    {        cout << "HttpSendRequest called successfully" << endl;        cout.flush();    }    WaitForSingleObject(hRequestCompleteEvent, INFINITE);    cout << "------------------- Read the response -------------------" << endl;    char lpReadBuff[256];    do    {        INTERNET_BUFFERS InetBuff;        FillMemory(&InetBuff, sizeof(InetBuff), 0);        InetBuff.dwStructSize = sizeof(InetBuff);        InetBuff.lpvBuffer = lpReadBuff;        InetBuff.dwBufferLength = sizeof(lpReadBuff) - 1;                if (bVerbose)        {            cout << "Calling InternetReadFileEx" << endl;            cout.flush();        }        if (!InternetReadFileEx(hRequest,                              &InetBuff,                              0, 2))        {            if (GetLastError() == ERROR_IO_PENDING)            {                if (bVerbose)                {                    cout << "Waiting for InternetReadFileEx to complete" << endl;                    cout.flush();                }                WaitForSingleObject(hRequestCompleteEvent, INFINITE);            }            else            {                cout << "InternetReadFileEx failed, error " << GetLastError();                cout.flush();                return;            }        }        lpReadBuff[InetBuff.dwBufferLength] = 0;        cout << lpReadBuff;        cout.flush();        if (InetBuff.dwBufferLength == 0)             bAllDone = TRUE;    } while (bAllDone == FALSE);    cout << endl << endl << "------------------- Request Complete ----------------" << endl;}void __stdcall Callback(HINTERNET hInternet,              DWORD dwContext,              DWORD dwInternetStatus,              LPVOID lpStatusInfo,              DWORD dwStatusInfoLen){    if (bVerbose)    {        cout << "Callback dwInternetStatus: " << dwInternetStatus << " Context: " << dwContext << endl;        cout.flush();    }    switch(dwContext)    {    case 1: // Connection handle        if (dwInternetStatus == INTERNET_STATUS_HANDLE_CREATED)        {            INTERNET_ASYNC_RESULT *pRes = (INTERNET_ASYNC_RESULT *)lpStatusInfo;            hConnect = (HINTERNET)pRes->dwResult;            if (bVerbose)            {                cout << "Connect handle created" << endl;                cout.flush();            }            SetEvent(hConnectedEvent);        }        break;    case 2: // Request handle        switch(dwInternetStatus)        {        case INTERNET_STATUS_HANDLE_CREATED:            {                INTERNET_ASYNC_RESULT *pRes = (INTERNET_ASYNC_RESULT *)lpStatusInfo;                hRequest = (HINTERNET)pRes->dwResult;                if (bVerbose)                {                    cout << "Request handle created" << endl;                    cout.flush();                }                SetEvent(hRequestOpenedEvent);            }            break;        case INTERNET_STATUS_REQUEST_SENT:            {                DWORD *lpBytesSent = (DWORD*)lpStatusInfo;                if (bVerbose)                {                    cout << "Bytes Sent: " << *lpBytesSent << endl;                    cout.flush();                }            }            break;        case INTERNET_STATUS_REQUEST_COMPLETE:            {                INTERNET_ASYNC_RESULT *pAsyncRes = (INTERNET_ASYNC_RESULT *)lpStatusInfo;                if (bVerbose)                {                    cout << "Function call finished" << endl;                    cout << "dwResult: " << pAsyncRes->dwResult << endl;                    cout << "dwError:  " << pAsyncRes->dwError << endl;                    cout.flush();                }                SetEvent(hRequestCompleteEvent);            }            break;        case INTERNET_STATUS_RECEIVING_RESPONSE:            if (bVerbose)            {                cout << "Receiving Response" << endl;                cout.flush();            }            break;        case INTERNET_STATUS_RESPONSE_RECEIVED:            {                DWORD *dwBytesReceived = (DWORD*)lpStatusInfo;                if (*dwBytesReceived == 0)                    bAllDone = TRUE;                if (bVerbose)                {                    cout << "Received " << *dwBytesReceived << endl;                    cout.flush();                }            }        }    }}

将MS例子中的回调,结合到类中就可以以c++方式异步httpPost。

将原始Demo重构一下

enum eHttpContext{    eHttpContext_Connection = 1, // Connection handle's Context    eHttpContext_Request = 2, // Request handle's context };
使用这2个enum的地方如下:

    // First call that will actually complete asynchronously even    // though there is no network traffic    hConnect = InternetConnectA(hInstance,         lpszServer,         INTERNET_DEFAULT_HTTP_PORT,        NULL,        NULL,        INTERNET_SERVICE_HTTP,        0,        eHttpContext_Connection);

    // Open the request    // 如果使用同步http操作, 主要是在HttpOpenRequest处,阻塞住.    hRequest = HttpOpenRequestA(hConnect,         "GET",         lpszUrl,        NULL,        NULL,        NULL,        INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_CACHE_WRITE,        eHttpContext_Request);

        if (!InternetReadFileEx(hRequest,            &InetBuff,            0, eHttpContext_Request))

internet*ex函数的最后一个参数是 dwContext, 换成类指针,就可以实现c++方式的回调操作.


0 0