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

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

戻る


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

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

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

#pragma comment(lib, "wsock32.lib")

SOCKET g_s;

BOOL StartConnect(LPCSTR pszHost, LPCSTR pszPort)
{
    SOCKADDR_IN SockAddr;
    LPSERVENT pServEnt;
    LPHOSTENT pHostEnt;
    INT iError;

    g_s = socket(AF_INET, SOCK_STREAM, 0);
    if (g_s != INVALID_SOCKET)
    {
        SockAddr.sin_family = AF_INET;

        pServEnt = getservbyname(pszPort, "tcp");
        if (pServEnt == NULL)
            SockAddr.sin_port = htons(atoi(pszPort));
        else
            SockAddr.sin_port = pServEnt->s_port;

        SockAddr.sin_addr.s_addr = inet_addr(pszHost);
        if (SockAddr.sin_addr.s_addr == INADDR_NONE)
        {
            pHostEnt = gethostbyname(pszHost);
            if (pHostEnt == NULL)
            {
                iError = WSAGetLastError();
                closesocket(g_s);
                WSASetLastError(iError);
                return FALSE;
            }
            SockAddr.sin_addr.s_addr = *(DWORD*)pHostEnt->h_addr;
        }
        if (connect(g_s, (LPSOCKADDR)&SockAddr, sizeof(SockAddr)) == 0)
            return TRUE;

        iError = WSAGetLastError();
        closesocket(g_s);
        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 CloseConnect(VOID)
{
    if(g_s != INVALID_SOCKET)
        closesocket(g_s);
    g_s = INVALID_SOCKET;
}

class DataStream
{
    LPSTR m_p;
    UINT m_size;
public:
    DataStream() : m_p(NULL), m_size(0) {}
    DataStream(LPVOID p, UINT size)
    {
        m_size = size;
        m_p = (LPSTR)malloc(size);
        if (m_p == NULL) throw bad_alloc();
        CopyMemory(m_p, p, size);
    }
    DataStream(const DataStream& s)
    {
        m_size = s.m_size;
        m_p = (LPSTR)malloc(s.m_size);
        if (m_p == NULL) throw bad_alloc();
        CopyMemory(m_p, s.m_p, s.m_size);
    }
    ~DataStream() { if (m_p != NULL) free(m_p); }

    LPSTR Ptr() { return m_p; }
    UINT Size() { return m_size; }
    void Append(LPCVOID p, UINT size)
    {
        m_p = (LPSTR)realloc(m_p, m_size + size);
        if (m_p == NULL) throw bad_alloc();
        CopyMemory(m_p + m_size, p, size);
        m_size += size;
    }
    INT Find(LPCVOID p, UINT size, UINT start = 0);
};

INT DataStream::Find(LPCVOID p, UINT size, UINT start)
{
    for(UINT i = start; i < m_size - size + 1; i++)
    {
        if (memcmp(m_p + i, p, size) == 0)
            return i;
    }
    return -1;
}

#define BUFSIZE 2048

BOOL HttpDownload(
    LPCSTR pszLocalFileName,
    LPCSTR pszHost,
    LPCSTR pszRemotePath,
    LPCSTR pszPort,
    LPCSTR pszReferer OPTIONAL)
{
    CHAR buf[BUFSIZE];
    INT i, j, k, n, length, status;
    FILE *fp;
    DataStream s;

    try
    {
        if (StartConnect(pszHost, pszPort))
        {
            try
            {
                wsprintf(buf, "GET %s HTTP/1.1\r\n", pszRemotePath);
                WriteSz(buf);
                WriteSz("User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)\r\n");
                if (pszReferer != NULL)
                {
                    wsprintf(buf, "Referer: %s\r\n", pszReferer);
                    WriteSz(buf);
                }
                wsprintf(buf, "Host: %s\r\n", pszHost);
                WriteSz(buf);
                WriteSz("Connection: close\r\n\r\n");
            }
            catch(INT iError)
            {
                fprintf(stderr,
                        "通信エラー (WSAGetLastError() == %d)。\n", iError);
                shutdown(g_s, 1);
                CloseConnect();
                return FALSE;
            }
            shutdown(g_s, 1);

            INT iError;
            while((n = Read(buf, BUFSIZE)) > 0)
            {
                s.Append(buf, n);
            }
            if (n == SOCKET_ERROR)
                iError = WSAGetLastError();
            CloseConnect();
            if (n == SOCKET_ERROR)
            {
                fprintf(stderr,
                        "通信エラー (WSAGetLastError() == %d)。\n", iError);
                return FALSE;
            }

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

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

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

            if ((INT)s.Size() < i + length)
            {
                fprintf(stderr, "接続が打ち切られたため、失敗しました。\n");
                return FALSE;
            }

            fp = fopen(pszLocalFileName, "wb");
            if (fp == NULL)
                return FALSE;
            n = fwrite(s.Ptr() + i, length, 1, fp);
            fclose(fp);
            if (n != 1)
            {
                DeleteFile(pszLocalFileName);
                fprintf(stderr, "ファイルの書き込みに失敗しました。\n");
                return FALSE;
            }
            return TRUE;
        }
        else
        {
            fprintf(stderr,
                    "%sに接続できません (WSAGetLastError() == %d)。\n",
                    pszHost, WSAGetLastError());
        }
    }
    catch(bad_alloc)
    {
        fprintf(stderr, "メモリ不足のため、ダウンロードに失敗しました。\n");
    }
    return FALSE;
}

BOOL HttpDownloadByURL(
    LPCSTR pszLocalFileName,
    LPCSTR pszURL,
    LPCSTR pszReferer OPTIONAL)
{
    LPCSTR p1, p2, p3;
    string strHost;
    string strPort;

    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)
        return HttpDownload(pszLocalFileName, p1, "/", strPort.c_str(), pszReferer);

    strHost.assign(p1, p3 - p1);
    return HttpDownload(pszLocalFileName, strHost.c_str(), p3, strPort.c_str(), pszReferer);
}

#ifdef UNITTEST
int main(void)
{
    WSADATA data;
    if (WSAStartup(MAKEWORD(1, 1), &data) == 0)
    {
        HttpDownloadByURL("yahoo.htm", "http://www.yahoo.co.jp", NULL);
        HttpDownloadByURL("readme.html", "http://localhost/readme.html", NULL);
        WSACleanup();
    }
    else
    {
        fprintf(stderr, "WinSockの初期化に失敗しました。\n");
    }
    return 0;
}
#endif  // def UNITTEST

ソース: http1.zip


戻る

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

inserted by FC2 system