ホーム » t-saitoh の投稿

作者アーカイブ: t-saitoh

2024年10月
 12345
6789101112
13141516171819
20212223242526
2728293031  

検索・リンク

CTF問題とセキュリティ(4年実験)

この実験では、セキュリティコンテストのCTF問題(Capture The Flag競技)について、インターネットの仕組みを理解し、その問題の解き方を考え、新しく自分自身でCTF問題を作ってもらいます。

日程

実験は、4週にわたり、以下の日程で行います。

内容
1 (前半)暗号・ファイル・Web
2
3 (後半) プログラム作成・インターネット・OS
4

前半・後半でそれぞれ、問題例(もしくは自分で見つけたCTF問題)の1つの説明と自作のCTF問題1つを新しく作り説明をしてください。最終的に4つの問題の説明のレポートを提出となります。

提出物

  • 実験の目的
  • 問題例(or 自分で見つけたCTF問題)を1つ選び
    • 前半・後半それぞれについて
    • その問題が情報セキュリティにどう関係しているのか
    • 問題の解き方のしくみと解説
  • 自作問題について
    • 前半・後半それぞれ
    • その問題が情報セキュリティにどう関係しているのか
    • 問題の解き方、問題の作り方
    • しくみと解説
  • 提出先はこちらのTeams共有フォルダに。
  • 自作問題の例
    • サブリミナル効果で隠されたGIF
    • 電子透かし
    • 学校からアクセスする時だけ、答えが見える。(REMOTE_HOST)
    • スマホでアクセスした時だけ、答えが見える。(HTTP_USER_AGENT)
    • Google 検索した後だけ、答えが見える。(HTTP_REFERER)

Ethernet LANとWAN接続

前回の物理層のLANの話に引き続き、WANの話を説明。

前回の復習

10BASE5, 10BASE2 では、同軸ケーブルにPCが接続。

ITメディアより引用

10BASE5 トランシーバ

10BASE2 とT型分岐コネクタ

10BASE-T

Ethernet と通信速度

10BASE 5/2/-T といった 10BASE は、通信速度の上限が 10Mbps (bit per second) を意味する。100BASE-T といった 100BASE は、100Mbps を意味する。最近では、1000BASE-T は、1000 Mbps = 1Gbps の通信速度となる。最近では、10G BASE-T といった記載であれば、10Gbps を意味する。

バス接続(LAN)と転送速度

基本的な Ethernet の接続では、1本の通信路を共有するバス型接続のため、1本の信号線をパケット単位の通信の短い時間に区切って、送信を交代しながら行う時分割多重方式で行い通信を行う。パケット(イーサネットフレーム)とは、通信データを送る単位で最大1500byteとなっている。(MTU値:Maximum Transmission Unit)

例えば、10BASE のネットワークでつながった4台のパソコンで、A-B間、C-D間で同時に通信を行おうとすると、A-Bの通信中は、通信路が使用中のため、C-D間の通信はできない。このため、A-B間、C-D間の通信をパケットを送る毎に交代しながら通信路を利用する。これにより、見かけ上は A-B, C-D 間が同時に通信しているようにみえる。

    • 10BASE/5の PC-AとPC-Bの間で、音楽CD1枚のデータ(700MB)をを送る場合、通信時間はどの位かかるか?
      • →答え:

        700M[byte] = 5.6G[bit] なので、10M[bit/sec]で送ると、560[sec]

    • 同じく、A-B間、C-D間で同時に送る場合は、通信時間はどのくらいかかるか?
      • →答え:

        短時間的には同時に通信ができないので、通信路を切り替えながら送るため、倍の時間がかかる。よって、1120[sec]

10BASE/T, 100BASE-T, *BASE-T では、HUBの内部構造に注意が必要。基本的には、見かけ上は木構造のように分配しているように見えるけど、内部はバス型の通信路に変わりはない。10BASE/5/2と異なり、データの送信用,受信用の2つの信号のペアとなっている。10BASE/T を利用している頃は、HUBは高価であり単純なバス型接続のHUB(Dumb HUB)であれば、短時間的にみればC-D間通信中はE-F間通信ができない。(前述のようにパケットに小分けして通信するので見かけ上は並行して通信しているように見える)

しかしこれでは、通信速度が無駄になるので、最近はスイッチングHUBが利用される。このHUBは、通信相手に応じてHUB内部の通信路を切り分けるので、A-B間通信中でも、C-D間通信が可能となる。送り先を区別するためには通信機器ごとに固有値が割り振られているMACアドレスを使う。

理解確認

  • 前述の2つのカスケード接続されたDumb HUBで、A,B,C,D,E,Fのコンピュータが繋がっている時、A-C間、B-D間で音楽CD700MBのデータを送る場合、通信時間はどうなる?

電話線接続

同じ敷地内のネットワーク接続のLANどうしを、ネットワークで相互接続するWAN(Wide Area Network)では、昔は電話線を用いていた。電話は、本来音声を伝えるためのものであるため、0/1のデジタル信号を、音の信号に変換(変調)し、受信側は音をデジタル信号に(復調)する。これらを行う機器は、変復調装置(モデム)と呼ばれる。

変調の際には、0/1信号を、音の強弱(振幅変調/AM),音程の高低(周波数変調/FM),位相の前後(位相変調/PM)の組み合わせによって、送受信を行う。参考:ダイヤルアップ接続音(YouTube)

当初は、300bps程度であったが、最終的には64Kbps 程度の通信速度が得られた。(電話線は元々10kHzの音を送るために開発されていたため、64Kbpsが限界だった)

これらの通信速度の改善のため、電話線にデジタル信号で送る ISDN , 電話線の音の信号の高帯域を使った通信 ADSLなどが用いられた。(ADSLでは高周波帯を使うので、自宅から交換機までの距離が長い時は通信速度が速くできなかったりした)

最近では、光ファイバによる FTTH(Fiber To The Home) が広く普及し、1Gbps を越える通信が可能となっている。このほかには、ケーブルテレビ事業者による回線を利用した HFC(Hybrid Fiber-Coaxial) も普及している。HFCでは幹線部分を光ケーブルで接続し、地域の拠点から家庭までは同軸ケーブルで配線することで、テレビ放送とインターネット接続を実現している。

光ファイバ

光ファイバでは、内側(コア)に屈折率の高い透過材料と、外側に屈折率の低い透過材料でケーブルを使い、屈折率の違う断面で全反射することを利用して光を遠くまで運ぶ。中身がガラス繊維なので、中の繊維が折れない工夫や、コネクタで光が減衰しないような工夫が重要。

光ファイバで自宅までネットワーク回線が引かれている場合、光ファイバと自宅内インターネットの間には、ONU(Optical Network Unit/光回線終端装置)が設置されている。一般的にモデムが音の信号を電気的なデジタル信号に変換するのに対し、ONU は光信号をデジタル信号に変換する。音声電話を使う場合には、音声信号をデジタル化して、これをインターネットで通信する VoIP(Voice over IP network) 技術が使われる。

(引用元)

通信速度の理解と、古い時代の通信速度を体験してもらうため、試しに「2000ドット✕1500ドットのRGB画像(1ドット3byte)のデータ(無圧縮)を、9600bps で通信したら、どの程度の時間を要するか、いくらかかるのか?」を計算してみよう。ちなみに2000年頃は、携帯電話では、1Kbyteあたり10円の通信料がかかった。

→答え:

データ量 2000✕1500✕3✕8 [bit] = 72 M[bit]
通信速度 9600[bps] であれば、72 M / 9600 = 7500[sec] = 約2時間(1/5に圧縮されても24分)
通信費  72M[bit]/8/1000 = 9000[Kbyte]、
通信料金 9000[Kbyte]=9000[パケット]、1パケット(1KB)10円だから90,000円 😥
# 画像が320✕240✕RGB(16bit)で圧縮で1/5であれば、それでも100円超え

J-PHONE(J-SH04,200年発売)で始めてカメラ付き携帯が登場。(解像度の低い自撮り写真をスマホで1枚送れば100円かかった時代)

ネットワークトポロジ

ネットワークに機器を接続する形態をネットワークトポロジと言う。

1本の線を共有するバス型、機器どうしがリング型に接続するリング型、中央の機器を通して接続されるスター型が基本となる。

基本的に、Ethernet は 1本の線を機器で共有するバス型。ただし、10BASE-T,100BASE-TX などの HUB で繋がることから、HUB を中心に広がるスター型とも言える。それぞれれのネットワークは相互につながることから、木の枝状に見えるものはツリー型と呼ばれる。また、上流ネットワークでは、機器が故障した場合に一切の通信ができなくなるのは問題があるため、複数のネットワークで相互に接続される。この場合、網が絡むような構造になることから、ネットワーク型と呼ばれる。

データベースの用語など

データベースの機能

データベースを考える時、利用者の視点で分類すると、以下の3つの視点の違いがある。

  1. データベースの管理者(データベース全体の管理)、
  2. 応用プログラマ(SQLなどを使って目的のアプリケーションに合わせた処理を行う)、
  3. エンドユーザ(データベース処理の専門家でなく、DBシステムのGUIを使ってデータベースを操作する)

データベース管理システム(DBMS)では、データとプログラムを分離してプログラムを書けるように、データ操作言語(SQL)で記述する。

また、データは独立して扱えるようにすることで、データへの物理的なアクセス方法があっても、プログラムの変更が不要となるようにする。

データベースは、利用者から頻繁に不定期にアクセスされる。このため、データの一貫性が重要となる。これらを満たすためには、(a) データの正当性の確認、(b) 同時実行制御(排他制御)、(c) 障害回復の機能が重要となる。

これ以外にも、データベースからデータを高速に扱えるためには、検索キーに応じてインデックスファイルを管理してくれる機能や、データベースをネットワーク越しに使える機能などが求められる。

データベースに対する視点

実体のデータをそれぞれの利用者からデータベースを記述したものはスキーマと呼ばれる。そのスキーマも3つに分けられ、これを3層スキーマアーキテクチャと呼ぶ。

  • 外部スキーマ – エンドユーザからどんなデータに見えるのか (create view の例)
  • 概念スキーマ – 応用プログラマからは、どのような表の組み合わせで見えるのか、表の中身はどのようなものなのか。
  • 内部スキーマ – データベース管理者からみて、表の中身は、どのようなファイル名でどのような形式でどう保存されているのか

データモデル

データを表現するモデルには、いくつかのモデルがある。

関係データベースの基礎

関係データベースは、1970年頃に、E.F.コッド博士によりデータベースのための数学的な理論が確立された。

1974 – IBM SEQUEL言語開発, Ingres初期型
1977 – ラリー・エリソンらが Oracle の前進となった SDL 社を創業, 1982に Oracle に改称

  • 集合 A, B – 様々なデータ
  • 直積 AB = { (x,y| xA , yB } 集合A,Bのすべての組み合わせ
  • 関係 R(A,B) すべての組み合わせのうち、関係があるもの。直積A,Bの部分集合

例えば、A={ s,t,u } , B={ p,q } (定義域) なら、

AB = { (s,p) , (s,q) , (t,p) , (t,q) , (u,p) , (u,q) }

このうち、Aが名前(sさん,tさん,uさん)、Bが性別(p=男性,q=女性)を表すなら、

R(A,B) = { (s,p) , (t,q) , (u,p) } (例)
(例):(sさん,男性) , (tさん,女性) , (uさん,男性)

前の例を使うなら、集合<学生>, 集合<科目> であり、直積 <学生> ✕ <科目> のうち、実際に受講したという結果が、関係 R( <学生> , <科目> ) に相当する。

SQLの導入

コッドが提唱した関係データベースの理論に基づいて作った Alpha 言語を元に、IBM が SEQUEL を開発したが、商標の問題で SQL と名前が変更された。同じころにコッドらの論文を元に、ラリー・エリソンらにより Oracle が開発されている。

SQLは、データベース管理システム(RDBMS)において、データの操作や定義を行うためのデータベース言語問い合わせ言語)である。プログラミングにおいてデータベースへのアクセスのために、他のプログラミング言語と併用される。COBOL の影響が大きく英語の文章のような文法となっている。

SQLの機能は、以下の3つに大きく分けられている。

  • データ定義言語(Data Definition Language)
    • CREATE , DROP , ALTER
  • データ操作言語(Data Manipulation Language)
    • INSERT INTO , UPDATE…SET , DELETE FROM , SELECT…FROM…WHERE
  • データ制御言語(Data Control Language)
    • GRANT , REVOKE , COMMIT , ROLLBACK

今回の授業では、Paiza.IO の MySQL 環境を使って演習を行う。

理解確認

  • データベースにおける3層スキーマアーキテクチャについて説明せよ
  • 集合A,Bが与えられた時、関係R(A,B) はどのようなものか、数学定義や実例をあげて説明せよ。

双方向リストとdeque

deque(両端キュー)

双方向循環リストを使うと、(1)先頭にデータを挿入(addFirst/unshift)、(2)先頭のデータを取り出す(removeFirst/shift)、(3)末尾にデータを追加(addLast/push)、(4)末尾のデータを取り出す(removeLast/pop)、といった処理が簡単に記述できる。この4つの処理を使うと、単純リスト構造で説明した、待ち行列(queue)やスタック(stack) が実現できる。この特徴を持つデータ構造は、先頭・末尾の両端を持つ待ち行列ということで、deque (double ended queue) とも呼ばれる。

先頭への挿入/削除

末尾への挿入削除

import java.util.*;

class BDListNode {
    BDListNode prev ;
    int        data ;
    BDListNode next ;
    
    BDListNode( BDListNode p , int d , BDListNode n ) {
        this.prev = p ;
        this.data = d ;
        this.next = n ;
    }
    BDListNode() {
        this.prev = this ;
        this.data = -1 ; // dummy
        this.next = this ;
    }
}

public class Main {
    static void addFirst( BDListNode p , int d ) {
        p.next = new BDListNode( p , d , p.next ) ;
        p.next.next.prev = p.next ;
    }
    static int removeFirst( BDListNode p ) {
        int ans = p.next.data ;
        p.next = p.next.next ;
        p.next.prev = p ;
        return ans ;
    }
    static void addLast( BDListNode p , int d ) {
        p.prev = new BDListNode( p.prev , d , p ) ;
        p.prev.prev.next = p.prev ;
    }
    static int removeLast( BDListNode p ) {
        int ans = p.prev.data ;
        p.prev = p.prev.prev ;
        p.prev.next = p ;
        return ans ;
    }
    public static void main(String[] args) throws Exception {
        BDListNode top = new BDListNode() ;
        // 先頭で Stack
        addFirst( top , 11 ) ;
        addFirst( top , 22 ) ;
        System.out.println( removeFirst( top ) ) ;
        System.out.println( removeFirst( top ) ) ;
        // 末尾で Stack
        addLast( top , 33 ) ;
        addLast( top , 44 ) ;
        System.out.println( removeLast( top ) ) ;
        System.out.println( removeLast( top ) ) ;
        // Queue として使う
        addFirst( top , 55 ) ;
        addFirst( top , 66 ) ;
        System.out.println( removeLast( top ) ) ;
        System.out.println( removeLast( top ) ) ;
    }
}

Javaでの LinkedList(Deque) のクラスの使い方

Javaで Deque のような双方向リスト(2重リスト)を使うには、LinkedList<E> を用いる。クラス宣言などで <E> の内側に型Eを指定する機能はジェネリクスと呼ばれる。クラス名に Deque というのもあるけど、LinkedList などの内部の処理を記述するために使われているものなので、ユーザが直接 Deque クラスを使うことはない。

LinkedList でデータ構造を宣言する場合には、LinkedList<E> のように、どのテータ構造を要素にもつ LinkedList なのかを指定する。ただし int,double といったプリミティブ型を型の欄に書くことはできない。こういった場合には Integer,Double といったオブジェクトを記載すること。

また、リストの要素で繰り返しをする場合には、for( 型 item : LinkedList型 ) {…} のように書けば、繰り返しが記述できる。

import java.util.*;

public class Main {
    public static void main(String[] args) throws Exception {
        LinkedList<Integer> lst = new LinkedList<Integer>() ;
        lst.addFirst( 11 ) ;  // lst の先頭に11を挿入
        lst.addFirst( 22 ) ;  // lst の先頭に22を挿入
        for( Integer item : lst ) {
            System.out.println( item ) ;
        }
        lst.addLast( 33 ) ;   // lst の末尾に33を追加
        // 全要素の繰り返し
        for( Integer item : lst ) {
            System.out.println( item ) ;
        }
        // 先頭を取り出す
        while( !lst.isEmpty() ) { // isEmpty() : lst の要素が空か判定する
            System.out.println( lst.removeFirst() ) ; // lstの先頭要素を取り出す
        }
    }
}

LinkedList クラスは双方向リストだけど、単純リスト専用のクラスは無い。このため、これまでの授業のように自分でクラスを宣言して使う必要がある。

ArrayList クラス

これと同じように自由な配列サイズのデータクラスとして、ArrayListクラスも存在する。以下の例は、ArrayList<Integer> の使用例。

ArrayList はジェネリクスを使った、要素数を増やすことができる配列である。

import java.util.*;

public class Main {
    public static void main(String[] args) throws Exception {
        ArrayList<Integer> lst = new ArrayList<Integer>() ;
        lst.add( 11 ) ;
        lst.add( 22 ) ;
        for( Integer item : lst ) {
            System.out.println( item ) ;
        }
        lst.add( 33 ) ;
        for( Integer item : lst ) {
            System.out.println( item ) ;
        }
        for( int x = 0 ; x < lst.size() ; x++ ) {
            System.out.println( lst.get( x ) ) ;
        }
    }
}

型推論

上記のプログラムで、LinkedList<Integer> lst = new LinkedList<Integer&gt() ; で宣言しているが、初期化の右辺と左辺で型を揃える必要があるが、複雑な型だとプログラムが煩雑になる。このため、最近の Java には型推論の機能があるため、下の様に型を省略して記述できる。

LinkedList<Integer> lst = new LinkedList<Integer>() ; // 型推論なし
LinkedList<Integer> lst = new LinkedList<>() ;        // 後半のIntegerは明らか
var lst = new LinkedList<Integer>() ; // lst の型は new LinkedList<Integer> で明らか

for( Integer item : lst ) { ... } // 型推論なし
for( var item : lst ) { ... }     // 型推論でIntegerを省略

LinkedListとArrayListの違い

LinkedList や ArrayList は同じ使い方ができるようにadd(int,E),get(int)クラスメソッド等が定義されている。しかし、LinkedList は双方向リスト、ArrayList は配列を使って実装されているので、同じ名前のメソッドでもそのメソッドの処理時間には、以下のような特徴がある。

処理時間のオーダ LinkedList ArrayList メソッドの機能
addFirst(E e)
/
add(E e)
O(1) O(1) リストの末尾に要素を追加
add(int index, E e) 指定した場所探しにO(N)
その場所に挿入O(1)
指定した場所探しにO(1)
その場所に挿入O(N)
リストの指定したインデックスに要素を追加
addFirst(E e) / add(0, E e) 先頭に挿入O(1) 先頭に挿入O(N) リストの先頭に要素を追加
E get(int index) O(N)  O(1) リストのインデックス番目を参照

理解確認


ランダムアクセス・シーケンシャルアクセスから双方向リスト

ランダムアクセスO(1)とシーケンシャルアクセスO(N)の説明を踏まえ、リスト構造のO(N)の改善にむけた解説を行う。

リスト構造の利点と欠点

リストを使った集合演算のように、データを連ねたリストは、単純リストとか線形リストと呼ばれる。特徴はデータ数に応じてメモリを確保する点や、途中へのデータの挿入削除が得意な点があげられる。一方で、配列は想定最大データ件数で宣言してしまうと、実際のデータ数が少ない場合、メモリの無駄も発生する。しかし、想定件数と実データ件数がそれなりに一致していれば、無駄も必要最小限となる。リスト構造では、次のデータへのポインタを必要とすることから、常にポインタ分のメモリは、データにのみ注目すれば無駄となる。

例えば、整数型のデータを最大 MAX 件保存したいけど、実際は それ以下の、平均 N 件扱うとする。この時のメモリの使用量 M は、以下のようになるであろう。(sizeof()はC言語での指定した型のメモリByte数を返す演算子)

配列の場合 リスト構造の場合

(ただしヒープ管理用メモリ使用量は無視)

シーケンシャルアクセス・ランダムアクセス

もう1つのリストの欠点はシーケンシャルアクセス。テープ上に記録された情報を読む場合、後ろのデータを読むには途中データを読み飛ばす必要があり、データ件数に比例したアクセス時間を要する。このような N番目 データ参照に、O(N)の時間を要するものは、シーケンシャルアクセスと呼ばれる。

一方、配列はどの場所であれ、一定時間でデータの参照が可能であり、これは ランダムアクセスと呼ばれる。N番目のアクセス時間がO(1)を要する。配列であれば、N/2 番目のデータをO(1)で簡単に取り出せるから2分探索法が有効だが、リスト構造であれば、N/2番目のデータを取り出すのにO(N)かかってしまう。

このため、プログラム・エディタの文字データの管理などに単純リストを用いた場合、1つ前の行に移動するには、先頭から編集行までの移動で O(N) の時間がかかり、大量の行数の編集では、使いものにならない。ここで、シーケンシャルアクセスでも1つ前にもどるだけでも処理時間を改善してみよう。

単純リストから双方向リストへ

ここまで説明してきた単純リストは、次のデータへのポインタを持つ。ここで、1つ後ろのデータ(N番目からN+1番目)をアクセスするのは簡単だけど、1つ前のデータ(N-1番目)を参照しようと思ったら、先頭から(N-1)番目を辿るしかない。でも、これは O(N) の処理であり時間がかかる処理。
ではどうすればよいのか?

この場合、一つ前のデータの場所を覚えているポインタがあれば良い。

Javaの場合

import java.util.*;

class BDListNode {
    BDListNode prev ;
    int        data ;
    BDListNode next ;
    
    BDListNode( BDListNode p , int d , BDListNode n ) {
        this.prev = p ;
        this.data = d ;
        this.next = n ;
    }
}

public class Main {
    public static void main(String[] args) throws Exception {
        BDListNode top
            = new BDListNode( null , 1 ,
                 new BDListNode( null , 2 ,
                    new BDListNode( null , 3 , null ) ) ) ;
        top.next.prev = top ;
        top.next.next.prev = top.next ;
        for( BDListNode p = top ; p != null ; p = p.next )
            System.out.println( p.data ) ; // 1,2,3
        for( BDListNode p = top.next.next ; p != null ; p = p.prev )
            System.out.println( p.data ) ; // 3,2,1
    }
}

C言語の場合

// 双方向リストの宣言
struct BD_List {
    struct BD_List* prev ; // 1つ前のデータへのポインタ
    int             data ;
    struct BD_List* next ; // 次のデータへのポインタ
} ;

このデータ構造は、双方向リスト(bi-directional list)と呼ばれる。では、簡単なプログラムを書いてみよう。双方向リストのデータを簡単に生成するための補助関数から書いてみる。

// リスト生成補助関数
struct BD_List* bd_cons( struct BD_List* p ,
                         int d ,
                         struct BD_List* n ) {
    struct BD_List* ans ;
    ans = (struct BD_List*)malloc(
                         sizeof( struct BD_List ) ) ;
    if ( ans != NULL ) {
        ans->prev = p ;
        ans->data = d ;
        ans->next = n ;
    }
    return ans ;
}
void main() {
    struct BD_List* top ;
    struct BD_List* p ;

    // 順方向のポインタでリストを生成
    top = bd_cons( NULL , 1 ,
          bd_cons( NULL , 2 ,
          bd_cons( NULL , 3 , NULL ) ) ) ;
    // 逆方向のポインタを埋める
    top->next->prev = top ;
    top->next->next->prev = top->next ;

    // リストを辿る処理
    for( p = top ; p->next != NULL ; p = p->next )
        printf( "%d\n" , p->data ) ;
    for(         ; p->prev != NULL ; p = p->prev )
        printf( "%d\n" , p->data ) ;
}

双方向リストの関数作成

以上の説明で、双方向の基礎的なプログラムの意味が分かった所で、練習問題。

先のプログラムでは、1,2,3 を要素とするリストを、ナマで記述していた。実際には、どんなデータがくるか分からないし、指定したポインタ p の後ろに、データを1件挿入する処理 bd_insert( p , 値 ) , また、p の後ろのデータを消す処理 bd_delete( p ) を書いてみよう。

Javaの場合

public class Main {
    // 指定したノードの後ろに1件追加
    static void bd_insert( BDListNode p , int d ) {
        p.next = new BDListNode( null , d , p.next ) ;
        p.next.next.prev = p.next ;
        p.next.prev = p ;
    }
    // 指定したノードの後ろを1件削除
    static void bd_delete( BDListNode p ) {
        p.next = p.next.next ;
        p.next.prev = p ;
    }
    public static void main(String[] args) throws Exception {
        // 双方向リストの追加,削除            
        BDListNode top2
            = new BDListNode( null , 1 ,
                 new BDListNode( null , 2 ,
                    new BDListNode( null , 4 , null ) ) ) ;
        top2.next.prev = top2 ;
        top2.next.next.prev = top2.next ;
        
        // 途中に挿入の実験
        bd_insert( top2.next , 3 ) ;
        for( BDListNode p = top2 ; p != null ; p = p.next )
            System.out.println( p.data ) ; // 1,2,3,4
        for( BDListNode p = top2.next.next.next ; p != null ; p = p.prev )
            System.out.println( p.data ) ; // 4,3,2,1
        
        // 途中を削除の実験
        bd_delete( top2.next ) ;
        for( BDListNode p = top2 ; p != null ; p = p.next )
            System.out.println( p.data ) ; // 1,2,4
        for( BDListNode p = top2.next.next ; p != null ; p = p.prev )
            System.out.println( p.data ) ; // 4,2,1
    }
}

C言語の場合

// 双方向リストの指定場所 p の後ろに、値 d を要素とするデータを挿入せよ。
void bd_insert( struct BD_List* p , int d ) {
   struct BD_List*n = bd_cons( p , d , p->next ) ;
   if ( n != NULL ) {
      p->next->prev = n ;
      p->next = n ;
   }
}

// 双方向リストの指定場所 p の後ろのデータを消す処理は?
void bd_delete( struct BD_List* p ) {
   struct BD_List* d = p->next ;
   d->next->prev = p ;
   p->next = d->next ;
   free( d ) ;
}

// この手のリスト処理のプログラムでは、命令の順序が重要となる。
// コツとしては、修正したい箇所の遠くの部分を操作する処理から
// 書いていくと間違いが少ない。

番兵と双方向循環リスト

前述の bd_insert() だが、データの先頭にデータを挿入したい場合は、どう呼び出せば良いだろうか?
bd_insert() で、末尾にデータを挿入する処理は、正しく動くだろうか?

同じく、bd_delete() だが、データの先頭のデータを消したい場合は、どう呼び出せば良いだろうか?
また、データを消す場合、最後の1件のデータが消えて、データが0件になる場合、bd_delete() は正しく動くだろうか?

こういった問題が発生した場合、データが先頭・末尾で思ったように動かない時、0件になる場合に動かない時、特別処理でプログラムを書くことは、プログラムを読みづらくしてしまう。そこで、一般的には 循環リストの時にも紹介したが、番兵(Sentinel) を置くことが多い。

しかし、先頭用の番兵、末尾用の番兵を2つ用意するぐらいなら、循環リストにした方が便利となる。このような双方向リストでの循環した構造は、双方向循環リスト(bi-directional ring list)と呼ばれる。

情報ネットワーク基礎・ガイダンス

情報ネットワーク基礎では、インターネットがどのような仕組みなのか、どのようにして動いているのかを説明する。TCP/IPって何? IPアドレスって何? セキュリティって何?

あなたが使っているネットワーク機能は?

まずは、Teams にて「あなたが使っているネットワーク機能は?」を返信にて書き込んでください。
ただしネットワークを使うことでコンピュータがどう動いているかの視点で答えてほしい。

共有:ネットワークプリンタ、ファイル共有… – サービスを利用する視点
(ハードウェアや情報を共有)

分散:大量のコンピュータで負荷分散リスク分散… – サービスを提供する視点
(仕事を分散し全体で高速化, 沢山のコンピュータの1台が壊れても全体は動く)

ネットワークの歴史

昔のコンピュータは、開発にお金がかかるため1台のコンピュータを全員で使うもの(TSS: Time Sharing System/時分割システム)だった。冷戦の時代、軍の重要な処理を行うコンピュータでは、コンピュータのある所に核攻撃を加えられ、軍の機能がすべて動かなくなることは問題だった。1970年頃にアメリカ国防総省ARPANETがインターネットの原型(TCP/IP)を作る。

1980年代には、パソコンが同じ組織内でネットワークで繋がるようになるLAN(Local Area Network)が使われるようになる。1990年代には、LANどうしを遠隔地接続をするWAN(Wide Area Network)が発達し、Internet(広域コンピュータネットワーク)という言葉が広く普及していった。欧州原子核研究機構(CERN)で、ティム・バーナーズ=リーWorld Wide Web/httpを開発(1989)。1995年、マイクロソフトの家庭用パソコンのOS Windows95の普及と共にWWWが普及する。

  • 1980年代:パソコン通信
  • 1997年:weblog(blog:自分で作るwebページの拡大)
  • 1998年:Google検索
  • 1999年:2ch
  • 2003年:SNSの誕生(2004:mixi)
  • 2006年:Twitter,Facebook(一般開放)

コンピュータインタフェースとネットワーク(物理層)

ネットワークにおける情報伝達において、伝送媒体(電気信号,光)にて0/1を伝えるための取り決めは、物理層という。まずは、コンピュータと機器の接続について考えると、シリアル通信パラレル通信に分類できる。(シリアル通信は時間を細かく区切って複数の信号を送ることから時分割多重通信と呼ぶこともある)

通信の高速化に伴い、伝送の配線はコンデンサやインダクタンスを考慮したインピーダンスマッチングが重要となる。このため、高速通信のインタフェース両端は終端抵抗(ターミネータ)が必要だった。

1本の信号線で単位時間あたりのデータ通信速度が同じであれば、パラレル通信の方が高速であるが、長い通信路ではノイズ対策が重要でありノイズ対策をきちんとした線が複数本あるとケーブルが太くなることから、長い通信路ではシリアル通信が使われる。少ない信号線に対してノイズ対策をきちんと施すことができるので、長い通信路ではシリアル通信の方が高速となる。

パラレル通信の例:パラレルポート(プリンタ用)IEEE 1284、ハードディスクATA(IDE)、計測器GP-IB

シリアル通信の例:RS-232C、IEEE1394(FireWire)、ハードディスク(SATA)USB1.1, USB2.0, USB3.0, USB3.1 Gen2, USB3.2 Gen2x2…、有線LAN/Ethernet

有線LAN/Ethernetの種別

  • 半二重通信 – 送信/受信を1本の信号線でおこなう。
  • 全二重通信 – 送信用の信号線、受信用の信号線がそれぞれ別。送信受信を同時にできる。
    • 複信 Simplex(一方的な放送), Half Duplex(半二重), Full Duplex(全二重)
  • 10BASE/* – 10Mbit/sec
    • 10BASE/5 – ケーブルに針を刺して増設 – 半二重通信/ターミネータが必要
    • 10BASE/2T型BNCケーブルで延長 – 半二重通信/ターミネータが必要
    • 10BASE/T – HUBで分配(終端抵抗などの問題はHUBが解決してくれる) – 全二重通信
  • 100BASE-T – 100Mbit/sec / CAT5
    • 信号線のノイズ対策は、シールドで覆う、信号線を“より線”(ツイストペア)にするなどの対策が重要
      • シールドや”より線”の方式でカテゴリー CAT5,CAT6,CAT7 などで分類される
  • 1000BASE-T ギガビット – 1000Mbit/sec = 1Gbit/sec / CAT6
  • 10000BASE , 10GBase – 10Gbit/sec / CAT7

同軸ケーブル

ツイストペアケーブル

ツイストペアケーブルがノイズに強い理由

理解確認

  • ネットワークにおける共有と分散について例をあげて説明せよ。
  • TSSのような通信によるコンピュータと、TCP/IPによる通信網を比べ何がどう良いのか?
  • シリアル通信とパラレル通信、それぞれの利点欠点は?
  • 10BASE/5,10BASE/2,10BASE/Tのそれぞれの問題点は?
  • CD1枚のデータを1000BASE-Tのネットワークで転送するのに何秒かかる?
    • サンプリングレート44.1kHz,16bit,ステレオ2ch,74分

データベースガイダンス2024

インターネットの情報量

インターネット上の情報量の話として、2010年度に281EB(エクサバイト)=281✕1018B(参考:kMGTPEZY)で、2013年度で、1.2 ZB(ゼタバイト)=1.2✕1021B という情報があった。ムーアの法則の「2年で2倍」の概算にも、それなりに近い。 では、今年2024年であれば、どのくらいであろうか?

しかし、これらの情報をGoogleなどで探す場合、すぐにそれなりに情報を みつけてくれる。これらは、どの様に実装されているのか?

Webシステムとデータベース

まず、指定したキーワードの情報を見つけてくれるものとして、 検索システムがあるが、このデータベースはどのようにできているのか?

Web創成期の頃であれば、Yahooがディレクトリ型の検索システムを構築してくれている。(ページ作者がキーワードとURLを登録する方式) しかし、ディレクトリ型では、自分が考えたキーワードではページが 見つからないことが多い。

そこで、GoogleはWebロボット(クローラー)による検索システムを構築した。 Webロボットは、定期的に登録されているURLをアクセスし、 そのページ内の単語を分割しURLと共にデータベースに追加する。 さらに、ページ内にURLが含まれていると、そのURLの先で、 同様の処理を再帰的に繰り返す。

これにより、巨大なデータベースが構築されているが、これを普通のコンピュータで実現すると、処理速度が足りず、3秒ルール or 5秒ルール (Web利用者は次のページ表示が3秒を越えると、次に閲覧してくれない)を実現するための能力が不足してしまう。だからこそ、これらを処理するには負荷分散が重要となる。

Webシステムの負荷分散

一般的に、Webシステムを構築する場合には、 1段:Webサーバ、2段:動的ページ言語、3段:データベースとなる場合も 多い。この場合、OS=Linux,Web=Apache,DB=MySQL,動的ページ生成言語=PHPの組合せによる、 LAMP構成とする場合も多い。

                            OS = Linux
               [ Webサーバ   動的Web言語  データベース ]
   User - - - - - Apache ----- PHP ----- MySQL

一方で、大量のデータを処理するDBでは、フロントエンド,セカンダリDB(スレーブDB),プライマリDB(マスタDB)のWebシステムの3段スキーマ構成となることも多い。
フロントエンドは、大量のWebユーザからの問合せを受ける部分であり、必要に応じてセカンダリDBに問合せを行う。
大量のユーザからの問合せを1台のデータベースシステムで捌くには処理の負荷が高い場合、複数のデータベースで負荷分散を行う。プライマリDBは、複数のデータベースシステムの原本となるべきデータを保存される。負荷分散の為に分散されたセカンダリDBは、プライマリDBと内容の同期をとりながらフロントエンドからの問合せに応答する。

データベースシステム

データベースには、ファイル内のデータを扱うためのライブラリの BerkleyDB といった場合もあるが、複雑なデータの問い合わせを実現する 場合には、リレーショナル・データベース(RDB)を用いる。 RDBでは、データをすべて表形式であらわし、SQLというデータベース 問い合わせ言語でデータを扱う。 また、問い合わせは、ネットワーク越しに実現可能であり、こういった RDBで有名なものとして、Oracle , MySQL , PostgreSQL などがある。 単一コンピュータ内でのデータベースには、SQLite などがある。

リレーショナルデータベースの串刺し

商品名 単価 個数 価格
りんご 200 2 400
みかん 50 6 300
アイスクリーム 125 1 125
みかん 50 3 150

このような表データでは、たとえば「みかん」の単価が変更になると、2行目,4行目を変更しなければいけなくなる。巨大な表の場合、これらの変更は大変。

そこで、この表を2つに分類する。

単価表
商品ID 商品名 単価
1010 りんご 125
1011 みかん 50
2101 アイスクリーム 125
販売表
商品ID 個数
1010 2
1011 6
2101 1
1011 3
必要に応じて、2つの表から、以下のような SQL の命令で、データを抽出する。

select 単価表.商品名, 単価表.単価, 販売表.個数, 単価表.単価*販売表.個数
    from 単価表, 販売表 ;

 

データベースに求められるのACID特性

データベースシステムと呼ばれるには、ACID特性が重要となる。(次に述べるデータベースが無かったら…を参照)

  • A: 原子性 (Atomicity) – 処理はすべて実行するか / しない のどちらか。
  • C: 一貫性 (Consistency) – 整合性とも呼ばれ、与えられたデータのルールを常に満たすこと。
  • I: 独立性 (Isolation) – 処理順序が違っても結果が変わらない。それぞれの処理が独立している。
  • D: 永続性 (Durability) – データが失われることがない(故障でデータが無くならないとか)

しかし、RDBでは複雑なデータの問い合わせはできるが、 大量のデータ処理のシステムでは、フロントエンド,セカンダリDB,プライマリDB の同期が問題となる。この複雑さへの対応として、最近は NoSQL(RDB以外のDB) が 注目されている。(例: Google の BigTable)

データベースが無かったら

これらのデータベースが無かったら、どのようなプログラムを作る 必要があるのか?

情報構造論ではC言語でデータベースっぽいことをしていたが、 大量のデータを永続的に扱うのであれば、ファイルへのデータの読み書き 修正ができるプログラムが必要となる。

こういったデータをファイルで扱う場合には、1件のデータ長が途中で 変化すると、N番目のデータは何処?といった現象が発生する。 このため、簡単なデータベースを自力で書くには、1件あたりのデータ量を 固定し、lseek() , fwrite() , fread() などの 関数でランダムアクセスのプログラムを書く必要がある。

また、データの読み書きが複数同時発生する場合には、排他処理(独立性)も 重要となる。例えば、銀行での預け金10万の時、3万入金と、2万引落としが 同時に発生したらどうなるか? 最悪なケースでは、 (1)入金処理で、残金10万を読み出し、 (2)引落し処理で、残金10万を読み出し、 (3)入金処理で10万に+3万で、13万円を書き込み、 (4)引落し処理で、残金10万-2万で、8万円を書き込み。 で、本来なら11万になるべき結果が、8万になるかもしれない。

さらに、コンピュータといってもハードディスクの故障などは発生する。 障害が発生してもデータの原子性永続性を保つためには、バックアップや 障害対応が重要となる。

iOS18, macOS Sequoia 更新でWiFi注意

iOS18, iPadOS18, macOS Sequoia などが9/20に公開されインストールした人も多いとは思いますが、学内のWiFi fnct-student などに接続する際には、MACアドレス認証機能を使っているので、固定したMACアドレスの必要があります。しかし、iOS18, iPadOS18, macOS Sequoia をインストールした際にセキュリティ対策にて「プライベート WiFi アドレス」のオフの設定が外されるようです。

Apple系端末で 学内の WiFi に繋がらないというトラブルの際には、下記のように「プライベート WiFi アドレス」= オフに改めて設定をする必要があります。

IchogoJamのロボット制作のメモ

2024年9月15日(日) 09:30~11:30

プログラム自動起動

IchigoJam で自走ロボットを作ると、モニターやキーボードをつけて動かすのは困難。このため、IchogoJam を起動したらすぐにプログラムを起動したい。

この場合は、プログラムを “SAVE 0” で保存しておき、IchogoJam を起動させるときに BTN() 機能で使う基板上のボタンを押しながら起動する。これにより起動時に “LOAD 0” を実行してくれる。

プログラムの切り替え

かにロボコンでは、スタート地点からボールの回収フィールドまでライントレースで移動し、回収の動作をして、再びライントレースでスタート場所に戻る必要がある。この際、ライントレース動作と回収動作は異なる動きとなる。

また、右コースか左コースかの違いによってプログラムを変化させたいかもしれない。こういう場合は、“LRUN” 機能を使う。

例えば、ライントレースの処理を “SAVE 0” で保存しておき、回収フィールドの処理を “SAVE 1″ で保存してあるのであれば、ライントレースの処理の中で「回収フィールドに到達した」と判断した時に、”LRUN 1” を実行すれば “LOAD 1″を実行してプログラムを起動できる。

IchigoJamと MableSylup への電源

IchigoJam を MapleSylup に接続してロボットとして動かす場合には、ジャンパーピン”J1″に注意が必要。

通常 IchigoJam と MapleSylup でロボットを使う場合、ジャンパーピン”J1″をショートさせて、MapleSylup に接続した乾電池などの電源を IchigoJam に供給して動かす。しかし、電流をたくさん使うようなモータ制御をする場合、乾電池だけでロボットを動かすと電流を モータに使われ、IchigoJam が誤動作する場合がある。

こういう場合には、IchigoJam には USB のモバイルバッテリーなどを搭載させ、IchigoJam はモバイルバッテリー、MapleSylup とモーターは乾電池で動かす。この場合には、ジャンパーピン”J1″ は抜いて動かす方がよい。

中間発表会の資料作成

パンチカード発掘

部屋の古い本を片付けたら、こんなの挟んであった。
{CAPTION}

システム

最新の投稿(電子情報)

アーカイブ

カテゴリー