トランスポート層(レイヤー4)の役割は、ポート番号を使ってプロセスとプロセス(⇒実行中のプログラム)間の通信を可能にすることです。
プロセスとプロセスを繋ぐことからエンドツーエンド(End To End)と呼ばれます。
このプロセスを特定する時、通信先のプログラムが利用するポート番号で通信します。
トランスポート層で使われるプロトコルには、TCPとUDP(User Datagram Protocol)がありますが、ここでは簡単なUDPの送信実験を行います。
javaでUDPを使う場合は、java.net.DatagramSocketと
java.net.DatagramPacketを使います。
DatagramPacketが、UDP用のデータを入れる入れ物のクラスで、
「データグラムパケット」とよばれます。
対して、DatagramSocketはデータグラムパケットを送受信するためのソケットです。
ソケットとは、Unixでプロセス間の通信を行う
API(Application Program Interface)群の総称です。
(『電球や電源プラグを取り付けるための差込口』をソケットと呼びますが、
その接続が通信相手に接続するイメージに似ていることが由来になっています。)
つまり、DatagramSocketで通信の出入り口を管理し、
DatagramPacketと言う入れ物に、データを入れて運ぶようにプログラミングします。
まず、キー入力した文字列を、指定のIPアドレスの指定のポートへ、送信するプログラム
を示します。
01
02
03
04
05
06
07
08
09
10 11
12
13
14
15
16
17
18
19
20 21
import java.io.*;//BufferedReadered用 import java.net.*;//DatagramSocket、InetAddress用 public class UDPSndTest { public static void main(String[] args) throws Exception { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); InetAddress inet = InetAddress.getByName("192.168.0.33");//送信先(変更ください) int portNumber = 49152;//ポート番号 DatagramSocket sendSocket = new DatagramSocket();//UDP送信用ソケット System.out.print("送信文字列>"); String msg = br.readLine();//送信メッセージキー入力 msg = "ここはsから始まる学籍番号に変更" + msg; byte[] buf = msg.getBytes("MS932");//バイト列に変換 DatagramPacket packet; packet = new DatagramPacket(buf, buf.length, inet, portNumber); //IPアドレス、ポート番号も指定 sendSocket.send(packet);//送信 sendSocket.close();//ソケットを閉じる } }
06行目で、inetの変数へ、
送信先のIPアドレス指定用インスタンスを生成しています
(15行目のデータグラム生成で使っています)。
このIPアドレスが送信先です。
08行目で、送信に使うソケットを生成しています。
17行目で、データグラムパケット送信するのですが、そこで使うソケットの生成です。
11行目でキー入力した文字列の先頭に、学籍番号の文字列を先頭へ連結し、13行目でバイト列へ変換しています。
このバイト列を送信用データとしたデータグラムパケットを15行で生成しています。
この時、そのバイト列で、何バイトまで送るかというサイズ、そして送信先IPアドレス、ポート番号を指定して生成していることに着目ください。
こうして出来上がったデータグラムパケットを、17行目でsendメソッドにより送信しています。
01
02
03
04
05
06
07
08
09
10 11
12
13
14
15
16
17
18
19
20
import java.io.*;//BufferedReadered用 import java.net.*;//DatagramSocket用 public class UDPRecTest { public static void main(String[] args) throws Exception { byte[] buf = new byte[256]; int portNumber = 49152;//ポート番号 DatagramPacket packet = new DatagramPacket(buf, buf.length); DatagramSocket recSocket = new DatagramSocket(portNumber);//UDP受信用ソケット System.out.println("受信待機状態"); recSocket.receive(packet);//受信& wait int len = packet.getLength();//受信バイト数取得 String msg = new String(buf, 0, len, "MS932"); System.out.println(msg + ":以上" + len + "byte を受信しました。"); recSocket.close(); } }
送信と違って、受信のデータグラムパケットは、
IPアドレスとポート番号を指定せずに生成します(08行)。
つまり、受信データを入れるバイト配列と、サイズだけを指定します。
そして、ソケット生成ではポート番号を指定して生成します(09行)。
送信用では指定しませんでした。
実際に受信命令を実行しているのは、12行のreceiveメソッドで、
引数で指定したパケットに受信しています。
この実行は受信するまで次へ進みません(待機状態になります)。
receiveメソッドで受信データは、
パケットで管理されるbuf配列に格納される仕組みになっています。
なお、必ずしも最初に作ったパケットサイズのデータを受信できるとは限りません。
実際に受信できたバイト数は、13行目で行っているように、
データグラムのインスタンスより、getLengthメソッドで取得します。