top / index / prev / next / target / source

2002-12-05 diary: HTTP経由ファイル送信サンプル(Visual C++版)

いがぴょんの日記 日記形式でつづる いがぴょんコラム ウェブページです。

old-v2

HTTP経由ファイル送信サンプル(Visual C++版)

C++用Javaストリーム実装が欲しいっ

Visual C++でJavaのストリームは使えないものかと…

Visual C++で Javaのストリームは使えないかなぁと ざっくりさがしていきました。するとなぜか GCCに行き着きました。

で そのままCygwinだと芸がない(?) というかヒネリが無いので とりあえずCygwinではない方を見てみました。

で やっぱりということで Cygwinの方をダウンロードして gcc最新版をゲットしてみました。ライセンス周りでもう少し調べてみないと 単に利用できるかどうか不明です…。

HTTP経由ファイル送信サンプル (Visual C++版)

今度は HTTP の POSTを利用したサンプルを作りました。作っていて気がついたのですが、私 既に delete演算子の存在を忘れきっています。たいへんびっくりしました。(忘れたいプログラミング言語その1が C/C++言語なのですけれども、本当に忘れてしまうと それはそれで ちと不便ですね。とゆ~か deleteを記載し忘れると 大変困りますから) HttpPost.cpp

/**
* シンプルHTTP POSTクライアント
* 2002.12.05 t.iga
*/

#include <afx.h>
#include <afxwin.h>
#include <afxinet.h>

CWinApp theApp;

/**
 * 転送時のバッファサイズ
 */
const int BUF_SIZE = 2048;

// 送信したいデータが格納されたファイル名
const char* READ_FILE = "postdata.dat";

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[]) {

    // MFC を初期化して、エラーの場合は結果を印刷します。
    if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
    {
        _tprintf(_T("MFCの初期化に失敗しました.\n"));
        return 1;
    }

    if (argc <= 1)
    {
        printf("Usage: HttpGet.exe http://www.google.co.jp/\n");
        return -1;
    }

    try
    {
        char* uri = argv[1];

        DWORD protocol = 0;
        CString serverName;
        CString fileName;
        INTERNET_PORT port;

        if (AfxParseURL(uri, protocol, serverName, fileName, port) == false)
        {
            printf("URLの分解に失敗しました。");
            return -1;
        }

        printf("プロトコル[%ld] ポート[%ld] サーバ[%s] ファイル名[%s]\n",
               protocol, port, (LPCSTR)serverName, (LPCSTR)fileName);

        CInternetSession session("HttpPost - simple http client");
        CHttpConnection* conn = session.GetHttpConnection(
                                    serverName,
                                    CHttpConnection::HTTP_VERB_POST,
                                    port, NULL, NULL);
        CHttpFile* file = conn->OpenRequest(
                              CHttpConnection::HTTP_VERB_POST, fileName,
                              NULL, 1, NULL, NULL,
                              INTERNET_FLAG_RELOAD | INTERNET_FLAG_DONT_CACHE);
        file->AddRequestHeaders(
            "Accept: text/*\r\nUser-Agent: HttpPost\r\nContent-Type: application/octet-stream\r\n");

        {
            CFile* readFile = new CFile();
            if (readFile->Open(READ_FILE, CFile::modeRead) == FALSE)
            {
                printf("読み込みデータファイル[%s]を開くことができませんでした\n", READ_FILE);
            }
            else
            {
                DWORD fileLength = (DWORD)readFile->GetLength();
                file->SendRequestEx(fileLength);
                char szBuf[BUF_SIZE + 1];
                int sendLength = 0;
                for (;;)
                {
                    UINT result = readFile->Read(szBuf, BUF_SIZE);
                    if (result <= 0)
                    {
                        break;
                    }
                    file->Write(szBuf, result);
                    szBuf[result] = 0;
                    printf("S: %ld [%s]\n", result, szBuf);
                    sendLength += result;
                }
                if (sendLength != fileLength)
                {
                    printf(
                      "送信しようとしたデータ長(%ld)と実際に送信したデータ長(%ld)とが不一致です\n",
                      fileLength, sendLength);
                }
                file->EndRequest();
                readFile->Close();
                delete readFile;
            }
        }

        DWORD statusCode;
        file->QueryInfoStatusCode(statusCode);
        if (statusCode >= 300)
        {
            printf("何かしらエラー:%ld\n", statusCode);
            return -1;
        }

        TCHAR buf[BUF_SIZE + 1];
        for (;;)
        {
            int result = file->Read(buf, BUF_SIZE);
            if (result <= 0)
            {
                break;
            }
            buf[result] = 0x00;
            printf("R: [%s]\n", buf);
        }

        file->Close();
        delete file;
        conn->Close();
        delete conn;
        session.Close();
    }
    catch (CInternetException* ex)
    {
        TCHAR szMsg[1024];
        ex->GetErrorMessage(szMsg, 1024);
        printf("Error occur: %s", szMsg);
        ex->Delete();
    }
    return 0;
}

いまいち HTTPのPOSTの仕組みについて、わたしは良くは理解していないということが分かりました。

2002.12.10 で これもC言語版を作ってみます。まずは情報源。下記のMicrosoftのページが役に立ちました。

/**
* シンプルHTTP POSTクライアント
* wininet.libをリンクに追加することが必要です。
* 2002.12.10 t.iga
*/
#include <windows.h>
#include <wininet.h>
#include <stdio.h>
#include <stdlib.h>

#define BUFSIZE         (1024)

int main(int argc, char* argv[])
{
    HINTERNET hsession = 0;
    HINTERNET hconnect = 0;
    HINTERNET hrequest = 0;
    char szBuf[1025];
    DWORD dwSize = 0;
    INTERNET_BUFFERS inetbuf;

    hsession = InternetOpen("HttpGet - simple http client",
                            INTERNET_OPEN_TYPE_PRECONFIG,
                            NULL, NULL, 0);

    if (hsession == NULL)
    {
        printf("hsession==NULL");
        return -1;
    }

    hconnect = InternetConnect(
                   hsession,
                   "www.tcct.zaq.ne.jp",
                   80,
                   "iga",
                   "password",
                   INTERNET_SERVICE_HTTP,
                   0,
                   0);
    if (hconnect == NULL)
    {
        printf("hconnect==NULL");
        return -1;
    }

    hrequest = HttpOpenRequest(
                   hconnect,
                   "POST",
                   "/iga/tosiki/igapyon/diary/index.html",
                   NULL,
                   NULL,
                   NULL,
                   INTERNET_FLAG_NO_CACHE_WRITE,
                   0);

    if (hrequest == NULL)
    {
        printf("hrequest==NULL");
        return -1;
    }

    memset(&inetbuf, 0, sizeof(INTERNET_BUFFERS));
    inetbuf.dwStructSize = sizeof(INTERNET_BUFFERS);
    inetbuf.dwBufferTotal = 5;

    if (HttpSendRequestEx(hrequest, &inetbuf, NULL, 0, 0) == FALSE)
    {
        printf( "Error on HttpSendRequestEx %d\n", GetLastError() );
        return -1;
    }

        // ここで実際のPOST動作を実行
    strcpy(szBuf, "ABCDE");
    if (InternetWriteFile(hrequest, szBuf, 5, &dwSize) == FALSE)
    {
        printf( "Error on InternetWriteFile %d\n", GetLastError() );
        return -1;
    }

    if (HttpEndRequest(hrequest, NULL, 0, 0) == FALSE)
    {
        printf( "Error on HttpEndRequest %d\n", GetLastError() );
        return -1;
    }

    szBuf[0] = 0;

    {
        dwSize = BUFSIZE;
        if (HttpQueryInfo(
                    hrequest,
                    HTTP_QUERY_CONTENT_LENGTH,

                    szBuf, &dwSize, 0))
        {
            szBuf[dwSize] = 0;
            printf("長さ[%s]\n", szBuf);
        }

        dwSize = BUFSIZE;
        if (HttpQueryInfo(
                    hrequest,
                    HTTP_QUERY_STATUS_CODE,
                    szBuf, &dwSize, 0))
        {
            szBuf[dwSize] = 0;
            printf("ステータス[%s]\n", szBuf);
        }

        dwSize = BUFSIZE;
        if (HttpQueryInfo(
                    hrequest,
                    HTTP_QUERY_STATUS_TEXT,
                    szBuf, &dwSize, 0))
        {
            szBuf[dwSize] = 0;
            printf("ステータス文字列[%s]\n", szBuf);
        }
    }


    for (;;)
    {
        dwSize = BUFSIZE;
        if (InternetReadFile(
                    hrequest,
                    szBuf,
                    dwSize,
                    &dwSize) == FALSE)
        {
            break;
        }

        if (dwSize <= 0)
        {
            break;
        }

        szBuf[dwSize] = 0;
        printf("%s\n", szBuf);
    }

    InternetCloseHandle(hrequest);
    InternetCloseHandle(hconnect);
    InternetCloseHandle(hsession);

    return 0;
}

ふう。C言語は面倒です。しかし 後々の運用時修正を考えると MFCなんかに頼ったコードよりも生でCのAPIを呼んでいる方が信頼あるプログラムを開発できるように思っています。

関連する日記


この日記について