Javaネットワークプログラミング

ネットワークプログラミングとは、ネットワークで接続された複数のデバイス(コンピュータ)上で動作するプログラムを作成することです。

java.netパッケージ内のJ2SEのAPIには、低レベルの通信の詳細を提供するクラスとインターフェースが含まれています。これらのクラスとインターフェースを直接使用することで、通信の詳細を気にせずに問題解決に集中できます。

java.netパッケージは、2つの一般的なネットワークプロトコルをサポートしています:

  • TCP:TCP(英語: Transmission Control Protocol、伝送制御プロトコル)は、コネクション指向で信頼性が高く、バイトストリームに基づくトランスポート層の通信プロトコルです。TCP層はIP層の上、アプリケーション層の下に位置する中間層です。TCPは2つのアプリケーション間の信頼性の高い通信を保証します。通常はインターネットプロトコルとして使用され、TCP/IPと呼ばれます。

  • UDP:UDP(英語: User Datagram Protocol、ユーザーデータグラムプロトコル)は、OSIモデルのトランスポート層に位置します。コネクションレス型のプロトコルです。アプリケーション間で送信するデータのデータグラムを提供します。UDPは信頼性に欠け、コネクションレス型プロトコルであるため、アプリケーションは通常、パケットの損失、エラー、重複をある程度許容する必要があります。

このチュートリアルでは、主に次の2つのトピックについて説明します。

  • Socketプログラミング:これは最も広く使用されているネットワーク概念であり、非常に詳細に説明されています。

  • URL処理:この部分は別の章で説明します。ここをクリックして、より詳しく学べます:Java言語でのURL処理。


Socketプログラミング

ソケットはTCPを使用して、2台のコンピュータ間の通信メカニズムを提供します。クライアントプログラムはソケットを作成し、サーバーのソケットへの接続を試みます。

接続が確立されると、サーバーはSocketオブジェクトを作成します。これでクライアントとサーバーはSocketオブジェクトへの書き込みと読み取りによって通信できます。

java.net.Socketクラスはソケットを表し、java.net.ServerSocketクラスはサーバープログラムにクライアントを監視し、クライアントとの接続を確立するメカニズムを提供します。

2台のコンピュータ間でソケットを使用してTCP接続を確立する際に、以下の手順が発生します:

  • サーバーはServerSocketオブジェクトをインスタンス化し、サーバー上のポートを介した通信を表します。

  • サーバーはServerSocketクラスのaccept()メソッドを呼び出します。このメソッドは、クライアントがサーバーの指定されたポートに接続するまで待機し続けます。

  • サーバーが待機している間に、クライアントはサーバー名とポート番号を指定してSocketオブジェクトをインスタンス化し、接続を要求します。

  • Socketクラスのコンストラクタは、クライアントを指定されたサーバーとポート番号に接続しようとします。通信が確立されると、クライアントにサーバーと通信できるSocketオブジェクトが作成されます。

  • サーバー側では、accept()メソッドがサーバー上の新しいソケット参照を返します。このソケットはクライアントのソケットに接続されます。

接続が確立された後、I/Oストリームを使用して通信します。各ソケットには出力ストリームと入力ストリームがあり、クライアントの出力ストリームはサーバーの入力ストリームに接続され、クライアントの入力ストリームはサーバーの出力ストリームに接続されます。

TCPは双方向の通信プロトコルであるため、2つのデータストリームを介して同時にデータを送信できます。以下に、ソケットを実装するための便利なメソッド一式を提供するクラスを示します。


ServerSocketクラスのメソッド

サーバーアプリケーションは、java.net.ServerSocketクラスを使用してポートを取得し、クライアントからのリクエストを監視します。

ServerSocketクラスには4つのコンストラクタがあります:

番号 メソッドの説明
1 public ServerSocket(int port) throws IOException
特定のポートにバインドされたサーバーソケットを作成します。
2 public ServerSocket(int port, int backlog) throws IOException
指定されたバックログを使用してサーバーソケットを作成し、指定されたローカルポート番号にバインドします。
3 public ServerSocket(int port, int backlog, InetAddress address) throws IOException
指定されたポート、リッスンバックログ、バインド先のローカルIPアドレスを使用してサーバーを作成します。
4 public ServerSocket() throws IOException
バインドされていないサーバーソケットを作成します。

バインドされていないサーバーソケットを作成します。ServerSocketコンストラクタが例外をスローしない場合、アプリケーションは指定されたポートへのバインドに成功し、クライアントからのリクエストを監視していることを意味します。

ここにServerSocketクラスの一般的なメソッドをいくつか示します:

番号 メソッドの説明
1 public int getLocalPort()
このソケットがリッスンしているポートを返します。
2 public Socket accept() throws IOException
このソケットへの接続をリッスンし、受け入れます。
3 public void setSoTimeout(int timeout)
タイムアウト値をミリ秒単位で指定して、SO_TIMEOUTを有効/無効にします。
4 public void bind(SocketAddress host, int backlog)
ServerSocketを特定のアドレス(IPアドレスとポート番号)にバインドします。

Socketクラスのメソッド

java.net.Socketクラスは、クライアントとサーバーの両方が相互に通信するために使用するソケットを表します。クライアントはインスタンス化によってSocketオブジェクトを取得し、サーバーはaccept()メソッドの戻り値によってSocketオブジェクトを取得します。

Socketクラスには5つのコンストラクタがあります。

番号 メソッドの説明
1 public Socket(String host, int port) throws UnknownHostException, IOException.
ストリームソケットを作成し、指定されたホストの指定されたポート番号に接続します。
2 public Socket(InetAddress host, int port) throws IOException
ストリームソケットを作成し、指定されたIPアドレスの指定されたポート番号に接続します。
3 public Socket(String host, int port, InetAddress localAddress, int localPort) throws IOException.
ソケットを作成し、指定されたリモートホストの指定されたリモートポートに接続します。
4 public Socket(InetAddress host, int port, InetAddress localAddress, int localPort) throws IOException.
ソケットを作成し、指定されたリモートアドレスの指定されたリモートポートに接続します。
5 public Socket()
システムのデフォルトタイプのSocketImplを使用して、未接続のソケットを作成します。

Socketコンストラクタが戻ったとき、単にSocketオブジェクトをインスタンス化したわけではなく、実際には指定されたサーバーとポートへの接続を試みます。

以下にいくつかの注目すべきメソッドを示します。クライアントとサーバーの両方がSocketオブジェクトを持っているため、クライアント側でもサーバー側でもこれらのメソッドを呼び出すことができます。

番号 メソッドの説明
1 public void connect(SocketAddress host, int timeout) throws IOException
このソケットをサーバーに接続し、タイムアウト値を指定します。
2 public InetAddress getInetAddress()
ソケットが接続されているアドレスを返します。
3 public int getPort()
このソケットが接続されているリモートポートを返します。
4 public int getLocalPort()
このソケットがバインドされているローカルポートを返します。
5 public SocketAddress getRemoteSocketAddress()
このソケットが接続されているエンドポイントのアドレスを返します。未接続の場合はnullを返します。
6 public InputStream getInputStream() throws IOException
このソケットの入力ストリームを返します。
7 public OutputStream getOutputStream() throws IOException
このソケットの出力ストリームを返します。
8 public void close() throws IOException
このソケットを閉じます。

InetAddressクラスのメソッド

このクラスはインターネットプロトコル(IP)アドレスを表します。以下に、Socketプログラミングで役立つメソッドを示します:

番号 メソッドの説明
1 static InetAddress getByAddress(byte[] addr)
指定された生のIPアドレスから、InetAddressオブジェクトを返します。
2 static InetAddress getByAddress(String host, byte[] addr)
提供されたホスト名とIPアドレスに基づいてInetAddressを作成します。
3 static InetAddress getByName(String host)
指定されたホスト名から、ホストのIPアドレスを決定します。
4 String getHostAddress() 
IPアドレス文字列(テキスト表現)を返します。
5 String getHostName() 
このIPアドレスのホスト名を取得します。
6 static InetAddress getLocalHost()
ローカルホストを返します。
7 String toString()
このIPアドレスをStringに変換します。

Socketクライアントの例

次のGreetingClientはクライアントプログラムです。このプログラムはソケットを介してサーバーに接続し、リクエストを送信して、応答を待ちます。

GreetingClient.java ファイルコード:

//ファイル名 GreetingClient.java import java.net.*; import java.io.*; public class GreetingClient { public static void main(String [] args) { String serverName = args[0]; int port = Integer.parseInt(args[1]); try { System.out.println("ホストに接続:" + serverName + "、ポート番号:" + port); Socket client = new Socket(serverName, port); System.out.println("リモートホストのアドレス:" + client.getRemoteSocketAddress()); OutputStream outToServer = client.getOutputStream(); DataOutputStream out = new DataOutputStream(outToServer); out.writeUTF("Hello from " + client.getLocalSocketAddress()); InputStream inFromServer = client.getInputStream(); DataInputStream in = new DataInputStream(inFromServer); System.out.println("サーバーの応答:" + in.readUTF()); client.close(); }catch(IOException e) { e.printStackTrace(); } } }

Socketサーバーの例

次のGreetingServerプログラムはサーバー側アプリケーションであり、Socketを使用して指定されたポートをリッスンします。

GreetingServer.java ファイルコード:

//ファイル名 GreetingServer.java import java.net.*; import java.io.*; public class GreetingServer extends Thread { private ServerSocket serverSocket; public GreetingServer(int port) throws IOException { serverSocket = new ServerSocket(port); serverSocket.setSoTimeout(10000); } public void run() { while(true) { try { System.out.println("リモート接続を待機中、ポート番号:" + serverSocket.getLocalPort() + "..."); Socket server = serverSocket.accept(); System.out.println("リモートホストのアドレス:" + server.getRemoteSocketAddress()); DataInputStream in = new DataInputStream(server.getInputStream()); System.out.println(in.readUTF()); DataOutputStream out = new DataOutputStream(server.getOutputStream()); out.writeUTF("接続してくれてありがとう:" + server.getLocalSocketAddress() + "\nGoodbye!"); server.close(); }catch(SocketTimeoutException s) { System.out.println("Socket timed out!"); break; }catch(IOException e) { e.printStackTrace(); break; } } } public static void main(String [] args) { int port = Integer.parseInt(args[0]); try { Thread t = new GreetingServer(port); t.run(); }catch(IOException e) { e.printStackTrace(); } } }

上記の2つのJavaファイルのコードをコンパイルし、次のコマンドを実行してサービスを起動します。ポート番号は6066を使用します:

$ javac GreetingServer.java 
$ java GreetingServer 6066
等待远程连接,端口号为:6066...

新しいコマンドウィンドウを開き、上記のコマンドを実行してクライアントを起動します:

$ javac GreetingClient.java 
$ java GreetingClient localhost 6066
连接到主机:localhost ,端口号:6066
远程主机地址:localhost/127.0.0.1:6066
服务器响应: 谢谢连接我:/127.0.0.1:6066
Goodbye!
その他の拡張