JAVAでTCP/IP+BIOについて実装してみた

この記事ではWIN10にインストールしたJava 10.0.1を使っています。

#はじめに
システム間の通信を行うには、TCPとUDPというOSIのレイヤ4（トランスポート）のプロトコルがよく使われます。
TCPとUDPのメリットは以下となります：
**TCP**
- 信頼性が高い
**UDP**
- スピードが早い
また、TCPとUDPはシステム間の通信をできますが、それ以外、通信するデータに対して何かI/O処理を行わないといけませんので、I/O処理の方式も必要です。ここはブロッキングと(BIO)かノンブロッキング(NIO)がよく使われいます。
今回はTCP/IP+BIOでシステム間の通信を実装してみます。

#実装#
TCP通信を行うには、**ソケット**というライブラリを利用します。
Java言語から**Socket**、**ServerSocket**を提供していので、今回はこれらを使ってTCP/IP+BIOを実装してみます。
(公式APIはここ：[Socket](https://docs.oracle.com/javase/jp/6/api/java/net/Socket.html)、[ServerSocket](https://docs.oracle.com/javase/jp/6/api/java/net/ServerSocket.html))
**サーバ側のファイル（実はローカル）**

***ソケットを生成し、クライアント側のアクセスを待ち受けます***
TcpServerファイル内容：

```java

import java.io.*;
import java.net.*;

public class TcpServer{
    public static void main (String[] argv) throws Exception{
        try (
            // 8001ポート番号を作成する
            ServerSocket server = new ServerSocket(8001);
            FileOutputStream fos = new FileOutputStream("server_recv.txt");
            FileInputStream fis = new FileInputStream("server_send.txt");
        ){
            System.out.println("wait access...");
            // クライアント側のアクセスを待つ
            Socket socket = server.accept();
            System.out.println("client access.");

            int ch;
            // クライアント側から渡されたストリームをserver_recv.txtに書く
            InputStream input = socket.getInputStream();
            while ((ch = input.read()) != 0) {
                fos.write(ch);
            }
            // server_send.txtに書いた内容ストリームでをクライアント側に渡す
            OutputStream output = socket.getOutputStream();
            while ((ch = fis.read()) != -1) {
                output.write(ch);
            }
            // アクセス終了
            socket.close();
            System.out.println("accsess closed.");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
```

server_send.txt ファイル内容：

```
server_send
```
server_recv.txtは空ファイル

**クライアント側のファイル**

***ソケットを生成し、指定されたサーバとポートをアクセスします***
TcpClientファイル内容：

```java

import java.io.*;
import java.net.*;

public class TcpClient{
    public static void main (String[] argv) throws Exception{
        try (
            // 8001ポート番号をアクセス
            Socket socket = new Socket("localhost", 8001);
            FileOutputStream fos = new FileOutputStream("client_recv.txt");
            FileInputStream fis = new FileInputStream("client_send.txt");
        ){

            int ch;
            // client_send.txtに書いた内容ストリームでをサーバ側に渡す
            OutputStream output = socket.getOutputStream();
            while ((ch = fis.read()) != -1) {
                output.write(ch);
            }
            // サーバ側に「転送終了！」旨を渡す
            output.write(0);
            // サーバ側から渡されたストリームをclient_recv.txtに書く
            InputStream input = socket.getInputStream();
            while ((ch = input.read()) != -1) {
                fos.write(ch);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
```

client_send.txt ファイル内容：

```
client_send
```
client_recv.txtは空ファイル

#実行#
TcpClient.javaとTcpServer.javaをそれぞれをjavacでコンパイルし、javaで実行します

- TcpServer.classを実行します

サーバを起動し、クライアント側の接続を待ち受け中：

```
PS C:\Users\ma\Documents\work\javaweb\1> java TcpServer
wait access...
```

- TcpClient.classを実行します

クライアントを起動し、サーバ側へアクセスします：

```
PS C:\Users\ma\Documents\work\javaweb\1> java TcpClient
```

サーバはクライアント側からの接続を処理したら終了します：

```
PS C:\Users\ma\Documents\work\javaweb\1> java TcpServer
wait access...
client access.
accsess closed.
PS C:\Users\ma\Documents\work\javaweb\1>
```

#結果検証#
server_recv.txt ファイル内容：

```
client_send
```
クライアント側から渡された内容(client_send.txt)を上書きすることを検証できました

client_recv.txtも同じくサーバ側から渡された内容(server_send.txt)を上書きされました：

```
server_send
```

#まとめ#
今回はJavaのSocket、ServerSocketライブラリを使ってTCP/IP+BIOの転送路を作りました。
サーバとクライアントの間に、データを双方向に送れることも検証しました。

#参考#
1.前橋和弥.2016.基礎からのWebアプリケーション開発入門.技術評論社.