2019年2月22日金曜日

サイズの大きいデータをPOSTすると404エラーが発生する

ASP.NETで作成したWeb APIに対し、HttpClientを使用して、JSONデータをPOSTするコードを書きました。

using (var client = new HttpClient())
{
    client.DefaultRequestHeaders.Clear();
    client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));

    var content = new StringContent(jsonString, Encoding.UTF8, "application/json");
    var task= client.PostAsync(uri, content).ContinueWith(x =>
    {
        var response = x.Result;
        if (!response.IsSuccessStatusCode)
        {
            throw new Exception(response.ReasonPhrase);
        }

        ・・・
    });
    try
    {
        task.Wait();
    }
    catch (AggregateException ex)
    {
        throw ex.Flatten();
    }
    catch
    {
        throw;
    }
}

40MB近くあるデータをPOSTしたところ、レスポンスに「Not Found」、いわゆる404エラーが返ってきました。












送信データサイズが小さい場合は問題はなく、エラーの原因がサイズの大きさにあることは明らかなのですが、
サーバーが受け取るリクエストの最大サイズはmaxRequestLengthですでに指定しています。
調べてみると、どうやらそれだけでは不十分で、リクエスト内のコンテンツ最大長(maxAllowedContentLength)の指定も
必要だということが分かりました。
web.configにmaxAllowedContentLengthを追加し、送信データサイズ以上の値を指定すると、エラーが返ることはなくなりました。

  <system.webServer>
    <security>
      <requestFiltering>
        <requestLimits maxAllowedContentLength="52428800"></requestLimits>
      </requestFiltering>
    </security>
  </system.webServer>

またいつか、どこかで。

2019年2月15日金曜日

TeraTermマクロで自動接続 & マクロ毎に設定ファイルを切り替える!



こんにちは。よっしーです。

皆さん TeraTerm 使ってますか?


Linuxや仮想マシンを使っていると、

リモート接続する際に TeraTerm をよく使います。


で、複数台にリモート接続する場合、

TeraTermを複数立ち上げるワケですが、

どの画面がどのリモート接続か、

見分けがつかなくなることがあります。

(↓こんな感じ)


で、これを回避するため、

コンソール毎に背景色を変えたりするわけですが、

(↓色が違うと見分けも付きやすい!!)


1つずつ手動で色の変更を行うのは面倒なので、

私はTeraTermの設定ファイルをいくつか用意し、

自動接続マクロにその設定ファイルを指定するような方法で

TeraTermの切り分けをしています。


以下、マクロの例です。

(↓赤枠でTeraTerm設定ファイルを指定しています。


マクロファイルをttl拡張子で保存し、TeraTermから関連付けすると、

ダブルクリックだけで自動的にリモート接続し、対象の設定ファイルが

適応された状態でTeraTermが立ち上がります。


設定ファイルには、色の他にも、ログ出力の設定だったり、

いろいろとカスタマイズできる項目があるので、

「接続先によって設定を切り替えたい!」とお困りの方は、お試し下さい。


ではまた~。

2019年2月11日月曜日

メモリのセクション内の配置を確認してみた

こんにちは、ふじかーです。

前回書いた.bssセクションのグローバル変数の初期化についての記事、
組み込み屋さんには当たり前の事と言われるかもしれませんが
本当にそうなってるか気になったので、実際に動かして確認してみました。


セクション概要


プログラムはメモリに配置されて実行されるわけですが
メモリ上にはプログラム内の「機械語」や「変数」「定数」など、各種用途に分けて配置され

その単位のことをセクションといいます。


と、ここまでは前回記載しましたが、

これ以外にもプログラム実行中、関数内のローカル変数等が
使用されるときに配置される「スタック領域」がありますね。

上記のセクション は
 プログラムをコンパイル(リンク)した時点でアドレスとサイズが決まり、
 実行中に変わる事はない、静的な領域
なのに対し、

スタック領域 は
 プログラム実行中、使用時に一時的に確保されたり開放されたりする、
 動的な領域
という違いがあります。


テストプログラム


それらを確認するため
変数の値や配置アドレスを出力するだけのプログラムを書いてみます。

#include <stdio.h>
int global_int1 = 111;   //global 初期値あり
int global_int2;   //global 初期値なし
int global_int3 = 0;   //global 初期値0
const char global_chr1[] = "abc"; //global constあり
      char global_chr2[] = "def"; //global constなし

int section_test(int param);

int main(void)
{
    int ret = 0;
    ret = section_test(123);
    return 0;
}

int section_test(int param)
{
    int local_int1 = 222;  //local 初期値あり
    int local_int2;   //local 初期値なし
    int local_int3 = 0;   //local 初期値0
    static int local_int4 = 333; //local static 初期値あり
    static int local_int5;  //local static 初期値なし
    static int local_int6 = 0;  //local static 初期値0

    printf("\n■関数\n");
    printf("main()          (0x%X)\n", &main);
    printf("section_test()  (0x%X)\n", &section_test);
    
    printf("\n■引数\n");
    printf("param   (0x%X) = %d \n", &param , param);
    
    printf("\n■グローバル変数\n");
    printf("global_int1 初期値あり (0x%X) = %d \n", &global_int1 , global_int1);
    printf("global_int2 初期値なし (0x%X) = %d \n", &global_int2 , global_int2);
    printf("global_int3 初期値0    (0x%X) = %d \n", &global_int3 , global_int3);
    printf("global_chr1 constあり  (0x%X) = %s \n", &global_chr1 , global_chr1);
    printf("global_chr2 constなし  (0x%X) = %s \n", &global_chr2 , global_chr2);

    printf("\n■ローカル変数\n");
    printf("local_int1  初期値あり (0x%X) = %d \n", &local_int1 , local_int1);
    printf("local_int2  初期値なし (0x%X) = %d \n", &local_int2 , local_int2);
    printf("local_int3  初期値0    (0x%X) = %d \n", &local_int3 , local_int3);

    printf("\n■静的ローカル変数(static)\n");
    printf("local_int4  初期値あり (0x%X) = %d \n", &local_int4 , local_int4);
    printf("local_int5  初期値なし (0x%X) = %d \n", &local_int5 , local_int5);
    printf("local_int6  初期値0    (0x%X) = %d \n", &local_int6 , local_int6);

    return 0;
}


各種変数をprintf出力するだけなのに、意外と長くなってしまいました
これを例によってVS Codeでコンパイルして、動かしてみます。


実行結果が




また、前回同様 objdump で実行ファイルの内容を確認しておきます。




メモリ配置確認


さて、実際の配置はどうなっているでしょうか。
テストプログラムでの実行結果を絵にすると、こんな感じになりました。


各変数は、想定したセクションに置かれていました


・・・とまぁ結果としては大体想定通り動いているようです。

「ほぉ、確かにこんな風に配置されるんだな」

とイメージ出来ていると、もしかしたら
いずれ業務で会話に出たとき役に立ったりするかもしれません。
プログラム初心者の方は参考にしてください。

※ここまで書いて、せっかくだったら「ヒープ領域」も
 追加しときゃよかったかな・・・とも思いましたが、
 まぁ想像以上にゴチャゴチャしてきたし、今回はここまでとします。。

2019年2月3日日曜日

秀丸grepをフォルダの右クリックメニューから行う



こんにちは。よっしーです。

仕事柄、テキストエディタとして秀丸エディタをよく使います。


秀丸にはgrep機能があり、

ソースコードを追いかける場合などは必須の機能となります。


で、grepをする場合、秀丸の検索メニューから

「grepの実行」を行うことになるのですが、

当然ながら「秀丸を起動」する必要があり、

これが手順として面倒な場合があります。


・プログラムから秀丸を起動

 (ここがダメ)grep時にgrep対象のフォルダパスを指定しなければならない


・秀丸に関連付けされたファイルを選択して秀丸を起動

 (ここがダメ)grep対象が開いたファイルのカレントフォルダとなっているので、
        異なるフォルダをgrepしたい場合はパスを指定しなおさなければならない

 (ここがダメ)わざわざ秀丸に関連付いたファイルを探し出して選択しないといけない





で、私はこの面倒を解決するため、

フォルダの右クリックメニューに「秀丸grep」という処理を追加しています。




これをするためには、レジストリエディタでレジストリを手修正する必要があります。


やり方としては以下です。

(1) HKEY_CLASSES_ROOT\Folder\shell の下に、キー追加。
  わかりやすい名前をつけます。私は「秀丸grep」としています。

(2) 作成した「秀丸grep」の下に、キー追加。
  「command」という名前にして下さい。

(3) 「command」の(規定)というデータに、以下を設定。
  "C:\Program Files (x86)\Hidemaru\Hidemaru.exe" /d"%1" /g
  ※ 秀丸の実行ファイルパスは環境によって合わせて下さい。


これだけです。


これでフォルダを右クリックすることで、秀丸grepが選択できるようになり、

選択すると、右クリックしたフォルダパスが検索対象となった状態で

grep機能が立ち上がります。




まぁ、些細なもんですが、チリも積もれば日々の生産性も上がるということで、

興味があれば試してみてください。

ちなみに、これは秀丸だけではなく、サクラエディタ等でも同じように設定できます。


それでは~。

2019年1月28日月曜日

.bssセクションのグローバル変数の初期化について

こんにちは、ふじかーです。

先日現場で グローバル変数の初期化 が話題に上がりました。

「このグローバル変数で判定してますね。値、何が入ってるんだろ」
「定義時には特に初期値入れてないですね」
「あら、判定までずっと値入れてないですね。じゃ値は0ですか」
「なんか不定値になることありませんでしたっけ?」
「必ず0初期化されるんじゃなかったですかね?」

昔調べた気がするけど、正確にはどうだったか・・
と曖昧になっていたので、少し確認しなおしました。

セクション


プログラムはメモリに配置されて実行されるわけですが、メモリ上には
プログラム内の「機械語」や「変数」「定数」など、各種用途ごとに分かれて配置されています。

その単位のことをセクションといいますが
今回のグローバル変数などは『.bss セクション』という領域に格納されます。

.bssセクションに格納される変数の種類は

・初期値 なし の グローバル変数
・初期値が 0 の グローバル変数
・初期値 なし の 静的(=static)なローカル変数
・初期値が 0 の 静的(=static)なローカル変数

となっています。

この.bss領域は「全て0初期化されているべし」とC言語の規約で規定されているため
プログラム実行前に、領域を確保して丸ごと0初期化されるようです。

wikipedia
通常、bssセクションに割り当てられたメモリは
プログラムローダーがプログラムをロードするときに初期化する。
main() が実行されるより前に
Cランタイムシステムがbssセクションにマップされたメモリ領域をゼロで初期化する。

ちなみに、初期値あり(0以外) のグローバル変数や静的ローカル変数は?というと
『.dataセクション』 という領域に格納されます。
プログラム実行前に、領域を確保して値を格納していきます。

また、「const」がつけられる定数が格納されるのは
『.rodataセクション』 という領域です。

さらに関数などプログラムの機械語そのものは
『.textセクション』 という領域です。


メジャーなのはそのあたりですが、
ビルド後の実行ファイルの各セクションがどのように配置されるか、
下記のコマンドで確認することができます。

>objdump -h a.exe



落とし穴


初めの話に戻り、.bssは 言語の仕様として0初期化される と決まっているので

「じゃあグローバル変数は自動的に『起動時0初期化処理』されてるものとして
 使うときも特に初期化せずに使えば良いね」

と考えられるかというと、そうでも無いようです。


場合によって、例えば組み込み機器などで

「電源投入からプログラム起動までの時間を極力短くしたい。
 メモリの初期化時間ですら、可能なかぎり限界まで削りたい」

というシーンでは、

やろうと思えばこの『起動時0初期化処理』を省くことができるようで、
そうすると実行時のグローバル変数には「不定値」が入っていたりするとの事。

やはり変数を使う前には、明示的に値を入れて初期化してから使う方がよさそうです。
見つけにくいバグや、不要な不安やトラブルを避けられますもんね。
今後実装する時やレビューする際は、気を付けたいと思います。

2019年1月19日土曜日

git コマンド チートシート。これだけは覚えておきたい!



こんにちは。よっしーです。

複数人のプロジェクトに参加すると、

もれなくついてくるのが、バージョン管理システムです。


少し前までは svn をよく使っていたのですが、

時代の流れもあり、最近では git を使うようになりました。


現在は、開発環境がLinuxなので、GUIツールは使わず、

端末上で git コマンドを直接叩いて処理しています。


せっかくなので、これだけ覚えていれば一通りの作業は出来ますよ。

というものを自分用の備忘録として以下にまとめます。




1.git リポジトリを取得

git clone https://リポジトリアドレス

この場合、デフォルトで master ブランチが取得されることになるので、
master 以外のブランチを直接取得する場合は、以下のブランチ指定で clone する。

git clone -b ブランチ名 https://リポジトリアドレス



2.git の設定

ユーザ名とEメールの設定

git config --global user.name ユーザ名
git config --global user.email Eメールアドレス

(この設定をしないと git へ commit 出来ない。)

git commit する時、パーミッション変更を無視する設定

git config core.filemode false



3.commit 関連

変更内容をaddする

git add コミットしたいファイル

全ての変更内容を add する場合は以下。

git add -A

変更ファイルなどの一覧を確認

git status

変更内容をコミット

git commit -m コミットログ

リポジトリへ反映

git push origin ブランチ名



4.差分確認

add する前に変更点を見る

git diff

add した後に変更点を見る

git diff --cached

commit した後に変更点を見る

git diff HEAD^



5.コミットログ確認

ログを確認

git log

ログを差分付きで確認

git log -p



6.ブランチ操作

変更の取り消し(追加されたファイルは残る)

git checkout .

ブランチ切り替え

git checkout -b ブランチ名 origin/ブランチ名



7.コミットログ

git commit する際のコミットログ(変更履歴)ですが、

業界的には「明確で簡潔に英語で!」というのがスタンダードになりつつあります。

英語が苦手な私は、これを考えるのに、なかなか時間がかかったりします。


そういったコミットログを考えるのに困っている人のため、

コミットログの例文をまとめているサイトもあります。

かなり、ここには助けられていますので、同じような人は参考にしてみてください。




ではまた~。

2019年1月12日土曜日

Visual Studio Code で C++ と Python をデバッグする


こんにちは、ふじかーです。

明けましておめでとうございます。本年もよろしくお願いします。

さて、こないだ下記の記事で VS Code でC言語デバッグできるようにしたんですが
Visual Studio Code でC言語をステップ実行

現場で C++ を扱う可能性が出てきたので、
そちらも VS Code で動かせるようにしたいと思います。

あと、ついでに Python も動かせるようにしたいと思います。

C++_デバッグ環境作成の流れ


    基本的に前回の C言語環境 作成時と同じ流れです。
    ファイル名や設定が少し異なるくらい。
    → ここまでは C言語環境 作成時と全く同じ手順ですので
      前回の記事にリンクしています。実施済みの場合とばしてください。



    C++_作業場所、test.cppの準備


    C言語の時と同じく、適当にHelloWorldソースを用意します。

    #include <iostream>
    
    int main() {
        std::cout << "Hello, world!" << std::endl;
        return 0;
    }
    

    これを作業フォルダに保存しておきます。ここでは D:\test\cpp\test.cpp としました。

    またこの作業フォルダを、VS Code のメニューから開いておきましょう。
    ・メニュー → フォルダーを開く → D:\test\cpp



    C++_デバッグの為の設定

    • ビルドタスクの設定(tasks.json)
    修正したソースコードをビルドするための設定を行います。
    ほぼC言語の時と同じで、コマンド行が下記のように異なるだけなので
        C言語・・・ "gcc -g -O0 -o a.exe test.c"
        C++   ・・・ "g++ -g -O0 -o a.exe test.cpp"

    C言語の時の tasks.json があるならファイルコピペして
    コマンド行だけ編集してもOKです。

     ・フォルダーを開いている状態で Ctrl+Shift+B
     ・「実行するビルドタスクがありません。ビルドタスクを構成する」というメッセージが出るのでクリック
     ・「テンプレートからtask.jsonを作成する」というメッセージが出るのでクリック
     ・表示された候補の中から「Others 任意の外部コマンドを実行する例」を選択
      → 作業フォルダ内に「.vscode/tasks.json」ファイルが自動生成され、画面に表示される




     ・表示された task.json の
    "command": "echo Hello"
    
      を削除して、下記を挿入
    "command": "g++ -g -O0 -o a.exe test.cpp",
    "problemMatcher": "$tsc", 
    "group": {
        "kind": "build",
        "isDefault": true
    }
    
     ・Ctrl+S で保存しておく


    • デバッグ環境の設定(launch.json)
     デバッグに必要な設定を行います。こちらはC言語の時と完全に同じなので、
    C言語の時の launch.json があるならファイルコピペでもOKです。

     ・画面左のデバッグアイコンを押下
     ・デバッグの開始アイコン(再生マーク)を押下
     ・表示された候補の中から「C++(GDB/LLDB)」を選択
      → 作業フォルダ内に「.vscode/launch.json」ファイルが自動生成され、画面に表示される




     ・表示された launch.json の
    "program": "enter program name, for example ${workspaceFolder}/a.exe",
    "miDebuggerPath": "/path/to/gdb",
    
      を削除して、下記を挿入
    "program": "${workspaceRoot}/a.exe",
    "miDebuggerPath": "c:\\mingw\\bin\\gdb.exe",
    
     ・Ctrl+S で保存しておく



    C++_デバッグ開始!


     ・試したいコードをmain関数に記載し、リビルドは Ctrl+Shift+B
     ・ブレークポイントをセットしてF5でデバッグ開始、F10でステップ実行



    Python_デバッグ環境作成の流れ


      お次は Python です。
        →  ここも同じ手順ですので、実施済みの場合とばしてください。



        Python3のインストール


        パソコンにまだPythonを入れていない場合、
        下記サイトに従ってインストールしておきます。








        Python_拡張機能をインストール


        C言語の時と同じく、Python開発用の拡張機能もインストールしておきます。
         ・画面左の 拡張機能(Extensions)ボタン を押して「python」で検索 → インストール → VS Codeを再起動






        Python_作業場所、test.pyの準備


        C言語の時と同じく、適当にHelloWorldソースを用意します。

        a = "Hello World!"
        print(a)
        

        これを作業フォルダに保存しておきます。ここでは D:\test\python\test.py としました。

        またこの作業フォルダを、VS Code のメニューから開いておきましょう。
        ・メニュー → フォルダーを開く → D:\test\python



        Python_デバッグ開始!




         ・ブレークポイントをセットしてF5でデバッグ開始、F10でステップ実行


        Pythonはインタープリタ言語なのでビルドとか必要ありません。お手軽。
        ただこのとき、こんなエラーメッセージが出る事があります。



         これはPythonのLinter(構文チェッカ)が入ってないよ、というエラーのようなので
         インストールしておきましょう。