AUTHOR: schwarz1009
TITLE: ネットワークの基本
BASENAME: 2021/01/27/064537
STATUS: Publish
ALLOW COMMENTS: 1
CONVERT BREAKS: 0
DATE: 01/27/2021 06:45:37
CATEGORY: ネットワーク
CATEGORY: Linux
CATEGORY: おすすめ
ネットワークにおいては、パケットと呼ばれる単位でデータ通信を行う。
パケットにはIPアドレスという宛て先が記述されており、
ルータと呼ばれる「どの機器にパケットを送れば
目的の機器に近づくことができるか(経路情報)を
知っている機器」にパケットを送り、
バケツリレー方式でパケットを送り続けることで、
インターネットにおけるネットワーク通信は行われる。
ルータは、周辺の経路情報を芋づる式にひとつの代表ルータに集め、
すべてのルータとの間で経路情報を共有することで、
どのルータに送れば目的の場所にたどり着けるかを知っている。
LANは家庭内のネットワークであり、
ネットワークとネットワークが家庭内のブロードバンドルータや
ISPやインターネット上のルータによって繋がったものが、
インターネットである。
イーサネットは、もっとも普及しているLANの規格。
イーサネットにおいては、MACアドレスとIPアドレスによって通信を行う。
MACアドレスは、ネットワーク機器の識別番号であり、
リンクバイリンクで、各機種の間で変わる。
IPアドレスは、パケットの送受信の宛て先情報であり、
エンドツーエンドで、最初から最後まで変わらない。
MACアドレスとIPアドレスを変換するには、
ARPというプロトコルを用いる。
ARPにおいては、ブロードキャストパケットで全ての機器に、
目的のIPアドレスを持っている機器(MACアドレス)を確認し、
ユニキャストアドレスで応答する。
ブロードキャストアドレスとは、1対多の通信で、
ネットワーク上のすべてのホストに対する通信のこと。
ユニキャストアドレスは、1対1の通信のこと。
実際、IPアドレスは無限ではないため、
ネットワーク部とホスト部に分かれており、
ネットワーク部はインターネット上の一意のアドレスだが、
ホスト部は家庭内で自由につけることができる。
IPアドレスをビットにした時に、
ネットワーク部を1とし、ホスト部を0としたものを
サブネットマスクと言い、
たとえば255.255.255.0となる。
サブネットマスクにより、ネットワーク部とホスト部を識別できる。
また、インターネットにおける一意のアドレスをグローバルアドレスと言い、
家庭内で自由につけられるアドレスのことをプライベートアドレスと言う。
この変換を行うシステムをNATと呼ぶ。
また、IPアドレスと同時に使われるのがポート番号であり、
どのアプリケーションに対して送受信を行うかを数値で指定し、
たとえばHTTPであれば80番となる。
ポートはファイアーウォールによって通常は閉じられており、
不正な通信を遮断しているが、
あえてポートを開けることによって、
HTTPサーバーなどを外部に公開することができる。
NATとファイアーウォールは、Linuxであればiptablesのようなシステムが行う。
また、IPアドレスは機械にとっては識別しやすいが、
人間にとっては理解し辛い。
このため、人間のためにドメインとホスト名によって、
名前付けを行う仕組みをDNSと呼ぶ。
DNSで名前を解決することを「名前解決」と呼ぶ。
実際はDNS以外にも、ネットワーク上の名前をホスト名の羅列によって解決したり、
NISなどによって設定することもあり、
これらすべての解決をするシステムのことを「リゾルバ」と呼ぶ。
プロトコルとは、ネットワーク上のやり取りを行う上で、
必要な「取り決め」のことであり、
通常は「通信します、いいですか」
「いいですよ」「ではデータを送ります」といったような
3ウェイハンドシェイクといったような取り決めが決められている。
プロトコルはOSI参照モデルという7階層のレイヤー分けがされており、
上から下へ階層を下がる時にヘッダと呼ばれる通信や接続のための情報を付加し、
通信を物理的に行った上で、ヘッダを除去して下から上へと上がる、
リファレンスアーキテクチャを採用している。
こうすることで、別の階層に影響を与えることなく、
目的の階層だけに処理を分割できる。
IPアドレスには経路情報をたどっていく機能があるが、
これに信頼性とデータのセグメント分割を与えるのがTCPというプロトコル。
TCPには、データの再送制御や、ふくそう制御など、
信頼性を確保する多くの機能がある。
これに対して、信頼性を犠牲にしても、効率やリアルタイム性を取るのがUDP。
通常のネットワーク通信はTCP/IPによって行うが、
動画や音声など、信頼性よりもリアルタイム性が必要な場合はUDPを使う。
また、さらに上のプロトコルには、HTTP, FTP, SMTP, POP, IMAP, NTPなどがあり、
それぞれよく知られたポート番号(ウェルノウンポート番号)を用いる。
ネットワーク機器においては
スイッチとルータがある。
スイッチは、ネットワークの中で、各機器において通信を行う。
ルータは、ネットワークとネットワークを繋げる。
デフォルトゲートウェイは、ネットワークの外部からの案内役であり、
デフォルトゲートウェイのアドレスを指定する時は、
通常はルータのアドレスを指定する。
(放送大学「情報学へのとびら ('16)」、おうちで学べるネットワークのきほん、徹底攻略 応用情報技術者教科書 平成30年度を参考に執筆しました。)
また、このようなTCP/IPの仕組みは、
便利だがソフトウェアの開発においては複雑である。
よって、OSがソケットと呼ばれる仕組みで簡素化を行う。
ソケットは、BSD UNIXで最初に採用されたTCP/IPスタックであり、
二つのソケットが繋がると有効になり、
繋がったソケット同士では、片方からwrite()すればもう片方からread()できる。
BSDではソケットをファイルとして実現し、
ファイルをシステムコールでやり取りする際の情報である、
ファイルディスクリプタによって操作できるようにしたため、
ファイルの読み書きと同様にソケットの読み書きができる。
ソケットを使うことで、
カーネルだけがネットワークの詳細と接続情報の管理を行えばよい。
ソケットは通常サーバー・クライアントで接続を行い、
ユーザーはソケットをサーバー側で待ち受け、
クライアント側で接続を要求するだけでよい。
UNIXでは、これは
socket(), bind(), listen(), accept(), connect()の各APIで行われる。
カーネルの内部では、
たとえばLinuxではsk_buff型のポインタを使っており、
sk_buff型のポインタを各階層に順々に渡していくことで処理が行われている。
カーネルは、確実にパケットを目的の機器に送らなければならないが、
このためにはルータのアドレスさえ知っておけばよい。
LinuxにおいてはBSDソケット層とINETソケット層で、
複雑な接続情報の管理を行っている。
(ふつうのLinuxプログラミング Linuxの仕組みから学べるgccプログラミングの王道と詳解 Linuxカーネル 第3版を参考にしました。)
Linuxでは、traceroute, route, netstat, ifconfig, arp, nslookupなどのコマンドで、
ネットワーク関連の操作を行うが、
これらのコマンドの多くは型遅れとなっており、
現在はiproute2パッケージを代わりに使う。
また、ifconfigなどのコマンドは低レベルで強力だが使いづらいため、
より上の高レベルな設定システム、
たとえばDebianであればifupdownを用いて
設定を行うことがデフォルトとなっている。
また、サーバーはデーモンと呼ばれるシステムに常駐するプログラムによって
一度に一回実行するコマンドではなく、
システムで常にサービスを提供するが、
これの管理にはsystemdと呼ばれる仕組みを用いる。
以前はSysV initと呼ばれるプログラムとrcスクリプトによって設定を行っていたが、
現在はinitに「デーモンの並列起動処理ができない」という問題があり、
systemdが使われることが多い。
FreeBSDなどの*BSD系UNIXでは、SysV initではなくrc.confと呼ばれる、
ひとつの設定ファイルにおいてinit処理を行う。
以前のrcスクリプトでは、デーモンごとに起動を行う起動スクリプトがあり、
スクリプトへのシンボリックリンクに番号をつけることで順番を管理していたが、
これでは並列で起動処理を行うことができず、
現在のマルチコアプロセッサにおいては起動が遅くなる。
そのため、systemdではUnitファイルを用いて、可能な限り並列で起動する。
同時に、systemdはinitの代替以外にも多くの機能を提供し、
たとえばコマンドを定期的に実行するcrondや、
システムロガーなどの代わりにもなる。
systemdは「新しいLinuxの管理の中心」ともいえるシステムであり、
複雑であるため賛否の両論があるが、
現在のLinuxの管理機構の中心となっている。
Linux上におけるほかのネットワークプログラムとしては、
リモートによる接続やリモートログインを行う、
telnetやrlogin, sshのようなプログラムや、
ネットワーク上でログイン情報を共通化するNIS/YP、
ネットワーク上のファイルシステムをローカルにあるのと同じように
マウントできるNFSなどがある。
NFS以外のネットワークファイルシステムに準ずるシステムとしては、
サーバとの間でファイル転送を行うFTPや、
Windowsネットワークを実装したSambaなどがある。
HTTPにおいては、サーバとクライアントの間でHTMLデータをやり取りする。
この時、リクエストに対してサーバはレスポンスを返す。
WebブラウザはWebサーバにリクエストを要求し、
この時GETやPOSTなどのメソッドを要求する。
これに対して、Webサーバは、
「安全にデータを返します」「エラーが発生しました」といった
番号(HTTPステータスコード)による応答と、
具体的なデータ(エンティティボディ)を返す。
ブラウザはHTMLをCSSなどと同時に解釈し、
HTMLデータを内部的なツリー構造であるDOMツリーに変換する。
DOMツリーはブラウザにおいては、
JavaScriptと呼ばれる言語で操作することができる。
JavaScriptによる操作は、クライアントのWebブラウザの内部で行われるため、
クライアントサイドと呼ばれる。
これに対し、そもそもサーバでHTMLデータを返す際に、
動的にサーバ側で処理を行うことをサーバサイドと呼ぶ。
クライアントサイドではJavaScriptを用いるが、
サーバサイドではPHPやRubyといった言語を用いることが一般的。
実際は単にPHPやRubyを直接書くこともできるが、
よりWebサービスの開発のために便利な機能を詰め込んだ、
フレームワークというものを用いてサーバサイドの処理を記述する。
PHPではLaravel, RubyではRuby on Railsといったフレームワークが知られている。
しかしながら、クライアントサイドでJavaScriptを使いながら、
サーバサイドでRailsを使うのは、言語が二種類あって非効率である。
このため、サーバサイドでもJavaScriptを使うNode.jsといった
「サーバサイドJavaScript」と呼ばれる仕組みもある。
RailsやLaravelでは、MVCフレームワークと呼ばれるモデルで開発を行う。
MVCフレームワークでは、
まず外部からのリクエストを処理するルーティングと呼ばれる処理があり、
そのルーティングによって、
MVCのCに相当するコントローラのアクションに処理が移る。
アクションでは、Mに相当するモデルによって、
データベースとのやり取りを行い、
Vに相当するビューによって、
HTMLを動的に作成してブラウザに返す。
従来はこのMVCの処理を全てサーバ側で行っていたが、
ビューの処理はクライアントサイドだけでも行えることが最近分かってきたため、
Vue.jsやReactといったビューに特化したJavaScriptフレームワークで、
クライアントでビューの処理を行うことも一般的になってきている。
また、RubyやLaravelなどは、
C++やJavaと同様のクラスベースのオブジェクト指向を行うが、
JavaScriptでは、クラスベースではなくプロトタイプベースの
オブジェクト指向を採用している。
クラスのメンバ変数とメソッドを用いることなく、
JavaScriptではプロトタイプを作成することでオブジェクト指向ができるが、
従来のプログラミングとは異なるため、
クラスベースのオブジェクト指向を行うためにTypeScriptと呼ばれる言語を用いる。
また、C++やJavaには型がある(静的型付け)が、
JavaScriptには型が無い(動的型付け)。
動的型付けはプログラムの開発が簡単であるというメリットがあるが、
多くの場合、静的型付けの方がプログラムの信頼性や保守性が向上し、
たとえばプログラムとプログラムを結合した際にもバグがでることが少ない。
このため、TypeScriptではJavaScriptにおいても静的型付けを実現できる。
TypeScriptでは、TypeScript独自の型のチェックをした後で、
TypeScriptコードがJavaScriptコードに変換される。
以前のトレンドでは、RubyやPythonといった動的型付け言語が、
プログラムの書きやすさといった点から流行していたが、
最近は大規模なプログラム開発において静的型付けが再流行しており、
RubyやPythonといった動的型付け言語でも、
型アノテーションや型宣言ファイルを用いて、
静的型解析を行うことが一般的になりつつある。
また、Webにおいては、
「データベース管理システム」を用いてデータの管理を行う。
たとえば、掲示板を作るのであれば、
投稿された投稿内容をデータベースサーバに登録し、
表示する際にはそれを参照する。
リレーショナルデータベース管理システム(RDBMS)では、
二次元の表によってデータを管理する。
PythonやR言語でいうデータフレームも、これに準ずるものである。
(Pandasなどでは、
二次元のラベル付きデータ構造であるデータフレームを用いる)。
RDBMSでは、「リレーション」と呼ばれる仕組みを用いて、
小さく細分化(正規化)されたデータを、
結合したり、選択したり、射影したりして、
さまざまなデータテーブルを自動的に作成して処理を行う。
データベース管理システムでは、
まず、巨大なデータを検索する時に高速で、
同時にSQLクエリを用いて処理を行うという、
パフォーマンスと柔軟性のメリットがあり、
同時に、複数のプログラムから操作しても、
排他制御などにより矛盾が発生しないという、
矛盾のないデータの整合性を保つといったメリットもある。
また、データが破壊されることをできるだけ防ぎ、
破壊されることがないように復旧したり、
データを複製する冗長化や、
ひとつのサーバが落ちても別のサーバが代わりを務めるという、
フェイルオーバと呼ばれる仕組みもある。
このような信頼性を「可用性」と呼び、
信頼性ではなく効率を重視したクラスタのことを「HPC」と呼ぶ。
HPCにおいては、どれだけのマシンで並列処理ができるかが重要になる。
ネットワーク以外にも、一般的に並列処理を行うには、
スレッドセーフを考えた設計が重要になる。
スレッドセーフでは、データの競り合い状況が発生しないように、
共有データを処理する間ロックして、処理した後でロックを解除する。
この仕組みのことをmutexと呼ぶ。
C++には長らくスレッドの概念がなかったため、
マルチスレッドコードはプラットフォーム依存のコードを書く必要があったが、
Javaでは標準でスレッドの概念があり、
ロックはsynchronizedメソッド・ブロックで可能となっており、
スレッドの待機や割り込み(中断)もできるようになっている。
また、制御モデルにおいて、並列処理には3つのモデルがある。
まず、同じ処理を全てのスレッドで行う単純な並列処理モデル。
次に、マスター(主人)がスレーブ(奴隷)を従えるマスター・スレーブモデル。
最後に、プログラムの出力を次のプログラムの入力として次々に渡していく、
パイプラインモデルである。
並列処理以外の制御モデルとしては、
これ以外にも、コールバック関数をイベントループのリスナとして設定する、
イベントドリブン(イベント駆動)モデルなどがある。
イベントドリブンは、Windowsのウィンドウプログラムのほか、
Linuxカーネルのシステムコールなどにもみられる考え方である。
(一部の内容でCode Reading ~オープンソースから学ぶソフトウェア開発技法~ (プレミアムブックス版)を参考にしました。)
また、Linuxなどではパッケージ管理システムと呼ばれる管理機構によって、
システムの全ソフトウェアを管理する。
このメリットは、依存性の解決であり、
プログラムが導入されていても、
それに依存するプログラムが導入されていないから、
といった理由でシステムが動かず破損することを防げる。
通常は、RPMやDpkg/Debなどといった低レベルなシステムの上に、
DNFやAptといった使いやすい管理ツールを用いる。
このDNFやAptを用いると、ネットワーク上のリポジトリから、
パッケージをコマンドひとつでインストールし、
更新や依存するパッケージの導入なども全て自動で実行できる。
パッケージ管理システムを用いると、
システムを常に安全かつ最新に保つことができるが、
実際は全てのパッケージがリポジトリに用意されているわけではなく、
自分の使いたいバージョンが導入できるとも限らないため、
ソースtarball(tar.gzファイルのこと)から
configureやmakeでビルドすることも時には必要である。
最近ではシステムとアプリケーションをサンドボックス環境で分離する、
Flatpakなどのパッケージ管理システムもある。
このメリットは、クロスディストリビューションであること。
従来のパッケージ管理システムにおいては、
ひとつひとつのディストリビューションに
対応するパッケージを用意する必要があった。
Flatpakを用いることで、全てのバージョンのパッケージを、
全てのディストリビューションに配布することができる。
また、ネットワークにおいては、仮想化と呼ばれる仕組みを使うこともある。
これは、OSの上で仮想マシンや仮想CPUをエミュレートし、
OSの上で別のOSを実行できる機能。
VM型の仮想化では、OSそのものを仮想化するため、
たとえばWindows上でLinuxを実行できる。
VM型仮想化としては、Virtualboxなどが有名。
これに対して、Linux上でLinuxの仮想化を行うDockerなどでは、
カーネルを共有するコンテナ型の仮想化を行うため、
軽量でパフォーマンスがいい。
コンテナ型の仮想化では、
プロセスを専用のコンテナプロセスとして「隔離」することができ、
それを「コンテナイメージ」とすることができる。
Docker Hubなどのホスティングサイトでは、
このコンテナイメージをインターネットからダウンロードでき、
たとえば何の設定や導入もしなくても、
簡単にRuby on Railsの環境をDockerだけで実現することができる。
また、必要がなくなったら、簡単に仮想サーバごと削除できる。
こうしたコンテナ型の仮想化は、
システムの開発(DevOps)においてはとても便利で、
本番環境を開発環境で再現するために使えるほか、
レンタルサーバなどでは、
簡単にroot権限のある仮想サーバを利用者に与えることができる(VPS)。
ネットワーク上でセキュリティを確保するためには、
暗号化という仕組みを用いる。
共通鍵暗号方式では、
暗号化と復号化に用いる鍵が同じだが、
公開鍵暗号方式では、
公開鍵と秘密鍵を使う。
秘密鍵は知られてはならないが、公開鍵は誰に知られても構わない。
暗号化通信においては、公開鍵暗号方式を使うことが多い。
まず、受信者が公開鍵と秘密鍵のペアを作り、
自分の公開鍵を相手に送る。
送信者は、その公開鍵を使ってデータを暗号化する。
そしてデータを受信した受信者は、秘密鍵を用いてデータを復号化する。
(暗号技術入門 第3版 秘密の国のアリスを参考にして執筆しました。)
また、コンピュータの原理においては、
二進数の計算は、00+00=00, 01+00=01, 00+01=01, 01+01=10の4通りしかない。
これは、論理回路におけるANDとEXORで機械的に計算できる。
実際は、これは下桁からの繰上りを考慮していないため、半加算器と呼ばれる。
下桁からの繰上りを考慮した全加算器は、
二つの半加算器とOR回路によって実現できる。
また、減算については2の補数を加算することで実現できる。
2の補数とは、ビットの0と1を反転させて1を加算した表現のことで、
正の数に負の数を加算すれば必ず桁あふれが起きて結果が0になる。
乗算と除算については、小学校で習う筆算と同様に、
桁ごとに演算を行えば実現できる。
(放送大学「情報学へのとびら ('16)」を参考にして執筆しました。)
Linuxでは、ファイルシステムはまずパーティションを作成し、
その中にファイルシステムを作成し、
それをマウントすることでディレクトリツリーとファイルを操作できる。
/etc/fstabには、
起動時にマウントされるファイルシステムボリュームの設定をする。
Linuxのファイルシステムでは、
VFSと呼ばれる仕組みによって、
さまざまな別のファイルシステムを使うことができる。
ブロック型のext2や
ジャーナリング(途中で強制終了しても壊れない)に対応した
ext3/ext4などがある。
また、ReiserFSやXFSはB-Treeファイルシステムと知られる。
ブロック型のext4ではなく
データベースと同様のインデックス技術を用いた高速な検索が可能。
また、ZFSやBtrFSのようなコピーオンライトのファイルシステムでは、
ファイルをコピーしてもほとんどのデータを共有データとし、
書き換えられた時点で複製を作る(コピーオンライト)仕組みを採用している。
これにより、データリソースを大幅な削減ができるほか、
毎日スナップショットをとってもデータの大幅な利用に繋がらないため、
いつでも好きな地点にスナップショットからデータを復旧させることができ、
信頼性の確保に繋がる。
ファイルシステム階層としては、
基本的に/usrにはシステム全体で共有される、
あまり頻繁に変更されないファイルを置く。
/varには、頻繁に変更されるファイル、
たとえばログやスプールファイルを置く、
そして、/etcにはシステム管理者が設定する設定ファイルなどを置く。
/usr/localは、/usrと同様だが、パッケージ管理システムではなく、
システム管理者が手動で管理するmakeビルドのプログラムを置く。
そして、/home/usernameにはユーザー個別のホームディレクトリが置かれる。
これらは、所有者、所有グループ、その他のユーザーに対する、
実行、読み込み、書き込みの許可権限であるパーミッションで守られる。
しかしながら、
特権ユーザーであるrootに莫大な権限があることが問題だったり、
Webサーバなどのプロセスに権限を付加させたい場合などは、
SELinuxなどのより強固なセキュアOSモジュールを使うこともできる。
プロセスは、シェルと呼ばれるプロンプトからコマンドで実行することが多いが、
この時&をつけることで、バックグラウンドで実行できる。
また、パイプとリダイレクトを用いることで、
あるコマンドの出力を別のコマンドに渡したり、
標準入出力をファイルと変換することができ、
特にgrep, find, xargs, sed, awkあるいはUNIXのさまざまなフィルターコマンドは、
このパイプとリダイレクトを用いて、
「複数のコマンドを組み合わせてひとつの作業をする」ことが一般的である。
UNIXではプロセスは、fork()とそれに準ずるシステムコールによって作成する。
また、デーモンを作る時は、fork()した後でsetsid()で端末を切り離す。
マルチタスクにはプロセスとスレッドがあり、
プロセスはそれぞれ個別にメモリ領域が与えられるが、
スレッドでは共有データとなる。
一応、プロセス間通信などの例外もある。
プロセスには、付属するメモリ領域として、
テキスト領域(プログラムそのもの)、
スタック領域、ヒープ領域などが与えられる。
入出力処理は、ストリームを通じて行われる。
ストリームはバイト列のことで、
バイト列としてあらわされるものは何でもストリーム。
ストリームを使うためには、
デバイスファイルを媒介に使う。
キャラクタ型デバイスかブロック型デバイスかによって使い方は異なるが、
キャラクタ型デバイスはバイト列の処理としてあらわされ、
ランダムアクセスができない。
ブロック型デバイスは、ファイルシステムにマウントして用い、
ランダムアクセスができる。
標準で標準入力、標準出力、標準エラー出力が、
ストリームを識別するファイルディスクリプタとして、
プロセスに与えられるが、
open()/close()したファイルについては
それぞれのストリームがファイルディスクリプタとして対応し、
read()やwrite()から読み書きできる。
しかしながら、システムコールはバイト固定長の入出力しかできず、
バッファ管理を行わないため速度も遅い。
これに対して、C言語のstdioライブラリでは、
バッファ管理ができて高速であるほか、
1文字単位や1行単位の入出力、フォーマット入出力もサポートしている。
stdioを使う時は、
fopen()とfclose()を使ってファイルをオープンし、
fread()やfwrite()で固定長の操作ができる。
注意点として、gets()は使ってはならない。
バッファオーバーランの脆弱性を回避できないためである。
通常、入力にはfgets()を使い、
一文字単位の入出力にはgetchar()とputchar()、
コンソールへの出力はputs()やprintf()、ファイルへの出力はfprintf()を使う。
また、文字列をフォーマット変換のみしたい場合は、sprintf()を使えばよい。
また、プログラミングの特性上、
「一文字余計に読み込まなければトークンの終端か分からない」ということがある。
この時、一文字元に戻すAPIとしてungetc()がある。
(ふつうのLinuxプログラミング Linuxの仕組みから学べるgccプログラミングの王道を参考に執筆しました。)
Linuxでは、主にC言語を用いてプログラムを記述し、
それをGCCなどのコンパイラを用いてコンパイルする。
GCCでは、コンパイラの前段階として
プリプロセス(#defineや#includeなどの処理)を行い、
コンパイル可能なC言語の完全なソースコードを生成したら、
それをアセンブリ言語にコンパイルする。
コンパイラの手順としては、
字句解析でトークンを解析し、
構文解析で構文ルールからパースツリーを作成し、
三番地コードなどの中間言語を作成し、
最適化を行ってアセンブリ言語を出力する。
GCCでは、フロントエンドとバックエンドに構造が分かれており、
フロントエンドではFORTRANなどのC/C++以外の言語にも対応して解析でき、
バックエンドではさまざまなCPUアーキテクチャのアセンブリ言語を吐き出せる。
コンパイルが終わったら、
アセンブルして機械語のオブジェクトファイルを生成し、
リンクを行う。
機械語のオブジェクトファイルになった段階で、
プログラムは実行可能なプログラムとライブラリに分かれている。
ライブラリには二つの種類があり、
スタティックリンク(*.a)では、
リンクの時点で完全に実行プログラムと結合される。
一方、ダイナミックリンク(*.so)では、リンクの時点では結合を行わず、
実行時にリンクローダ(/lib/ld-linux.so.2)が動的にリンクを行う。
最近のUNIXでは、ダイナミックリンクを使うのが一般的だが、
一部の軽量libc(Muslなど)ではスタティックリンクに最適化されたものもある。
また、全てのプログラムは暗黙のうちに、
libc.so.6にダイナミックリンクされている。
バイナリがどの共有ライブラリに依存しているかはlddコマンドで確認できる。
参考文献:
Linuxでは、GUI環境をWindowsと同様に利用することができる。
このために、Xサーバーを使う。
X Window System(X11)は、クライアント・サーバー方式で、
ネットワーク透過と呼ばれるネットワーク通信をサポートしており、
その中核のプトロコルをXプロトコルと呼ぶ。
Xプロトコルは、ディスプレイを表示するXサーバーと、
アプリケーションウィンドウを担当するXクライアントの間で、
ネットワークで通信しながら、
マウスボタンクリックなどのイベントメッセージをやり取りする。
Xプロトコルの詳細を知らなくてもいいように、
Xlibと呼ばれるライブラリが用意されており、
プログラマはXlibを使ってXクライアントを書くことができる。
また、X11においては、ウィンドウを表示するプロトコルとAPIは決まっていても、
ボタンやメニューなどのウィジェットツールキットまでは用意されていない。
そのため、Motif, Qt, GTKなどのウィジェットツールキットを用いて
アプリケーションを書くことが一般的である。
また、X11はウィンドウマネージャと呼ばれるGUI環境を用いて、
ユーザーは操作するが(これがWindowsやMacの環境に相当する)、
標準ではとても簡素なウィンドウマネージャしか提供されておらず、
これを使ってデスクトップ環境を操作することは一般的ではない。
ウィンドウマネージャにはたくさんの種類があるが、
ウィンドウマネージャだけではなく、
統合的なデスクトップ環境を与えるものとして、
GNOME, KDE, Xfce, MATE, Cinnamonなどがある。
GNOMEではツールキットにGTKが、KDEではツールキットにQtが採用されている。
GNOMEなどでは、CORBAと呼ばれる分散システムを設計の基本にすることで、
プラットフォームと言語とネットワークの垣根を超えた
モジュールのリンクが可能であり、
これを長らくKDEに比べた優位性としてきた。
しかしながら、GNOME 3では
CORBAはD-Busによってリプレースされている。
また、GNOMEのGTKはGLib/GObjectと呼ばれる
オブジェクト指向の仕組みを提供しており、
GLibにのっとってC言語でオブジェクト指向の環境でプログラムを開発できる。
また、C言語は比較的各種言語のバインディングが作りやすく、
C++/Python/JavaScript/Vala/Rustなどにも対応している。
これに対して、QtはC++の仕組みを採用しているが、
比較的、美しくて機能的なのはKDE/Qtの方である。
しかしながら、Qtはそもそも昔はフリーソフトウェアではないツールキットであり、
GNUなどではこれに対してGNOMEプロジェクトを開始するに至った。
今ではQtはフリーソフトウェアライセンスで提供されている。
また、GNOMEは比較的独立性が高く、
また初心者向けで、最初のログイン時に動画で使い方を教えるなど、
Windowsも使えない初心者ユーザーのためによく考えられている。
しかしながら、Linux開発者のリーナス・トーバルズなどは、
「ユーザーを馬鹿だとみなすGNOMEの姿勢は根本的に誤りである」としている。
標準となっているのはGNOMEだが、
デスクトップのデザインが美しく、
また、搭載アプリケーションの高機能性が光るのはKDEである。
特に、KDEアプリケーションには、
Windowsに遜色のない機能的GUIアプリが多く備わっている。
フリーソフトウェアライセンスには、大きく二種類がある。
それは、GPLなどのコピーレフトのライセンスと、
BSDライセンスやMITライセンスなどの緩いパーミッシブライセンスである。
コピーレフトのライセンスでは、
コピーレフトなコードを含まれたコードは、
必ずコピーレフトなライセンスで再配布しなければならない。
つまり、GPLで書かれたソフトウェアは、
含まれているコードがどれだけ一部分であったとしても、
必ずどんな場合でもGPLで再配布される。
そのため、永久にGPLが保たれる。
逆に、ソフトウェア開発者は、
GPLのコードが含まれていないかどうかを確認し、
含まれている場合はGPLで配布しなければならない。
GPLでは、ソフトウェアの実行、コピー、再配布、改造を認めており、
この前提としてソースコードを配布しなければならない。
つまり、GPLコードは必ずオープンソースで配布しなければならないため、
商用的なソフトウェアのソースコードとして、
GPLのものを含めることは適切ではない。
なぜなら、含めた時点でソースコードを公開しなければならず、
それは自由に再配布や改造を認めなければならないため、
はっきり言って「商売にはならない」。
しかしながら、パブリックドメインのUNIXが後にクローズドになった経験や、
多くの商用UNIXでフリーソフトウェアが
非フリーの状態で提供されていたことを受け、
「フリーなUNIXのクローンを作ろう」と
GNU創始者のリチャード・M・ストールマンが考えた結果、
GPLはGNUによるソフトウェアの多くに採用されており、
初期のMINIXのコンポーネントを
GNUのコンポーネントに置き換えたLinuxカーネルにおいても、
商用利用を禁じる初期のライセンスを撤廃して、GPLが採用されている。
GPLに対して、GNU以外のフリーソフトウェアプロジェクトは、
パーミッシブライセンスと呼ばれる
BSDライセンスやMITライセンスを採用したものもある。
FreeBSD/NetBSD/OpenBSDのソフトウェアや、
X.org Serverなどでは、パーミッシブライセンスが採用されている。
パーミッシブライセンスでは、
「コードが含めれていてもフリーなライセンスで配布しなくてよい」。
プロジェクトがフリーソフトウェアのままで存続するためには、
オリジナルのプロジェクトがきちんと組織管理すればよいと考え、
たとえフリーでないライセンスで配布されてもそれを許している。
このような姿勢は「緩い」ライセンスと知られている。
しかしながら、パーミッシブライセンスにおいても、
著作者の表示とライセンスの表示は行わなければならない。
こうしたフリーソフトウェアのライセンスを、
ソフトウェアだけではなく文書やコンテンツに適用したものとして、
クリエイティブ・コモンズなどが知られている。
クリエイティブ・コモンズは、
たとえば日本の同人誌や同人作家のように、
「二次創作における自由なライセンスを確保するため」に
フリーソフトウェアを参考にして法律化されたもので、
さまざまなライセンス形態が選べる。
クリエイティブ・コモンズは、
Wikipediaの共同文書のライセンスなどに採用されている。
また、インターネット上には多くのクリエイティブ・コモンズで
ライセンスされた画像ファイルや文書ファイルがある。
しかしながら、GPLと同様に、
継承条項を付けたSAライセンスを選ぶことができるため、
商用利用を行う際には、
継承条項がついているかどうかに注意する必要がある。
もしついていたとしたら、
そのコンテンツを自分たちもSAで公開する必要がある。
また、フリーソフトウェアという言葉とよく似た言葉として、
オープンソースという言葉がある。
これは、開発をオープンにし、みんなのパッチをどんどん取り込むことで、
片手間のボランティアによって一流のカーネルが開発された、
Linuxカーネルの開発手法から生まれた言葉で、
「伽藍とバザール」というエリック・レイモンドの文書を代表として、
作られた造語である。
伽藍とバザールでは、GNUのように、
一部のきちんと分かっているエンジニアが慎重に作り上げる開発手法のことを、
「伽藍」すなわち教会のカテドラルになぞらえ、
これに対して「乱交まがいにオープンにする」Linuxカーネルの開発手法を、
「バザール」と呼んだ。
この伽藍とバザールは、インターネットの多くの人々に衝撃と称賛を与え、
これにならってオープンソース開発をしようとする企業が現れた。
それが、マイクロソフトのIEとのブラウザ戦争に負けたNetscapeである。
Netscapeはインターネットの黎明期にWebブラウザの覇者として君臨したが、
Windowsの成功と、バンドルされたIEとのブラウザ戦争に負け、
その時「伽藍とバザール」の影響を受けて、
ブラウザの存続をかけて、Netscapeブラウザのオープンソース化を決める。
新しいブラウザの名前は「Mozilla」となり
(「Mozilla」は昔からのNetscapeの愛称だった)、
そのプロジェクトはオープンなMozilla.orgによって行われる。
しかしながら、Mozillaはなかなか安定したバージョンをリリースできず、
開発は遅れ、
開発の中心メンバーもコミュニティのボランティアではなく、
Netscape社員であるままが続いた。
Netscapeの業績不振もあり、Netscape社はAOLに買収される。
しかしながら、その後もMozillaの開発は続く。
MozillaはXULと呼ばれるXMLとJavaScriptを用いた抽象的なUI言語を持っており、
ブラウザだけではなくメールクライアントやHTML編集エディタもあったが、
このせいでIEに比べてとても巨大で重かった。
しかしながら、XULの機構を用いることで、
拡張機能をEmacsのLispのように分離することができる。
いつまでもMozillaは日進月歩で開発されたが、
こうした機能を上手く使って、
メールクライアントやHTML編集エディタを削除し、
最低限の機能を持った軽量なWebブラウザである、
Mozilla Firefox(以前の名はPhoenixあるいはFirebird)を新たにリリースし、
使いたい機能を拡張機能としてユーザーが自由に拡張できるようにした。
Firefoxと同様、メールクライアントもThunderbirdとして分離。
一時期はIEに次ぐ第二のブラウザとして、
NewYork Timesに広告を掲載するなどの流行を見せていたが、
GoogleによるWebKit系のブラウザであるGoogle Chromeなどに
第二位の座を奪われ、
今ではFirefoxは「商用企業ではなくユーザーのためのブラウザ」として
なんとかインターネット上で続いている。
Linuxにおいては、
GNOMEではFirefoxがデフォルトのブラウザになっていることが多いが、
KDEではKonqueror(WebKitの元になったKHTMLをベース)が標準であり、
XfceではMidoriなどが軽量ブラウザとして提供されており、
またGNOMEにおいてもGNOME Webなどが開発されており、
サーバーサイドJavaScriptのNode.jsはChromeのV8エンジンの上で動くなど、
しだいにFirefoxも草葉の陰に隠れつつある。
WindowsやMacでも、決してFirefoxはマイナーなブラウザではないが、
メインのブラウザとしてはChromeを使う人が増えてきている。
また、「なぜこのようなWindowsが勝利するのか」と言えば、
まず、WindowsはIBM PC/AT互換機で標準だったMS-DOSから始まる、
「バンドルの歴史」がある。
IBM PC/AT互換機を買うと、必ずWindowsがついてくる。
IEやMS-Officeなども、標準でWindowsにくっついてくる。
そのため、初期ユーザーを簡単に得ることができた。
もうひとつの要因は、「MS-Officeの文書形式」である。
MS-Officeは独自の文書形式を採用しており、
これは長い間Microsoftの独自形式であったため、
MS-Officeで作った文書は、MS-Officeでしか編集できない。
そのため、簡単にMS-Officeから別のOfficeソフトウェアに変えられない。
しかしながら、オープンソースの世界では、
これに対して「オープン標準の文書形式を採用しよう」という声があり、
それが、Sunが買収してオープンにした、
OpenOffice.orgのOpenDocument Formatである。
OpenOffice.orgは、オープンソースのOfficeソフトウェアであり、
Office形式にOpenDocumentを採用し、
ほかのOfficeソフトウェアと相互運用ができるようにした。
今では、さまざまな経緯からOpenOffice.orgはApacheの所管に移り、
メインの開発はLibreOfficeという後継ソフトウェアに移行している。
しかしながら、LibreOfficeの問題は、「使いづらい」こと。
MS-Officeでは、ユーザーが間違った操作をしたり、
ユーザーがあまりOfficeに詳しくなくても、
適当になんとなく操作できるようになっていることが多いが、
これがLibreOfficeだと「まったくどの機能を使っていいか分からない」。
ユーザーは、MS-Officeとの操作性の違いなどから、
まともにLibreOfficeを使うことができない。
もうひとつは、果たして
「MS-Officeを捨ててまでLibreOfficeを使う理由がない」ということ。
WindowsからLinuxに移行すると、
普通にLibreOfficeを使おうとすれば使えるのだが、
逆にMS-Officeを使える環境がなくなってしまう。
これは、「無料のOfficeを使えるといっておいて、
有料の標準のMS-Officeを奪っていく行為に等しい」。
このことから、いくらLinuxがオープンソースかつ無料で利用できるといっても、
なかなかMS-OfficeからLibreOfficeへの移行は起きていない。
同様のことが、Adobe PhotoshopとGIMPなど、オープンソース全般に言える。
GIMPは確かに無料だが、
Adobe Photoshopに慣れているデザイナーは、
誰もがAdobe Photoshopを使うことを楽しみとしており、
無料のGIMPを与えたところで、簡単には移行しようとしないのである。
しかしながら、Microsoftの栄華も安泰ではない。
なぜなら、今の世界は完全にWebサービスの時代であり、
特にGAFAと呼ばれるインターネット企業の時代だからである。
WindowsはあくまでローカルのコンピュータOSであり、
いくらクライアントを中心に普及しているからといって、
Webサーバーの世界ではLinuxなども普及しているし、
何より、モバイルOSやモバイルアプリの存在がある。
モバイルではGoogleのAndroidとAppleのiOSが覇権を握っており、
Windowsは完全に野外に追いやられてしまっている。
また、商業的なシステムにおいても、
Windowsをエンタープライズで作る事例は多くない。
エンタープライズでは、メインフレームやUNIXが今でも多く、
このような現場ではJavaが使われており、
ある程度の規模のシステムではLinuxをOSによく使う。
何より、最近はクラウドと呼ばれるネットワークサービスとしての、
コンピュータの利用が増えている。
このクラウドで強いのはLinuxであり、
Microsoftもこうした現状を受けて、
オープンソースへの取り組みを多く行っている。
たとえば、MicrosoftはVS-Codeと呼ばれる
オープンソースのテキストエディタを作っており、
ほとんどエンジニアの間で標準である。
また、MicrosoftはJavaScriptの拡張言語であるTypeScriptを
オープンソースで開発している。
PHPのWebフレームワークのLaravelも、MSの社員によるものである。
また、リーナス・トーバルズによる分散バージョン管理システムGitの、
ホスティングサイトGitHubはMicrosoftによって買収された。
Windows上でLinux互換環境を実現するWSLは、
WSL 2によって、Linuxカーネルを完全にWindows上で仮想化し、
Windowsで全てのLinuxアプリケーションが動くようになる。
WindowsでGUIアプリを開発するための標準開発環境である、
.NET Frameworkについても、
.NET Coreをオープン化することでオープンソース化し、
Linuxなどでも.NET Coreを使うことができるようになった。
Azureでも、Linuxをサポート対象に加えている。
このように、Windowsがオープンソースに近づいているのは、
やはり、GoogleやFacebookといったGAFA系の企業がある。
彼らはどんどんオープンソースでプロダクトを公開・標準化しており、
このままだと「Microsoftが開発するよりも先にGAFAが制覇してしまう」。
よって、MSはあえてオープンに近い戦略を取ることで、
GAFAの力をくじいているのである。
しかしながら、いくらMSの技術力とOSシェアが高くても、
GAFAに勝つのは容易ではない。
それは、たとえば開発者視点でのフレームワークである。
Googleのモバイル向けフレームワークのFlutterや、
FacebookのJavaScriptフレームワークのReactなどは、
国際的な視野で見て、圧倒的な開発者の支持を得ている。
地球規模で、FlutterやReactはほぼ標準であり、
多くのプロのエンジニアがそれらを使って開発をしている。
このような波の中で、いくらMSが一流の技術企業であっても、
GAFAに勝つのは困難を極めるだろう。
特に、GoogleのYouTubeなどは、
再生回数に応じて収入が入る仕組みになっており、
たくさんの勝ち馬に乗ろうとするYouTuberが動画をアップし、
一部のYouTuberは莫大な利益をあげている。
それくらい、MSがWindowsで金があるのと同様、
GAFAも同じぐらい金がある。
しかしながら、僕はあえて綺麗事を言う。
それは、「金儲けだけじゃないものもある」ということ。
今のIT技術というのは、
金儲けがまず先にあり、そのためにサービスを作って提供するが、
昔のインターネットはそうじゃなかった。
たとえば2ちゃんねるのようなアングラ匿名掲示板でも、
あるいは昔先駆的だったブログでも、
金儲けではない、「新しいものを一緒に共有する楽しさ」があった。
みんなで掲示板にAAで作った顔文字を投稿するのも、
時には高度な2ちゃんねる専用ブラウザを開発するのも、
「IT技術そのものを楽しんでいる楽しさ」があった。
今のGAFAには、それがない。
Appleのカリスマ経営者スティーブ・ジョブズ氏が死去したことも、
原因のひとつかもしれない。
ジョブズは偉大なエンジニアで、経営者で、デザイナーだったが、
彼が死んだことで、MacだけではなくWindowsやLinuxでさえ、
「デザイン性の欠如したコピー製品になった」。
そのような今のIT業界を、僕は信頼することができないのである。
昔のITは、何が楽しかったかは分からないが、楽しかった。
足は、軟骨がおかしくなっている。
それは、関節を治しすぎたからである。
軟骨を復活させれば、治した部分が元に戻って治る。
気持ち悪かったのが復活して、元に戻っていく。
すべて、治る。
これこそ、恒星の一生である。