計算機
プログラミング基礎
(Cクラス)
河口 信夫
前回の復習
名簿管理システムの開発
– 自分で理解してできたでしょうか?
– オブジェクト指向の基本は理解できましたか?
Person, Student, Teacher の役割は
理解できたでしょうか?
大事なこと
– プログラムを読んで理解できる
– 必要な修正をする場所を見つけることができる
– やりたいことを実現するライブラリ等を
見つけることができる
Java 言語応用
マルチスレッド
単純なプログラムは1つの計算フローしか
持たない
チャットをしたい場合
– ユーザからの入力待ち
– ネットワークからの入力待ち
複数のフローが必要になる
マルチスレッドプログラミング
JavaによるThread
言語レベルで Thread をサポート
Thread クラス, Runnable インタフェース
Runnable runner = new MyRunnable();
Thread th = new Thread(runner);
th.start();
… メインスレッドと runner スレッドの2つが
同時に実行される
マルチスレッドプログラミング
複数のスレッドが同時に実行
同じ変数にアクセスする場合、問題になる
– x = x * 2 + x (x を3倍するはず)
– もし 2つのスレッドが同時にアクセスすると、
最初のxへの参照と後のxの参照で値が
異なる場合が発生しうる。
リソースの競合を避けるために
synchronized 節がある
ネットワークの基礎
インターネットプロトコル
インターネットは多数のプロトコル(約束事)
で動いている
– TCP, IP, UDP, HTTP, FTP…
個々のプロトコルさえ理解すれば
相互に通信可能
IPアドレス
IP (Internet Protocol) アドレスは
8bit * 4 = 32 bit の数字
一般に nnn.xxx.yyy.zzz と表記される
これで世界中の計算機にアクセス可能
ソケット(Socket)
インターネットのプログラミングを簡単に
するための方法論
ソケットを接続するように簡易に利用可能
IPアドレスとポート番号で相手を指定できる
サーバ・クライアントモデル
サーバ
クライアント
クライアント
ポート
ポート
ポート
ポート
サーバ・クライアントモデル
サーバ
クライアント
クライアント
ポート
ポート
ポート
ポート
サーバ・クライアントモデル
サーバ
クライアント
クライアント
ポート
ポート
ポート
ポート
ソケットによる S/C モデル
サーバソケット
クライアント
ソケット
クライアント
ソケット
ポート
ポート
ポート
ポート
HTTPの基礎
HTTP (Webプロトコル)
Webサーバをアクセス・利用するための
プロトコル
W3Cによって定義されている
ポート番号は 80 番(課題では8080を利用)
Get コマンドでページを取得
詳細は http://www.w3.org/
RFC1945 (HTTP/1.0)
HTTPの概要
アプリケーション層(HTTP) トランスポート層 (TCP) ネットワーク層 (IP) データリンク層 (Ethernet Driver)Webブラウザ
アプリケーション層(HTTP) トランスポート層 (TCP) ネットワーク層 (IP) データリンク層 (Ethernet Driver)Webサーバ
HTTP
TCP
IP
Ether
Protocol
電気信号HTTP の基本動作
HTTPリクエスト (GET)
HTTPレスポンス
すべてのWebアクセスは基本的に
上記の1回のやり取りの繰り返し
Javaネットワークプログラミング
Javaにおけるソケット
非常に簡単にネットワーク通信を実現
サーバ側
クライアント側
java.net.ServerSocket, java.net.Socket
ServerSocket ss = new ServerSocket(portNo);
ss.accept();
Socket sock = new Socket(addr, portNo);
ポート番号 ポート番号 IPアドレス/ホスト名 クライアントからの 接続要求の受付Socket クラス
双方向の信頼性あるストリームを実現
getInputStream, getOutputStream で
通信用の入出力ストリームを得ることが
可能
[演習1] ネットワークプログラム
講義ホームページからサンプルプログラムを
ダウンロードしましょう
–NetTest.java
–NetClient.java
NetTest,NetClient を別々のターミナルで
実行してみましょう
% java NetTest
(ターミナル1)
% java NetClient 127.0.0.1
(ターミナル2)
[演習1] 実行例
% java NetTest
Waiting for Connection! b001/127.0.0.1
Connect:/127.0.0.1:32959
From :/127.0.0.1:1024
% java NetClient 127.0.0.1
Connect:/127.0.0.1:1024
From :/127.0.0.1:32959
Hello!
<ターミナル1>
<ターミナル2>
簡単なサーバサンプル
import java.net.*; import java.io.*; public class NetTest {static public void main(String args[]){ try{
ServerSocket ss = new ServerSocket(1024);
System.out.println( "Waiting for Connection!" + InetAddress.getLocalHost() );
Socket sock = ss.accept();
System.out.println( "Connect:" + sock.getInetAddress()+ ":" + sock.getPort()+ "¥nFrom :" + sock.getLocalAddress()
+ ":" + sock.getLocalPort());
PrintStream ps = new PrintStream( sock.getOutputStream(), true );
ps.println( "Hello!" ); sock.close(); } catch(Exception e){ e.printStackTrace(); } } } /* NetTest.java */ 1024番ポートを使用する サーバソケットを作成 クライアントからの 接続要求の受付 ソケットにバイトを出力するストリームを作成。 (必要に応じて、PrintStream を自動的に フラッシュする)
サンプルサーバへのアクセス
同じ計算機から
telnet 127.0.0.1 1024
異なる計算機から
サーバのIPアドレスを画面から読む
そのアドレスへ
telnet ip-address 1024
で接続可能
telnet コマンド "Hello!"+改行サンプルサーバの動作の様子
ServerSocket ss = new ServerSocket(1024); サーバ ソケット ss 1024番 1024番 "Hello!"+改行 クライアントからの 接続を受付 ss.accept() XXX番 sock.getLocalPort() sock.getPort() 127.0.0.1 XX.XX.XX.XX sock.getLocalAddress() sock.getInetAddress() ストリーム ps ソケット sock 自動フラッシュ
簡単なクライアントサンプル
import java.net.*; import java.io.*; public class NetClient {static public void main(String args[]){ try{
Socket sock = new Socket(args[0],1024);
System.out.println( "Connect:" + sock.getInetAddress()+ ":" + sock.getPort()+ "¥nFrom :" + sock.getLocalAddress()+ ":" + sock.getLocalPort()); InputStream is = sock.getInputStream(); int i; while( ( i = is.read()) != -1 ) { System.out.print( (char)i ); } sock.close(); } catch(Exception e) { e.printStackTrace(); } } } /* NetClient.java */ 接続先のIPアドレス/ホスト名を args[0]、接 続先のポート番号を 1024 とする ソケットを作成 ソケットからバイトを読み込む ストリームを作成 ストリームの終わりに達して読み込むデー タがなくなるまで入力ストリームからバイト データを読み込んで標準出力
サンプルクライアントから
サンプルサーバへのアクセス
サーバ側のIPアドレスを調査
(同じ計算機の場合は 127.0.0.1 でOK)
127.0.0.1 はローカルアドレス
% java NetClient [ip-address]
接続後、すぐに終了
Server 側
import java.net.*; import java.io.*; public class NetTest {
static public void main(String args[]){ try{
ServerSocket ss = new ServerSocket(1024); Socket sock = ss.accept();
BufferedReader br = new BufferedReader(new InputStreamReader(sock.getInputStream()));
BufferedReader mr = new BufferedReader(new InputStreamReader(System.in)); PrintStream ps = new PrintStream(sock.getOutputStream(),true);
String s; ps.println("Hello!"); // 最初に1行書く while(!(s =br.readLine()).equals("bye")){ // ソケットから読み込んでから System.out.println("you> "+s); System.out.print("me > "); s = mr.readLine(); // 自分のを書き出す ps.println(s); } sock.close(); }catch(Exception e){}
Client 側
import java.net.*; import java.io.*; public class NetClient {static public void main(String args[]){ try{
Socket sock = new Socket(args[0],1024); BufferedReader br = new BufferedReader(new
InputStreamReader(sock.getInputStream()));
BufferedReader mr = new BufferedReader(new InputStreamReader(System.in)); PrintStream ps = new PrintStream(sock.getOutputStream(),true);
String s; while(!(s =br.readLine()).equals("bye")){ // ソケットから読み込んでから System.out.println("you> "+s); System.out.print("me > "); s = mr.readLine(); // 自分のを書き出す ps.println(s); } sock.close(); }catch(Exception e){}
Javaネットワークプログラミング
簡単なChatを作成しよう
– NetTest , NetClient を改造
– ポイント: 互いに書き込む順を
間違えないこと
IPアドレスの確認
コマンドプロンプト(cmd)から
ipconfig
と実行すると
inet addr: 172.16.6. xxx
となるはず。これがIPアドレス
ChatFrame を実行してみよう!
プログラムを書く/読む
書く場合
– 基本的な筋道をよく考えること
– Chat の場合は、送信/受信の段取り
読む場合
– プログラムの機能全体の概要を理解
– コードを見ながら、機能の分割を行う
– 各部分の役割を理解
Threadを使ったChat
Thread を使うと、
– 受信専用のThread
– 送信専用のThread
2つのことが同時に行える
サーバ、クライアントを同じクラスで実現
– main メソッド中で判断
– Runnable インタフェースを実装
[演習2] ちょっと高度なチャット
(Thread利用)
講義ホームページからサンプルプログラムを
ダウンロードしましょう
–Chat.java (ターミナル版)
–ChatFrame.java (フレーム版)
実行してみよう
2つのターミナルを起動し、それぞれで
% java Chat
を実行すれば、2つのターミナル間で
chat ができます
最初のChatの実行で表示されるIPアドレスに対し
% java Chat 192.168.x.x
を実行すれば、別の端末ともチャットできます
Chat クラス(1)
import java.net.*; import java.io.*;
public class Chat implements Runnable {
static Socket sock = null; // shared variable using static static public void main(String args[]){
try{
if(args.length == 0){ // no argument try{
ServerSocket ss = new ServerSocket(1024); System.out.println("Waiting for Connection!"
+InetAddress.getLocalHost()); sock = ss.accept();
}catch(IOException e2){} // another server is running? }
if(sock == null){// not server
String dest = "127.0.0.1";// default for local connection if(args.length > 0) dest = args[0];
sock = new Socket(dest,1024); }
new Chat();
}catch(Exception e){} // ignore error (Not recommendable) }
Chat クラス(1)
import java.net.*; import java.io.*;
public class Chat implements Runnable {
static Socket sock = null; // shared variable using static static public void main(String args[]){
try{
if(args.length == 0){ // no argument try{
ServerSocket ss = new ServerSocket(1024); System.out.println("Waiting for Connection!"
+InetAddress.getLocalHost()); sock = ss.accept();
}catch(IOException e2){} // another server is running? }
if(sock == null){// not server
String dest = "127.0.0.1";// default for local connection if(args.length > 0) dest = args[0];
sock = new Socket(dest,1024); }
new Chat();
}catch(Exception e){} // ignore error (Not recommendable) }
引数が無いときは、
サーバとして動かす
すでにサーバがあると、例外が発生する
まだソケットがないなら、クライアント動作
引数が無くても、ローカルに接続
チャットオブジェクト作成
Chat クラス(2)
public Chat(){ System.out.println("Connect you:" +sock.getInetAddress()+":"+sock.getPort() +"¥n me :" +sock.getLocalAddress()+":"+sock.getLocalPort()); new Thread(this).start();// listen threadsender(); // send thread }
public void run(){ // socket listner thread try{
BufferedReader br = new BufferedReader( new InputStreamReader(sock.getInputStream())); String s;
while((s = br.readLine()) != null) System.out.println(s); System.exit(0); // when socket closed .. finish! }catch(Exception e){} }
受信は別スレッドで動作させる
ソケットからの1行読み込み
受信用スレッド
この1行だけで受信ループ
Chat クラス(3)
public void sender(){ // socket sender thread try{
BufferedReader br = new BufferedReader( new InputStreamReader(System.in));
PrintStream ps = new PrintStream(sock.getOutputStream()); String s=""; while(!s.equals("bye")){ s = br.readLine(); ps.println("you> "+s); } sock.close(); }catch(Exception e){} } }
public void sender(){ // socket sender thread try{
BufferedReader br = new BufferedReader( new InputStreamReader(System.in));
PrintStream ps = new PrintStream(sock.getOutputStream()); String s=""; while(!s.equals("bye")){ s = br.readLine(); ps.println("you> "+s); } sock.close(); }catch(Exception e){} }