ドライバとサーバーのプログラミング
LinuxとRaspberry Piを用いて、室内情報の計測と他のデバイスからのデータを閲覧するためのサーバーのプログラム
- はじめに
はじめに本稿では、今回のプロジェクト演習を通して学んだ事、最後に取り組んだプロジェクトについて、演習の感想を記述します。
- 組み込み環境の理解
組み込み環境とは他のハードウェアのマイクロコンピューターにソフトウェアを組み込み、機械の中で制御が行われます。組み込み機器はディスプレイやキーボードがないので単体では基本何もできません。
組み込み環境においてはクロス開発を行います。クロス開発とは逆に自分を開発することはセルフ開発と言います。
クロス開発ではターゲット側とホスト側に分かれます。授業内ではRaspberry piをターゲットとしてクロス開発を行いました。
ターゲットへの入出力はシリアル接続を用いて行います。ターゲットにはディスプレイもキーボードもないのでシリアルを通してホスト側から入出力を行います。
この際にホストのキーボードからシリアルに入力をするためにminicomというソフトを用います。
以上の準備をした上でクロスコンパイルを行います。クロスコンパイルではARM用のクロスコンパイラarm-linux-gnueabi-gccを用います。
この時に気を付けておくべきなのはターゲットはscpサーバーにはなれない事です。
サーバー側は通信要求を待ち、クライアント側が通信要求を出します。つまりraspberry piはターゲットであるためクライアントにしかなれません。よって常に通信要求を出すことしかできないのです。そのため、組み込み環境においてはこういった関係を把握しておくことが重要です。
- 最終課題の動作概要
3章より最終プロジェクトの説明に入ります。最終課題は通信アプリコースの1番でマルチスレッド版Webサーバーを作成しました。
課題の概要は、サーバーに対するクライアントが複数存在する場合ソケットへ入力待ちが入ると処理中のクライアントが停止してしまうため、この対策方法として、スレッドを用いてクライアントごとにスレッド生成するサーバーのプログラムの作成をすることです。クライアントからのアクセスにはraspberry piを用いて温度計測を行い、その結果をHTMLを用いて表示します。
プログラムの大きな流れとしてはソケットの作成→アドレスの作成→ソケットにアドレスを割り当て→コネクション要求を待つ→要求の待ちまでサーバーを準備します。
待ち状態中のサーバーに通信要求が入ったらスレッドを作成し、また待ち状態に入って通信要求を待ちます。このようにして複数のクライアントからの要求を処理できるようにします。
スレッド内ではraspberry piの温度センサから温度を読み取りHTMLとして表示します。
このような流れでプログラを作成しました。
- システムの詳細
システムの詳細について説明します。
while(1)
{
new_sockfd = accept(sockfd, NULL, NULL);
if(new_sockfd == -1)
{
perror("ERROR accept\n");
}
pthread_t t0;
pthread_create(&t0, NULL, fun, (void *) &new_sockfd);
pthread_detach(t0);
}
上の文ではサーバーの要求の待ちとスレッドの作成を行っています。要求があればスレッドを作成し、pthread_detachで即座に切り離します。そしてwhileの繰り返しによりまた要求の待ちに入ります。
get_resource();
i2c = open("/dev/i2c-1", O_RDWR);
if(i2c < 0)
{
perror("open\n");
exit(1);
}
// set slave device's address
ret = ioctl(i2c, I2C_SLAVE, 0x76); // 0x76 = slave address
if (ret < 0)
{
perror("ioctl");
}
initBME280(i2c);
// get temperature
i2c_mread(i2c, TEMP_MSB, data, 3);
temp = (data[0]<<12) | (data[1]<<4) | (data[2]>>4);
printf("%d\n", temp);
temp_d = BME280_compensate_T_int32(temp)/100.0;
printf("%f C\n", temp_d);
release_resource();
上のプログラムはスレッド内で温度を測るプログラムです。一連の作業の前後にget_resource()とrelease_resource()というmutexを用いてraspberry piへのアクセスを制限する作業を追加しています。これによりrasberry piの温度センサに同時に複数のアクセスが内容に管理できます。測った温度は変数temp_dに保存します。
fprintf(istream, "HTTP/1.1 200 OK\r\n");
fprintf(istream, "\r\n");
fprintf(istream, "%f C\r\n", temp_d);
上のプログラムはスレッド内でfprintfを行いアクセスに対する出力としてHTMLでtemp_dに保存された気温のデータを出力します。
printf("sleep in\n");
sleep(20);
rintf("sleep out\n");
上のプログラムは実際に複数のクライアントからの通信要求を処理しているかの確認のテストです。スレッドの作業にsleep(20)を用いて20秒間スレッドを寝かせます。これにより一つのクライアントの処理に確実に20秒間の処理行わせます。この処理の前に”sleep in”という表示を行います。この処理が終わったら”sleep out”の表示をしてスレッドを終了します。
一つのスレッドが寝ている間に違うクライアントから要求を出します。この時片方のスレッドで”sleep in”の表示を確認し、そのスレッドが”sleep out”の表示とともにスレッドを終了する前に他のクライアントのスレッドの”sleep in”を確認すれば、同時並行でクライアントの処理ができたと確認できる。
上記の動作を確認したため、マルチスレッドWebサーバーの作成に成功しました。
- 感想
このプロジェクト演習を通して組み込みの環境のクロス開発やサーバーとクライアントの通信の仕組みなど、現在様々な場所で実際に使われているプログラムの実態を知れたと感じました。
また既存プログラムにprintfなどを実行してどのタイミングでどのようにプログラムが動いているのかを確認したりして、よりプログラムの詳細的な動きに詳しくなったと感じます。
7回の演習で大きくstep upできました。とても大変でしたが、とても身になる演習でした。
ソースコード