今週からようやく梅雨らしくなってきました。紫陽花がいい色になって少し嬉しい今日この頃です。
さて季節とは全く関係ないのですが、今日たまたまこちらの記事「MacからNASとかWindowsの共有フォルダへのアクセスが妙に遅いのを解決する」を見ていて気づいたことがありました。
Viは難しい
近年Macを使う人がとても増えましたよね。MacはサーバOSとしてよく使われるLinuxをベースにしていますので、少し特別なシステム設定を変更したいとき、多くの人にとってはあまり馴染みの無い、ターミナルを開いて操作をしなければならない場面があります。
それがその記事で紹介されているような、/etc/sysctl.conf というファイルに net.inet.tcp.delayed_ack=0 という文字を書き込むといった操作ですね。具体的にviというエディタでファイルを開いて編集する手順が紹介されていることも、同様に多いです。
こういった場合、サーバのオペレーションに慣れている人はいいのですが、慣れない人にとってviという特殊なエディタを使うことはひどく敷居が高いと思います。その記事のコメント欄もviの使い方説明になってしまっていたほど、ちょっと普通の「メモ帳」とか「テキストエディット」とかとは操作の仕方が違うのです。
teeを使う
それよりはただ1行追記するだけでよいのであれば、ターミナルから以下のように入力します。(エンターキーを押した後、パスワードの入力も必要です)
echo 'net.inet.tcp.delayed_ack=0' | sudo tee -a /etc/sysctl.conf
このようにすれば、例え書き込みにroot権限(強い管理者の権限)が必要なファイルであっても、viエディタを開くことなく追記することができます。
こんばんは。梅雨に入ったというのに、全然雨が降らないですね。天気がいいのはとりあえず洗濯物にとってはいいことですが、あんまり降らないようだと今度は夏の水不足が心配になってきます。
ところで今日は前回の続きというか補足をします。最初はノンブロッキングAPIを使う方法を書くつもりでしたが、ちょっと気が変わりました(笑)。
ブロッキングモードとノンブロッキングモード
前回も少し触れた通り、ソケット通信を扱う方法として、ブロッキングモードとノンブロッキングモードというものがあります。簡単に言えば通信をする際にいちいちブロックするのがブロッキングモード、ブロックしないのがノンブロッキングモードです。
・・・それではあまり説明になっていないのでもう少し詳しく言いましょう。ネットワーク越しにデータを読み取ろうとしたり書き込もうとしたりする場合、それ相応の遅延が発生します。その遅延時間をどうするのかという違いがブロッキングモードとノンブロッキングモードの違いです。
- ブロッキングモード
- 読み込みや書き込みを完了するまで待ちます。つまりコード上、readやwriteのメソッドをコールすると完了するまで制御はブロックします。
- ノンブロッキングモード
- 「今できる処理だけをする」ことを基本にします。つまりコード上、readやwriteのメソッドをコールすると今読み取れるデータのみをreadし、或は今書き込めるデータのみをwriteして、すぐに制御が戻ります。
前回 Java SE 7 においてサーバソケットを扱う方法は3通りあると言いました。クラス名でいうなら、
- java.net.ServerSocket
- java.nio.channels.ServerSocketChannel
- java.nio.channels.AsynchronousServerSocketChannel
この3通りです。前回使った ServerSocket はブロッキングモードで処理をします。2番目の ServerSocketChannel はブロッキングモードとノンブロッキングモードのどちらでも処理をすることができます。加えて効率の良いChannelクラスを使って読み書きできますので、ブロッキングモードで処理したい場合であってもJDK1.4以上の環境ならば、ServerSocket より ServerSocketChannel を使用することを考えた方がよいと思います。
java.nio.channels.ServerSocketChannel をブロッキングモードで使う
というわけで、前回の ServerSocket を ServerSocketChannel に置き換えて、ブロッキングモードで処理してみましょう。
try (ServerSocketChannel listener = ServerSocketChannel.open();) {
listener.setOption(StandardSocketOptions.SO_REUSEADDR, Boolean.TRUE);
listener.bind(new InetSocketAddress(8080));
System.out.println("Server listening on port 8080...");
while (true) {
try (SocketChannel channel = listener.accept();) {
System.out.printf("ACCEPT %s%n", channel);
Bytes.copy(channel, channel);
System.out.printf("CLOSE %s%n", channel);
}
}
} catch (IOException e) {
e.printStackTrace();
}
完全なコード
んん? あまり変わっていないような・・・? その通りです。ブロッキングモードで処理する場合、だいたい似たようなコードを書けばよいのです。ちなみに前回説明を省略しましたが、Bytes#copy()というメソッドはJDKには(今のところ)ありません。以下のようなシグネチャのメソッドを想定しています。
Bytes#copy(ReadableByteChannel from, WritableByteChannel to);
Bytes#copy(InputStream from, OutputStream to);
ソケットは読み込みも書き込みもできますので、SocketChannel も ReadableByteChannel と WritableByteChannel を両方実装しているというわけです。
再びスレッド化する
さて上記のコードは前回と同じく1対1で通信するコードになっています。なのでやはりスレッド化したコードも掲げておきます。
ExecutorService worker = Executors.newCachedThreadPool();
try (ServerSocketChannel listener = ServerSocketChannel.open();) {
listener.setOption(StandardSocketOptions.SO_REUSEADDR, Boolean.TRUE);
listener.bind(new InetSocketAddress(8081));
System.out.println("Server listening on port 8081...");
while (true) {
final SocketChannel _channel = listener.accept();
System.out.printf("ACCEPT %s%n", _channel);
worker.submit(new Runnable() {
@Override
public void run() {
try (SocketChannel channel = _channel;) {
Bytes.copy(channel, channel);
System.out.printf("CLOSE %s%n", channel);
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
} catch (IOException e) {
e.printStackTrace();
} finally {
worker.shutdown();
}
完全なコード
これもほとんど同じですね。
それでは次回はいよいよ、ServerSocketChannel をノンブロッキングモードで使ってみたいと思います。
そういえば今週はJava EE 7のリリースがあります。私もオンラインのローンチイベントに参加登録しています。昼間は参加が難しそうなので、深夜の部かあるいは、あとでYouTubeを見るとかそんな感じになるかもしれませんが・・・。
私はこの5月をもって株式会社TAGGYを辞し、6月より株式会社medibaに入社いたしました。ここにご報告いたします。
まずはお世話になっている皆様にお礼申し上げます。至らぬ点の多い私ですが、これまで仕事を続けてこられたのは皆様のご指導お力添えのお陰です。新天地にても今までに得てきたものを活かし、全てのビジネスに関して最高の技術的解法を提供することができるよう、努力して参ります。今後ともよろしくお願いいたします。
またこれから新しい立場でお世話になる皆様、不慣れ故何かとお手数ご迷惑をお掛けすることと存じます。一日も早く戦力となるべくキャッチアップしていくとともに、ビジネスの質と量を向上できるよう新しい視点で貢献して参りますので、何卒よろしくお願いいたします。
今回職場は変わりますが、Webに関わるエンジニアリングという職に変わりはありません。今後ともより良いWebを目指して私自身日々研鑽を続け、また知識共有を推進していく所存です。何かの機会にはお声掛け頂ければ幸いです。
最後に皆様に重ねてお礼申し上げ、略儀にて恐縮ながらご報告とさせて頂きます。
2013年6月
子安 輝
今回の社内勉強会はScalaについてでした。
Scalaを理解すること、使ってみることは、Javaプログラマにとって様々なメリットがあります。限られた時間の中でScalaの全てを説明することはできませんが、Javaプログラマにあまり馴染みの無い概念である「関数型プログラミング」と「トレイト」について少し詳しく説明し、またコレクションの操作、並列処理モデルのアクターに触れています。
http://www.slideshare.net/akirakoyasu/scala-forjavaprogrammers
The last study in my company was about Scala programming language.
It has some merits for Java programmers to understand it and to use it. Although I can’t explain all about Scala in a limited time, I give a detailed explanation of “Functional programming” and “Traits” which is unfamiliar to Java programmers, and touch on collection operations and Actors the model of concurrency.
http://www.slideshare.net/akirakoyasu/scala-forjavaprogrammers