ソフトウェア開発 Win32プログラミング

HTTPプロコトルでファイルをダウンロードする(非同期)

戻る


非同期的にHTTPプロコトルでインターネットからファイルをダウンロードするコードは以下の通り。

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock.h>

#include <cstdlib>
#include <string>
using namespace std;

#define MYWM_SELECT     (WM_USER + 100)
#define MYWM_GETHOST    (WM_USER + 101)

HINSTANCE g_hInstance;
HWND g_hMainWnd;
HWND g_hwndURL;
HWND g_hwndButton;
HWND g_hwndText;

SOCKET g_s;
HANDLE g_hGetHost;
CHAR g_szHost[256];
string g_strHost;
string g_strPort;
string g_strRemotePath;

class DataStream
{
    ...
};

...

DataStream g_ds;

CHAR g_szWndClass[] = "Http Client";
CHAR g_szTitle[] = "Httpクライアント";

INT Error(LPCSTR pszFormat, ...)
{
    CHAR sz[1024];
    INT n;
    va_list va;
    va_start(va, pszFormat);
    wvsprintf(sz, pszFormat, va);
    n = MessageBox(g_hMainWnd, sz, NULL, MB_ICONERROR);
    va_end(va);
    return n;
}

VOID CloseConnect(VOID)
{
    if(g_hGetHost != NULL)
    {
        WSACancelAsyncRequest(g_hGetHost);
        g_hGetHost = NULL;
    }

    if(g_s != INVALID_SOCKET)
        closesocket(g_s);
    g_s = INVALID_SOCKET;
}

BOOL AsyncStartConnect(HWND hWnd)
{
    INT iError;
    LONG lEvent;
    LPSERVENT pServEnt;
    SOCKADDR_IN sockAddrIn;
    
    sockAddrIn.sin_family = AF_INET;

    sockAddrIn.sin_addr.s_addr = inet_addr(g_strHost.c_str());
    if (sockAddrIn.sin_addr.s_addr == INADDR_NONE)
    {
        g_hGetHost = WSAAsyncGetHostByName(hWnd, MYWM_GETHOST, 
                                           g_strHost.c_str(), g_szHost, 
                                           256);
        if (g_hGetHost == NULL)
        {
            closesocket(g_s);
            g_s = INVALID_SOCKET;
            return FALSE;
        }
        return TRUE;
    }

    pServEnt = getservbyname(g_strPort.c_str(), "tcp");
    if (pServEnt == NULL)
        sockAddrIn.sin_port = htons(atoi(g_strPort.c_str()));
    else
        sockAddrIn.sin_port = pServEnt->s_port;

    g_s = socket(AF_INET, SOCK_STREAM, 0);
    if(g_s != INVALID_SOCKET)
    {
        lEvent = FD_CONNECT | FD_READ | FD_CLOSE;
        if (WSAAsyncSelect(g_s, hWnd, MYWM_SELECT, lEvent) != SOCKET_ERROR)
        {
            if (connect(g_s, (LPSOCKADDR)&sockAddrIn, sizeof(sockAddrIn)) != SOCKET_ERROR)
            {
                return TRUE;
            }
            else
            {
                iError = WSAGetLastError();
                if (iError == WSAEWOULDBLOCK)
                    return TRUE;
            }
        } else
            iError = WSAGetLastError();

        CloseConnect();
        WSASetLastError(iError);
    }
    return FALSE;
}

BOOL OnGetHost(HWND hWnd)
{
    INT iError;
    LPHOSTENT pHostEnt;
    LPSERVENT pServEnt;
    SOCKADDR_IN sockAddrIn;
    LONG lEvent;

    pHostEnt = (LPHOSTENT)g_szHost;

    sockAddrIn.sin_family = AF_INET;
    sockAddrIn.sin_addr = *((LPIN_ADDR)*pHostEnt->h_addr_list);
    pServEnt = getservbyname(g_strPort.c_str(), "tcp");
    if (pServEnt == NULL)
        sockAddrIn.sin_port = htons(atoi(g_strPort.c_str()));
    else
        sockAddrIn.sin_port = pServEnt->s_port;

    g_s = socket(AF_INET, SOCK_STREAM, 0);
    if(g_s != INVALID_SOCKET)
    {
        lEvent = FD_CONNECT | FD_READ | FD_CLOSE;
        if (WSAAsyncSelect(g_s, hWnd, MYWM_SELECT, lEvent) != SOCKET_ERROR)
        {
            if (connect(g_s, (LPSOCKADDR)&sockAddrIn, sizeof(sockAddrIn)) != SOCKET_ERROR)
            {
                return TRUE;
            }
            else
            {
                iError = WSAGetLastError();
                if (iError == WSAEWOULDBLOCK)
                    return TRUE;
            }
        }
        else
            iError = WSAGetLastError();

        CloseConnect();
        WSASetLastError(iError);
    }
    return FALSE;
}

INT Read(LPSTR str, INT length)
{
    return recv(g_s, str, length, 0);
}

VOID Write(LPCSTR str, INT length)
{
    INT len;
    while(length)
    {
        len = send(g_s, str, length, 0);
        if (len <= 0)
            throw WSAGetLastError();
        length -= len;
        str += len;
    }
}

VOID WriteSz(LPCSTR str)
{
    Write(str, lstrlen(str));
}

VOID ParseURL(LPCSTR pszURL)
{
    LPCSTR p1, p2, p3;
    string strHost, strPort, strRemotePath;

    p1 = pszURL;
    if (memcmp(pszURL, "http://", 7) == 0)
    {
        p1 += 7;
    }

    p2 = strchr(p1, ':');
    p3 = strchr(p1, '/');
    if (p3 < p2)
        p2 = NULL;

    if (p2 == NULL)
        strPort = "80";
    else
        strPort.assign(p2, p3 - p2);

    if (p3 == NULL)
    {
        strHost = p1;
        strRemotePath = "/";
    }
    else
    {
        strHost.assign(p1, p3 - p1);
        strRemotePath = p3;
    }

    g_strHost = strHost;
    g_strPort = strPort;
    g_strRemotePath = strRemotePath;
}

BOOL OnConnect(VOID)
{
    CHAR buf[256];
    
    try
    {
        wsprintf(buf, "GET %s HTTP/1.1\r\n", g_strRemotePath.c_str());
        WriteSz(buf);
        WriteSz("User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)\r\n");
        wsprintf(buf, "Host: %s\r\n", g_szHost);
        WriteSz(buf);
        WriteSz("Connection: close\r\n\r\n");
    }
    catch(INT iError)
    {
        Error("通信エラー (WSAGetLastError() == %d)", iError);
        shutdown(g_s, 1);
        CloseConnect();
        return FALSE;
    }
    shutdown(g_s, 1);
    return TRUE;
}

#define BUFSIZE 4096

BOOL OnRead(VOID)
{
    CHAR buf[BUFSIZE];
    INT n;
    
    INT iError;
    
    try
    {
        n = Read(buf, BUFSIZE);
        if (n > 0)
        {
            g_ds.Append(buf, n);
        }
        if (n == SOCKET_ERROR)
        {
            Error("通信エラー (WSAGetLastError() == %d)。\n", 
                  WSAGetLastError());
            return FALSE;
        }
        return TRUE;
    }
    catch(bad_alloc)
    {
        Error("メモリ不足のため、ダウンロードに失敗しました。\n");
        return FALSE;
    }
}

BOOL OnClose(VOID)
{
    INT i, j, k, length, status;

    CloseConnect();

    i = g_ds.Find("\r\n\r\n", 4);
    if (i == -1)
    {
        Error("ダウンロードに失敗しました。");
        return FALSE;
    }
    i += 4;

    //assert(lstrlen("HTTP/1.1 ") == 9);
    k = g_ds.Find("HTTP/1.1 ", 9);
    if (k == -1 || i < k)
        return FALSE;
    k += 9;
    status = atoi(g_ds.Ptr() + k);
    if (status != 200)
    {
        Error("ダウンロードに失敗しました(HTTPステータス:%d)。",
              status);
        return FALSE;
    }

    //assert(lstrlen("Content-Length:") == 15);
    j = g_ds.Find("Content-Length:", 15);
    if (j != -1 && j < i)
    {
        j += 15;
        length = atoi(g_ds.Ptr() + j);
    }
    else
    {
        length = strtol(g_ds.Ptr() + i, NULL, 16);
        i = g_ds.Find("\r\n", 2, i);
        if (i == -1)
        {
            Error("ダウンロードに失敗しました。");
            return FALSE;
        }
        i += 2;
    }

    if ((INT)g_ds.Size() < i + length)
    {
        Error("接続が打ち切られたため、ダウンロードに失敗しました。");
        return FALSE;
    }
    
    try
    {
        g_ds.Append("\0", 1);
    }
    catch(bad_alloc)
    {
        Error("メモリ不足のため、ダウンロードに失敗しました。\n");
        return FALSE;
    }
    g_ds.Ptr()[i + length] = '\0';
    SetWindowText(g_hwndText, g_ds.Ptr() + i);
    g_ds.Clear();
    return TRUE;
}

LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    INT cchURL;
    LPSTR pszURL;
    switch(uMsg)
    {
    case MYWM_GETHOST:
        if (WSAGETASYNCERROR(lParam) != 0)
        {
            Error("IPアドレスの取得に失敗しました。");
            break;
        }
        OnGetHost(hWnd);
        break;

    case MYWM_SELECT:
        if(g_s != (SOCKET)wParam)
            break;

        switch(WSAGETSELECTEVENT(lParam))
        {
        case FD_CONNECT:
            OnConnect();
            break;

        case FD_READ:
            OnRead();
            break;

        case FD_CLOSE:
            OnClose();
            break;
        }
        break;

    case WM_COMMAND:
        switch(LOWORD(wParam))
        {
        case 2:
            cchURL = GetWindowTextLength(g_hwndURL);
            pszURL = (LPSTR)malloc(cchURL + 1);
            g_ds.Clear();
            SetWindowText(g_hwndText, "");
            if (pszURL != NULL)
            {
                GetWindowText(g_hwndURL, pszURL, cchURL + 1);
                ParseURL(pszURL);
                AsyncStartConnect(hWnd);
                free(pszURL);
            }
            break;
        }
        break;
        ...
    }
    return 0;
}

...

ソース: http2.zip


戻る

©片山博文MZ
katayama.hirofumi.mz@gmail.com

inserted by FC2 system