m_shige1979のときどきITブログ

プログラムの勉強をしながら学習したことや経験したことをぼそぼそと書いていきます

Github(変なおっさんの顔でるので気をつけてね)

https://github.com/mshige1979

pleiades(eclipse)のCDT(MinGW)でDLLを作成する

会社とかでするときとかさあ

VisualStudioないんですけど…
なんで買っといてくんないの(´・ω・`)
Community入れたくなるんですけど…

というわけで

フリーかどうか知らんがeclipseに入っていたMinGWを使ってDLLを作成してみる

プロジェクトを作成する

共用ライブラリとして作成

f:id:m_shige1979:20170806104546j:plain

ソースディレクトリと空のソースファイルを用意

f:id:m_shige1979:20170806104746j:plain

実装
/*
 * sample01.cpp
 *
 *  Created on: 2017/08/06
 *      Author: hogehoge
 */


extern "C" {
	__declspec(dllexport)

	/**
	 * 加算
	 */
	int add(int a, int b) {
		return a + b;
	}
};

extern "C" {
	__declspec(dllexport)

	/**
	 * 減算
	 */
	int sub(int a, int b) {
		return a - b;
	}
};
プロパティのリンカーフラグを追加

f:id:m_shige1979:20170806105454j:plain
※「-static」を追加

ライブラリ名などを設定

f:id:m_shige1979:20170806105611j:plain
※インポートライブラリ名を「libsample01.lib」を作成する
※defファイルとして「sample01.def」を作成する

ビルドを行う

f:id:m_shige1979:20170806105912j:plain
Debugディレクトリ配下に作成されていることを確認

静的インポートで使用する

プロジェクトを作成する

f:id:m_shige1979:20170806110533j:plain

プロパティのリンカーのその他のオブジェクトに「libsample01.lib」を追加

f:id:m_shige1979:20170806110743j:plain
※リンカーフラグに「-static」も忘れずに追加

実装
//============================================================================
// Name        : sample02.cpp
// Author      :
// Version     :
// Copyright   : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================

#include <iostream>
using namespace std;

// エクスポート関数定義
extern "C" __declspec(dllexport) int add(int a, int b);
extern "C" __declspec(dllexport) int sub(int a, int b);

int main() {
	cout << "!!!Hello World!!!" << endl; // prints !!!Hello World!!!

	cout << add(100, 40) << endl;
	cout << sub(100, 40) << endl;

	return 0;
}

※ヘッダーファイル用意するのめんどかったので今回は直書きです。

ビルド

f:id:m_shige1979:20170806111223j:plain
※「libsample01.dll」を配置しておくこと

実行
!!!Hello World!!!
140
60

できた感じです。

わかったこと

eclipseMinGW(64bit)はリンカーフラグに「-static」を設定しないとcoutが出力してくれない
・dllは実行プログラムと同じ場所もしくはsystem32などのシステムファイルに配置しないと読み込まない
c言語ってjavaとかと違って例外とか発生させないのでエラーでも結果がよくわからんw

所感

そもそもC言語できないんですけどね(´・ω・`)
あんましやる気はないけどとりあえずやってみた感じです。
C++のクラスとかそこそこやってみようかな…

Azure Storage ServiceでBlobの読み書きをJavaで行う

PHPではなく

Java

pom.xml

    <dependencies>
        <!-- https://mvnrepository.com/artifact/com.microsoft.azure/azure-storage -->
        <dependency>
            <groupId>com.microsoft.azure</groupId>
            <artifactId>azure-storage</artifactId>
            <version>5.0.0</version>
        </dependency>
        
        <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-io -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-io</artifactId>
            <version>1.3.2</version>
        </dependency>
        
    </dependencies>

実装

一覧出力
import java.net.URISyntaxException;
import java.security.InvalidKeyException;

import com.microsoft.azure.storage.CloudStorageAccount;
import com.microsoft.azure.storage.StorageException;
import com.microsoft.azure.storage.blob.CloudBlobClient;
import com.microsoft.azure.storage.blob.CloudBlobContainer;
import com.microsoft.azure.storage.blob.ListBlobItem;

public class Sample01 {
	
	// 接続文字列
	public static final String storageConnectionString =
		    "DefaultEndpointsProtocol=http;" +
		    "AccountName=自分のアカウント名;" +
		    "AccountKey=自分のアクセスキー";
	
	/**
	 * 指定されたコンテナのblob一覧を取得するサンプル
	 * @param args
	 * @throws URISyntaxException 
	 * @throws InvalidKeyException 
	 * @throws StorageException 
	 */
	public static void main(String[] args) throws InvalidKeyException, URISyntaxException, StorageException {
		
		// ストレージアカウントオブジェクトを取得
		CloudStorageAccount storageAccount = CloudStorageAccount.parse(storageConnectionString);
		
		// Blobクライアントオブジェクトを取得
		CloudBlobClient blobClient = storageAccount.createCloudBlobClient();
		
		// blobの指定したtest01コンテナを取得
		CloudBlobContainer container = blobClient.getContainerReference("test01");
		
		// blob情報を出力する
		for (ListBlobItem blobItem : container.listBlobs()) {
	        System.out.println(blobItem.getUri());
	    }
	}

}
読み込み
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URISyntaxException;
import java.security.InvalidKeyException;

import com.microsoft.azure.storage.CloudStorageAccount;
import com.microsoft.azure.storage.StorageException;
import com.microsoft.azure.storage.blob.CloudBlobClient;
import com.microsoft.azure.storage.blob.CloudBlobContainer;
import com.microsoft.azure.storage.blob.CloudBlockBlob;

public class Sample02 {
	
	// 接続文字列
	public static final String storageConnectionString =
		    "DefaultEndpointsProtocol=http;" +
		    "AccountName=自分のアカウント名;" +
		    "AccountKey=自分のアクセスキー";
	
	/**
	 * 指定されたコンテナのblobを読み込むサンプル
	 * @param args
	 * @throws URISyntaxException 
	 * @throws InvalidKeyException 
	 * @throws StorageException 
	 * @throws IOException 
	 */
	public static void main(String[] args) throws InvalidKeyException, URISyntaxException, StorageException, IOException {
		
		// ストレージアカウントオブジェクトを取得
		CloudStorageAccount storageAccount = CloudStorageAccount.parse(storageConnectionString);
		
		// Blobクライアントオブジェクトを取得
		CloudBlobClient blobClient = storageAccount.createCloudBlobClient();
		
		// blobの指定したtest01コンテナを取得
		CloudBlobContainer container = blobClient.getContainerReference("test01");
		
		// blobデータを読み込む
		CloudBlockBlob blob = container.getBlockBlobReference("testdata_20170716233116.txt");
		InputStream input = blob.openInputStream();
		InputStreamReader inr = new InputStreamReader(input, "UTF-8");
		
		// 読み込んだ値を出力する
		String utf8str = org.apache.commons.io.IOUtils.toString(inr);
		System.out.println(utf8str);

	}
}
書き込み
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.net.URISyntaxException;
import java.security.InvalidKeyException;

import com.microsoft.azure.storage.CloudStorageAccount;
import com.microsoft.azure.storage.StorageException;
import com.microsoft.azure.storage.blob.BlobOutputStream;
import com.microsoft.azure.storage.blob.CloudBlobClient;
import com.microsoft.azure.storage.blob.CloudBlobContainer;
import com.microsoft.azure.storage.blob.CloudBlockBlob;

public class Sample03 {
	
	// 接続文字列
	public static final String storageConnectionString =
		    "DefaultEndpointsProtocol=http;" +
		    "AccountName=自分のアカウント名;" +
		    "AccountKey=自分のアクセスキー";
	
	/**
	 * 指定されたコンテナのblobを書き込むサンプル
	 * @param args
	 * @throws URISyntaxException 
	 * @throws InvalidKeyException 
	 * @throws StorageException 
	 * @throws IOException 
	 */
	public static void main(String[] args) throws InvalidKeyException, URISyntaxException, StorageException, IOException {
		
		// ストレージアカウントオブジェクトを取得
		CloudStorageAccount storageAccount = CloudStorageAccount.parse(storageConnectionString);
		
		// Blobクライアントオブジェクトを取得
		CloudBlobClient blobClient = storageAccount.createCloudBlobClient();
		
		// blobの指定したtest01コンテナを取得
		CloudBlobContainer container = blobClient.getContainerReference("test01");
		
		// blobデータへ書き込む準備
		CloudBlockBlob blob = container.getBlockBlobReference("testdata_20170725000000.txt");
		BlobOutputStream output = blob.openOutputStream();
		
		// データを書き込む
		output.write("aaaaaaa".getBytes());
		output.close();
	}
}

所感

今回というかファイルをローカルに扱うのは準備が面倒な感じがしたのでテキストデータを読み込んだり、書き込んだりする方法を記載。
PHPの場合はそのまま読み込んでも良いけど、Javaの場合は型が厳密なのでそこそこ手段が別れているような感じです。

scoket.ioで下層パスごとに処理を記載する

パス別に処理を分割したいみたいな…

ホスト名は実際のwebサイトみたいに扱って/hogehoge1、/hogehoge2とかでsocket通信したいみたいな感じですかね

やったこと

下層パスを用意して、処理を記載。
クライアントもそれに合わせたURIを指定してアクセス

実装

サーバ側
var io = require('socket.io').listen(3000);

// 下層パス1
io.of("/hogehoge/test1").on("connect", socketFunction1);

// 下層パス2
io.of("/hogehoge/test2").on("connect", socketFunction2);

// 接続処理1
function socketFunction1(socket) {

    console.log("/hogehoge/test1: connected");

    // メッセージ
    var msg = {
        "client": "client_" + (new Date()).getTime(),
        "msg": "接続OKです。"
    };
    socket.emit("client_info", msg);

    // 切断
    socket.on("disconnect", function() {
        console.log("/hogehoge/test1: disconnected");
    });

    // メッセージ受信
    socket.on("message", function(data) {
        console.log("送信:" + data);
    });

}

// 接続処理2
function socketFunction2(socket) {

    console.log("/hogehoge/test2: connected");

    // メッセージ
    var msg = {
        "client": "client_" + (new Date()).getTime(),
        "msg": "接続OKです。"
    };
    socket.emit("client_info", msg);

    // 切断
    socket.on("disconnect", function() {
        console.log("/hogehoge/test2:" + "disconnected");
    });

    // メッセージ受信
    socket.on("message", function(data) {
        console.log("送信:" + data);
    });

}
クライアント1
var client = require("socket.io-client");
var socket = client.connect("http://localhost:3000/hogehoge/test1");

// 接続
socket.on("connect", function() {
    console.log("/hogehoge/test1: client connected");
});

// メッセージ受信
socket.on("message", function(data) {
    console.log("/hogehoge/test1:" + "受信文字:" + data);
});

// 接続情報
socket.on("client_info", function(data) {
    clientId = data.client;
    console.log("client:" + clientId);
});

// 5秒後に切断
setTimeout(function() {
    socket.disconnect();
}, 5000);
クライアント2
var client = require("socket.io-client");
var socket = client.connect("http://localhost:3000/hogehoge/test2");

var clientId = "";

// 接続
socket.on("connect", function() {
    console.log("/hogehoge/test2 client connected");
});

// メッセージ受信
socket.on("message", function(data) {
    console.log("/hogehoge/test2: " +  "受信文字:" + data);
});

// 接続情報
socket.on("client_info", function(data) {
    clientId = data.client;
    console.log("client:" + clientId);
});

// 5秒後に切断
setTimeout(function() {
    socket.disconnect();
}, 5000);

所感

サーバ側はそれぞれ用意しないといけないのと同じでクライアントもURIを指定する必要がある。
まあ、サーバで設定するイベントの使用可否が変わってくるはずなのでこの辺の問題は受け入れる事となる。
実際にhttp://localhost:3000/sample1みたいなURIのsocket.io通信自体はあるのでその設定自体がわかっただけでも良いこととなりました。
最初はwebサーバとかでなんかしないといけないとか考えてて面倒くさいと思っていたのでちょっと楽になった感じ
javascriptjqueryしか使っていないのでnodejsをもう少し勉強してjavascriptの知識向上に役立てたい。

nodejsのsocket.ioのサーバにJavaで作成したクライアントで接続する

ソケット通信のサンプルって

基本TCP/IP関連のやつなんですね。
まあ、わかりますけど、websocketとか使う際はどんなデータが流れてくるとかどんな手法で送信したらよいとかちょっとわかりづらい事があります。

今回はJavaでsocket.ioのサンプルを探して見ました。

簡単なやつですけど助かりました。

実装

サーバ側
var io = require('socket.io').listen(3000);

// 接続
io.sockets.on("connect", function(socket) {
    console.log("connected");

    // 接続後にクライアントへ送信する
    socket.emit("message", "接続OKです。");

    // 切断
    socket.on("disconnect", function(data) {
        console.log(data);
        console.log("disconnected");
    });

    // メッセージ受信
    socket.on("message", function(data) {
        console.log("送信:" + data);
    });

});
クライアント側
package socket_sample01;

import java.net.URISyntaxException;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.TimeUnit;

import io.socket.client.IO;
import io.socket.client.Socket;
import io.socket.emitter.Emitter;

public class Sample01 {
	
	private static Socket socket;
	
	public static void main(String[] args) throws URISyntaxException, InterruptedException {
		socket = IO.socket("http://localhost:3000");

        // サーバーからのmessageがemitされた時
        socket.on("message", new Emitter.Listener() {
            public void call(Object... objects) {
                // 最初の引数を表示
                System.out.println(objects[0]);
                //サーバー側にmessageで送信
                socket.emit("message", "This is Java");
            }
        });
        
        // 接続開始
        socket.connect();
        
        // タイマーようのタスク
        class SampleTask extends TimerTask {

        	/** このメソッドがTimerから呼ばれる */
        	@Override
        	public void run() {
        		System.out.println("タスク実行:" + new Date());
        		
        		// 切断処理
        		socket.disconnect();
        	}
        }
        
        // 一定時間後に処理を切断するように指示
        TimerTask task = new SampleTask();
        Timer timer = new Timer("myTimer");
        System.out.println("処理開始:" + new Date());
        timer.schedule(task, TimeUnit.SECONDS.toMillis(3)); //3秒遅延させる
        TimeUnit.SECONDS.sleep(5);
        timer.cancel();
        System.out.println("処理終了");

	}

}

クライアントのライブラリ

  <dependencies>
    <dependency>
      <groupId>io.socket</groupId>
      <artifactId>socket.io-client</artifactId>
      <version>1.0.0</version>
    </dependency>
  </dependencies>

所感

簡単な接続自体はできた。
単純なメッセージではなく、配列とかクラスのようなデータの場合はどのような設定で送信すればよいのかちょっと調べてみよう。

nodejsでsocket.ioのサンプルを作成

socket.io

nodejsのモジュールで双方向通信を可能とするモジュール。
WebScoketなどを用いてチャットなどを実行できる。

いままではhttp併用

だったけど、socket.ioのみのバージョンを用意できるようになったらしい

環境

nodejs v8系
※nodebrewなどを使用してバージョンを更新

実装

サーバ側
var io = require('socket.io').listen(3000);

// 接続
io.sockets.on("connect", function(socket) {
    console.log("connected");

    // 接続後にクライアントへ送信する
    socket.emit("message", "接続OKです。");

    // 切断
    socket.on("disconnect", function(data) {
        console.log(data);
        console.log("disconnected");
    });

});
クライアント側
var client = require("socket.io-client");
var socket = client.connect("http://localhost:3000");

// 接続
socket.on("connect", function() {
    console.log("client connected");
});

// メッセージ受信
socket.on("message", function(data) {
    console.log("受信文字:" + data);
});

// 3秒後に切断
setTimeout(function() {
    socket.disconnect();
}, 3000);

今回はここまで

所感

nodejs自体は嫌いではなかったけどなんとなるやる気が行いものでした。
socket.ioをやってみることの必要性が感じられたのでちょっとだけやっている状態。
最近ではスタンドアローンでのサーバークライアントの処理がかなり簡単にかけるようになったのでやっている。
クライアントから任意のタイミングで切断もできるようなので処理も任意に制御できそうかも…

AzurよりSendGridを使用してメールを送信する

Azureでのメール送信はSendGridらしい

詳しくは知らないけどSendGridの送信手段を調べてみました。

環境

CentOS7
PHP7

Azure設定

サービスを追加

f:id:m_shige1979:20170720165411p:plain

アプリ名やパスワードを設定

f:id:m_shige1979:20170720165420p:plain

料金プランを設定

f:id:m_shige1979:20170720165429p:plain

アクセス情報を設定

f:id:m_shige1979:20170720165440p:plain

同意確認を行う

f:id:m_shige1979:20170720165449p:plain

作成ボタンを押下

f:id:m_shige1979:20170720165458p:plain

ダッシュボードに作成されたことを確認

f:id:m_shige1979:20170720165507p:plain

Azureの管理画面より「Manage」を押下してSendGridの管理ページへジャンプ

f:id:m_shige1979:20170720165518p:plain

メールを送信して認証チェックを行う

f:id:m_shige1979:20170720165527p:plain

メール送信完了画面

f:id:m_shige1979:20170720165535p:plain

自分のメールクライアントよりメールを受信してボタンを押下

f:id:m_shige1979:20170720165545p:plain

認証後はそのまま管理画面を表示

f:id:m_shige1979:20170720165648p:plain

APIキー作成画面を表示

f:id:m_shige1979:20170720165657p:plain

作成ボタンを押下して作成画面を表示

f:id:m_shige1979:20170720165708p:plain

APIキー名と権限を設定

f:id:m_shige1979:20170720165719p:plain

キーの値をクリックしてコピーする

f:id:m_shige1979:20170720165729p:plain

Azureの設定画面で資格情報を取得

f:id:m_shige1979:20170720165739p:plain
※パスワードは設定したもの、ユーザ名はこれを使用することでメール送信のパラメータとなります。

送信用設定

yum
udo rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
sudo rpm -Uvh http://rpms.famillecollet.com/enterprise/remi-release-7.rpm
sudo yum install --enablerepo=remi,remi-php70 php php-devel php-mbstring php-pdo php-gd php-xml php-intl
composer
mkdir -p sample1
cd sample1
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php -r "if (hash_file('SHA384', 'composer-setup.php') === '669656bab3166a7aff8a7506b8cb2d1c292f042046c5a994c43155c0be6190fa0355160742ab2e1c88d40d5be660b410') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
php composer-setup.php
php -r "unlink('composer-setup.php');"
php composer.phar require swiftmailer/swiftmailer
composer.json
{
    "require": {
        "swiftmailer/swiftmailer": "5.3.0"
    }
}

実装

sendmail1.php
<?php
include_once "vendor/autoload.php";

// 本文
$text = "Hi!\nHow are you?\n";

// 送信元
$from = array(
    '送信元メールアドレス' => 'sample_from'
);

// 送信先
$to = array(
    '送信先メールアドレス' => 'sample_to',
);

// タイトル
$subject = 'Example PHP Email';

// ユーザ情報
$username = '資格情報のユーザ名';
$password = '資格情報のパスワード';

// 送信設定
$transport = Swift_SmtpTransport::newInstance('smtp.sendgrid.net', 587);
$transport->setUsername($username);
$transport->setPassword($password);
$swift = Swift_Mailer::newInstance($transport);

// メッセージ生成
$message = new Swift_Message($subject);

// 送信情報設定
$message->setFrom($from);
$message->setBody($text, 'text/plain');
$message->setTo($to);

// 送信処理
if ($recipients = $swift->send($message, $failures)) {
   echo "送信成功";
} else {
    echo "送信失敗";
}
sendmail2.php
<?php

// 接続情報
$url = 'https://api.sendgrid.com/';
$user = '資格情報より取得したユーザ名';
$pass = '資格情報より取得したパスワード';

// 送信情報
$params = array(
    'api_user' => $user,
    'api_key' => $pass,
    'to' => '送信先のメールアドレス',
    'subject' => 'testing from curl',
    'text' => 'testing body',
    'from' => '送信元のメールアドレス',
);

// リクエスト先設定
$request = $url.'api/mail.send.json';

// curl初期化
$session = curl_init($request);

// curl設定(POST送信)
curl_setopt ($session, CURLOPT_POST, true);

// curl設定(パラメータ設定)
curl_setopt ($session, CURLOPT_POSTFIELDS, $params);

// curl設定(ヘッダー不要、レスポンス必要?)
curl_setopt($session, CURLOPT_HEADER, false);
curl_setopt($session, CURLOPT_RETURNTRANSFER, true);

// 送信して終了
$response = curl_exec($session);
curl_close($session);

// 処理結果
print_r ($response);

※WEB APIを使用してメール送信するサンプルでもユーザとパスワードは資格情報のものを使用します。

所感

参考にしたドキュメントの通りにやることでなんとかできた。
最近は日本語のドキュメントが豊富なので環境を用意するのも簡単で助かります。
一部英語でわからないこともあるけど
まあなんとかなるかな…

Azure App FunctionsでLINE Botへプッシュ送信してみる

LINE Botにプッシュ送信はしたことあるけど

AWSのラムダとかはあまり使ったことがないので動かせるかはわからないのでやってみる

準備

LINEの開発アカウントは取得しておく
LINE Business Center

App Functionsを用意

前回のものを利用

npmインストー

Kuduを起動する

f:id:m_shige1979:20170717230744p:plain

CMDを選択する

f:id:m_shige1979:20170717230754p:plain

コマンドを確認する

f:id:m_shige1979:20170717230804p:plain

jsアプリの場所まで移動し、npm installを実施

f:id:m_shige1979:20170717230815p:plain

スクリプト修正

index.js
module.exports = function (context, myBlob) {
    // Blob情報
    var msg = "blobInfo " + "\n" +
        "Name:" + context.bindingData.name + "\n" +
        "Size:" + myBlob.length + "Bytes" + "\n";

    var accessToken = "チャネルアクセストークン";

    var request = require('request');
    var options = {
        uri: "https://api.line.me/v2/bot/message/push",
        method: "POST",
        headers: {
            "Content-type": "application/json",
            "Authorization": "Bearer " + accessToken
        },
        json: {
            "to": "テスト用のプッシュID",
            "messages":[{
                "type": "text",
                "text": msg
            }]
        }
    };
    request.post(options, function(error, response, body){
        context.log("error");
    });
    
    context.done();
};

実行

f:id:m_shige1979:20170717231107p:plain

所感

なんかちょっと遅く感じるような…
設定などに応じて時間が少しかかっているのかもしれない
まあ、動作することは確認できたのでOKとする