最終更新日:180909 原本2018/05/06 

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言語からSocketServerSocketを提供していので、今回はこれらを使ってTCP/IP+BIOを実装してみます。
(公式APIはここ:SocketServerSocket)
サーバ側のファイル(実はローカル)

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

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ファイル内容:

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の転送路を作りました。
サーバとクライアントの間に、データを双方向に送れることも検証しました。