Debianのapache2の設定方法
学生が、Raspberry-PiでCGIを使いたいらしいけど、設定の方法がDebianは一癖あるので、 説明資料を記述。
Debianの原則
Debianでは、基本的な設定ファイルは極力自分で触らない主義。
apache2 も同様で、便利なモジュールも設定ファイルは、必要なものは モジュール毎にインストール時に読み込ませて、触らない主義。
このための設定があって、 CGIとかPHPといったものは、モジュールで管理。
DebianのApache2設定ファイルの考え方
一般的なApacheでは、設定は、/etc/apache2/apache2.conf とか、 /etc/apache2/httpd.conf に記述する。 しかし、いくつものモジュールを使うと、これらの設定ファイルが、 巨大で理解困難になってしまう。
このためDebianのapache2 では、/etc/apache2/*-enabled で対応する。 /etc/apache2/apache2.conf には、以下のような行が書いてあり、 *-enabled配下の設定ファイルをすべて読み込んで起動する。
(( /etc/apache2/apache2.confの一部 )) IncludeOptional mods-enabled/*.load IncludeOptional mods-enabled/*.conf IncludeOptional conf-enabled/*.conf IncludeOptional site-enabled/*.conf
/etc/apache2/mods-enabled (mods-available)
- 必要なモジュールをインストールすると、 設定ファイルは /etc/apache2/mods-available に書き込まれる。
(モジュール名.load モジュール名.conf)使えるモジュールは、以下のコマンドを使えば、一覧が見れる。 $ aptitude search libapache2-mod インストールしたいモジュールが見つかったら $ sudo aptitude install libapache2-mod-モジュール
- 本当に使いたいモジュールは、以下のコマンドを実行。
$ sudo /usr/sbin/a2enmod モジュール名 /etc/apache2/mods-enabled に、mods-available への シンボリックリンクを作ってくれる。
使いたくなくなったら、
$ sudo /usr/sbin/a2dismod モジュール名
- a2enmodなどを実行したら、以下のコマンドで apache2を再起動
$ sudo /etc/init.d/apache2 restart
基本原則 /etc/apache2/mods-enabled の配下の設定ファイルは触らない。 どうしても設定ファイルを変更したい場合は、conf-enabled , site-enabled で設定。
/etc/apache2/sites-enabled (sites-available)
- apache2では、1台のコンピュータで複数のwebサイトを構築できる。 バーチャルホストの設定は1つのホスト毎に、sites-available の *.conf に記述。 ホスト毎の細かい設定は、この中に記述する。
- そのホストを使えるようにしたかったら、以下のコマンド。
$ sudo /usr/sbin/a2ensite ホスト /etc/apache2/site-enabled に、site-available への シンボリックリンクを作ってくれる。
ホストを使えないようにする。
$sudo /usr/sbin/a2dissite ホスト
- a2ensite を実行したら、"/etc/init.d/apache2 restart"
/etc/apache2/conf-enabled (cont-available)
- site-* では、各ホスト毎の設定を書くけど、すべての仮想ホストに共通な 設定は、conf-enabled / conf-available を使う。
- 設定を /etc/apache2/conf-available の中に、設定名.conf で記述し、 以下のコマンドで有効にする。
$ sudo /usr/sbin/a2enconf 設定名 $ sudo /usr/sbin/a2disconf 設定名
(例)
CGIを使いたい (CGIは基本モジュールなのでlibapache2-mod-cgi などはしなくていい)
$ sudo /usr/sbin/a2enmod cgi # cgiモジュールの有効化 $ sudo /etc/init.d/apache2 restart
PHP5を使いたい
$ sudo aptitude install php5 # PHP5をインストール $ sudo aptitude install libapache2-mods-php5 # apache2のphp5モジュールをインストール $ sudo /usr/sbin/a2enmod php5 # php5モジュールの有効化 $ sudo /etc/init.d/apache2 restart # apache2 の再起動
ページは各ユーザの /home/user/public_html/ 配下に作らせたい。
$ sudo /usr/sbin/a2enmod userdir
SSLのhttps://を使いたい
$ sudo vi /etc/apache2/site-available/default-ssl.conf $ sudo /usr/sbin/a2ensite default-ssl $ sudo /etc/init.d/apache2 restart
SQLの最初
関係データベースの導入説明が終わったので、実際のSQLの説明。
create user
データベースを扱う際の create user 文は、DDL(Data Definition Language)で行う。
CREATE USER ユーザ名 IDENTIFIED BY "パスワード"
grant
テーブルに対する権限を与える命令。
GRANT システム権限 TO ユーザ名 データベースシステム全体に関わる権限をユーザに与える。 (例) GRANT execute ON admin.my_package TO saitoh GRANT オブジェクト権限 ON オブジェクト名 TO ユーザ名 作られたテーブルなどのオブジェクトに関する権限を与える。 (例) GRANT select,update,delete,insert ON admin.my_table TO saitoh REVOKE オブジェクト権限 ON オブジェクト名 TO ユーザ名 オブジェクトへの権限を剥奪する。
create table
実際にテーブルを宣言する命令。構造体の宣言みたいなものと捉えると分かりやすい。
CREATE TABLE テーブル名 ( 要素名1 型 , 要素名2 型 ... ) ; PRIMARY KEY 制約 型の後ろに"PRIMARY KEY"をつける、 もしくは、要素列の最後に、PRIMARY KEY(要素名,...)をつける。 これによりKEYに指定した物は、重複した値を格納できない。 型には、以下の様なものがある。(Oracle) CHAR( size) : 固定長文字列 / NCHAR国際文字 VARCHAR2( size ) : 可変長文字列 / NVARCHAR2... NUMBER(桁) :指定 桁数を扱える数 BINARY_FLOAT / BINARY_DOUBLE : 浮動小数点(float / double) DATE : 日付(年月日時分秒) SQLiteでの型 INTEGER : int型 REAL : float/double型 TEXT : 可変長文字列型 BLOB : 大きいバイナリデータ DROP TABLE テーブル名 テーブルを削除する命令
insert,update,delete
指定したテーブルに新しいデータを登録,更新,削除する命令
INSERT INTO テーブル名 ( 要素名,... ) VALUES ( 値,... ) ; 要素に対応する値をそれぞれ代入する。 UPDATE テーブル名 SET 要素名=値 WHERE 条件 指定した条件の列の値を更新する。 DELETE FROM テーブル名 WHERE 条件 指定した条件の列を削除する。
select
データ問い合わせは、select文を用いる、 select文は、(1)必要なカラムを指定する射影、(2)指定条件にあうレコードを指定する選択、 (3)複数のテーブルの直積を処理する結合から構成される。
SELECT 射影 FROM 結合 WHERE 選択 (例) SELECT S.業者番号 FROM S WHERE S.優良度 > 30 ;
2分木の生成
先週に2分木に対する再帰などを交えたプログラムの説明をしたので、 今週は木の生成について、AVL木などを交えて説明。 後半は、情報処理センターで演習。
#include <stdio.h> #include <stdlib.h> // 2分木の宣言 struct Tree { int data ; struct Tree* left ; struct Tree* right ; } ; // 木の根 struct Tree* top = NULL ; // 木のノードを構築する補助関数 struct Tree* tcons( int x , struct Tree* l , struct Tree* r ) { struct Tree* n ; n = (struct Tree*)malloc( sizeof( struct Tree ) ) ; if ( n != NULL ) { n->data = x ; n->left = l ; n->right = r ; } return n ; } // 木を表示する補助関数。枝の左右がわかる様に... void print( struct Tree* p ) { if ( p == NULL ) { printf( "x" ) ; } else { printf( "(" ) ; print( p->left ) ; printf( " %d " , p->data ) ; print( p->right ) ; printf( ")" ) ; } } // 木に1件のデータを追加する補助関数 void entry( int x ) { struct Tree** ppt = &top ; while( (*ppt) != NULL ) { if ( (*ppt)->data == x ) break ; else if ( (*ppt)->data > x ) ppt = &( (*ppt)->left ) ; else ppt = &( (*ppt)->right ) ; } if ( *ppt == NULL ) (*ppt) = tcons( x , NULL , NULL ) ; } int main() { entry( 51 ) ; entry( 26 ) ; entry( 76 ) ; entry( 60 ) ; print( top ) ; // ((x 26 x) 51 ((x 60 x) 76 x)) top = NULL ; entry( 26 ) ; entry( 51 ) ; entry( 60 ) ; entry( 76 ) ; print( top ) ; // (x 26 (x 51 (x 60 (x 76 x)))) }
2EI実験ガイダンスでコンピュータ将棋など…
電子情報工学科の2年の後期実験では、 私の担当はゲームのプログラミング。 といっても、シューティングなどではなく、オセロ・五目並べ・ポーカーの 勝敗判定や役判定などを行うプログラムを通して、 プログラミングの大変さを味わってもらう。
プログラミングは、論理的思考能力のたわものではあるが、 ある程度は「プログラムを自分で作って間違った経験の差」が、 プログラム能力になると思う。そこで、タイミングやアニメ表示の プログラミングではなく、ゲーム盤の勝敗判定のプログラミングを通して 経験を深めてもらうのが目的。
簡単なゲームプログラムの作成
実験の配布資料を上記に示す。 実験では、2人が交互にオセロの手を打ち、ルール判定や勝敗を行うプログラムを作成するのが目標。
プログラミング技量に応じたプログラム作成をしてもらうために、 2週の最初にどの機能までを実装するのか、実装する機能目標の表をチェックし、 1週目さいご、2週目さいごに進捗を自分で確認する。 2週の最後には、隣の人と本当に動くのかチェックをしてもらう。
コンピュータ.vs.人間による対戦
実験ガイダンスは簡単にしておいて、プログラミングの興味を持ってもらうために、 チェスなどのコンピュータ対戦の雑談。
- コンピュータ・オセロ
- コンピュータ・チェス
チェス:カスパロフ.vs.ディープ・ブルー ・DB.vs.Kasparov動画 - コンピュータ将棋
電王戦の記録
電王戦で衝撃的な結末!「角成らず」を認識できずに反則負け… ・角歩成らず動画 - コンピュータ囲碁
コンピュータは論理的思考の処理(左脳)が得意で、現状ではコンピュータの速度にはかなわない。 しかし、人間のイメージで捉える能力(右脳)ではまだまだ劣っている。 こういった領域でもコンピュータが活躍するための研究なども進められている。
プログラマーに見て欲しい映画
構造体の参照渡しとオブジェクト指向
一緒に、来週のプログラミング応用の資料書いちゃえ。
構造体の参照渡し
構造体のデータを関数の呼び出しで記述する場合には、参照渡しを利用する。
struct Person { char name[ 20 ] ; int age ; } ; void print( struct Person* p ) { printf( "%s %d¥n" , p->name , p->age ) ; } void main() { struct Person saitoh ; strcpy( saitoh.name , "t-saitoh" ) ; saitoh.age = 50 ; print( &saitoh ) ; }
このようなプログラムの書き方をすると、「データ saitoh に、print() せよ…」 といった処理を記述したようになる。 これを発展して、データ saitoh に、print という命令をするイメージにも見える。
この考え方を、そのままプログラムに反映させ、Personというデータは、 名前と年齢、データを表示するprintは…といったように、 データ構造と、そのデータ構造への処理をペアで記述すると分かりやすい。
オブジェクト指向の導入
オブジェクト指向では、データ構造とその命令を合わせたものをクラス(class)と呼ぶ。 また、データ(class)への命令は、メソッド(method)と呼ぶ。
class Person { private: char name[ 20 ] ; int age ; public: Person( char s[] , int a ) { strcpy( name , s ) ; age = a ; } int scan() { return scan( "%s %d" , name , &age ) ; } void print() { printf( "%s %d¥n" , name , age ) ; } } ; void main() { Person saitoh( "t-saitoh" , 50 ) ; saitoh.print() ; Person table[ 50 ] ; for( int i = 0 ; i < 50 ; i++ ) { if ( table[ i ].scan() != 2 ) break ; table[ i ].print() ; } }
構造体とオブジェクト指向
プログラミング応用の後期では、構造体とコンピュータグラフィックスの基礎を扱う予定。 CGの基礎でも、X座標,Y座標…をひと塊の構造体で表現という意味では、構造体の延長として授業を進める予定。
構造体
上記資料を元に説明。 最初に構造体が無かったら、名前・国語・算数・理科の1クラス分のデータをどう表現しますか?
// まずは基本の宣言 char name[ 50 ][ 20 ] ; int kokugo[ 50 ] ; int sansu[ 50 ] ; int rika[ 50 ] ; // もしクラスが最初20人だったら、20→50に変更する際に、 // 文字列長の20も書きなおしちゃうかも。 // 50とか20とかマジックナンバーは使わないほうがいい。 #define SIZE 50 #define LEN 20 char name[ SIZE ][ LEN ] ; int kokugo[ SIZE ] ; : // 2クラス分のデータ(例えばEI科とE科)を保存したかったら? // case-1(配列2倍にしちゃえ) char name[ 100 ][ 20 ] ; // どこからがEI科? int kokugo[ 100 ] ; : // case-2(2次元配列にしちゃえ) char name[ 2 ][ 50 ][ 20 ] ; // 0,1どっちがEI科? int kokugo[ 2 ][ 50 ] ; : // case-3(目的に応じた名前の変数を作っちゃえ) char ei_name[ 50 ][ 20 ] ; // EI科は一目瞭然 int ei_kokugo[ 50 ] ; // だけど変数名が違うから : // 処理を2度書き char ee_name[ 50 ][ 20 ] ; int ee_kokugo[ 50 ] ; :
このような問題に対応するために構造体を用いる。
struct Person { // Personが構造体名(タグ名) char name[ 20 ] ; int kokugo ; int sansu ; int rika ; } ; struct Person saitoh ; struct Person ei[ 50 ] , ee[ 40 ] ; strcpy( saitoh.name , "t-saitoh" ) ; saitoh.kokugo = 100 ; ei[ 0 ].sansu = 80 ; ee[ 1 ].rika = 75 ;
授業では、構造体の初期化、入れ子の話をする。詳細は配布資料参照。
途中で、C言語の歴史として、unix開発時に、BCPL→B言語→C言語(K&R)→ANSI-C→…C++→D言語 といった雑談も説明。
入れ子の話では、 for(…) { for(…) { } } のような、処理の入れ子(処理の構造化)と、 構造体の入れ子(データの構造化)の話から、構造化プログラミング(structured programming)といった話も紹介する。
データベース・ガイダンス
今日が後期の選択科目「データベース」の第一回目ということで、 シラバス配布&ガイダンスをしてからぁ〜のぉ〜、概要説明。
インターネットの情報量
インターネット上の情報量の話として、2010年度に281EB(エクサバイト) 参考:kMGTPEZYで、今日改めて探したら、2013年度で、1.2 ZB(ゼタバイト) という情報があった。ムーアの法則2年で2倍の概算にも、それなりに近い。 今年2015年であれば、約2年で、2 ZBにはなっているかな。
そして、これらの情報をGoogleなどで探す場合、すぐにそれなりに情報を みつけてくれる。これらは、どの様に実装されているのか?
Webシステムとデータベース
まず、指定したキーワードの情報を見つけてくれるものとして、 検索システムがあるが、このデータベースはどのようにできているのか?
Web創成期の頃であれば、Yahooがディレクトリ型の検索システムを構築 してくれている。(ページ作者がキーワードとURLを登録する方式) しかし、ディレクトリ型では、自分が考えたキーワードではページが 見つからないことが多い。
そこで、GoogleはWebロボット(クローラー)による検索システムを構築した。 Webロボットは、定期的に登録されているURLをアクセスし、 そのページ内の単語を分割しURLと共にデータベースに追加する。 さらに、ページ内にURLが含まれていると、そのURLの先で、 同様の処理を再帰的に繰り返す。
これにより、巨大なデータベースが構築されているが、これを少ない コンピュータで実現すると、処理速度が足りず、3秒ルール/5秒ルール (Web利用者は次のページ表示が3秒を越えると、次に閲覧してくれない) これを処理するには負荷分散が重要となる。
一般的に、Webシステムを構築する場合には、 1段:Webサーバ、2段:動的ページ言語、3段:データベースとなる場合も 多い。この場合、OS=Linux,Web=Apache,DB=MySQL,言語=PHPの組合せで、 LAMP構成とする場合も多い。
一方で、大量のデータを処理するDBでは、 フロントエンドDB,スレーブDB,マスタDBの3段スキーマ構成となることも多い。
データベースシステム
データベースには、ファイル内のデータを扱うためのライブラリの、 BerkleyDBといった場合もあるが、複雑なデータの問い合わせを実現する 場合には、リレーショナル・データベース(RDB)を用いる。 RDBでは、データをすべて表形式であらわし、SQLというデータベース 問い合わせ言語でデータを扱う。 また、問い合わせは、ネットワーク越しに実現可能であり、こういった RDBで有名なものとして、Oracle , MySQL , PostgreSQL などがある。 単一コンピュータ内でのデータベースには、SQLite などがある。
しかし、RDBでは複雑なデータの問い合わせはできるが、 大量のデータ処理のシステムでは、フロントエンドDB,スレーブDB,マスタDB の同期が問題となる。この複雑さへの対応として、最近は NoSQL が 注目されている。
データベースが無かったら
これらのデータベースが無かったら、どのようなプログラムを作る 必要があるのか?
情報構造論ではC言語でデータベースっぽいことをしていたが、 大量のデータを永続的に扱うのであれば、ファイルへのデータの読み書き 修正ができるプログラムが必要となる。
こういったデータをファイルで扱う場合には、1件のデータ長が途中で 変化すると、N番目のデータは何処?といった現象が発生する。 このため、簡単なデータベースを自力で書くには、1件あたりのデータ量を 固定し、lseek() , fwrite() , fread() などの 関数でランダムアクセスのプログラムを書く必要がある。
また、データの読み書きが複数同時発生する場合には、排他処理も 重要となる。例えば、銀行での預け金10万の時、3万入金と、2万引落としが 同時に発生したらどうなるか? 最悪なケースでは、 (1)入金処理で、残金10万を読み出し、 (2)引落し処理で、残金10万を読み出し、 (3)入金処理で10万に+3万で、13万円を書き込み、 (4)引落し処理で、残金10万-2万で、8万円を書き込み。 で、本来なら11万になるべき結果が、8万になるかもしれない。
さらに、コンピュータといってもハードディスクの故障などは発生する。 障害が発生してもデータの一貫性を保つためには、バックアップや 障害対応が重要となる。
Raspberry-Piのカメラをサーボで制御したい
I2Cを認識させる
(( i2cを認識させる設定 )) $ sudo raspi-config ## 8 Advenced Options" -> "A7 I2C" よりI2Cを標準で認識するように設定 ## /etc/modprobe.d/raspi-blacklist.confのblacklistがコメントアウト # blacklist i2c-bcm2708 ## /etc/modules に以下の行が追加される i2c-dev i2c-bcm2708 $ sudo reboot (( i2cが認識されたか確認 )) $ sudo aptitude install i2c-tools $ ls /dev/i2c-* /dev/i2c-1 ## Raspberry-Pi によっては、/dev/i2c-0 となるかも。 $ sudo i2cdetect -y 1 0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 70: -- -- -- -- -- -- -- -- ## まだi2c機器を何も繋げていない... (( i2cをユーザで使えるように )) $ ls /dev/i2c-1 crw-rw---T 1 root i2c 89, 1 9月 10 09:02 /dev/i2c-1 ## i2cを使うためのグループにユーザpiを加える。 $ sudo adduser pi i2c