2014年4月6日日曜日

javaでsocketを使ってバイナリデータ送受信メモ

javaでソケットを使って、例えばint+doubleの12byteデータを複数回送受信するようなことをしてみた。これができれば、片側javaでもう片方がjava以外の場合に、任意のプロトコルデータみたいなものを決めて通信できるはず。java同士ならクラスを作ってObjectOutputStream/ObjectIutputStream使えば済むと思う。 ここでは、ByteBufferに詰め込んで送受信する方法で試したが、もっといい方法があるのかはあんまり調べてない。

サーバ側

この例ではserverSocket.accept()で待ち受け開始、クライアント着信後に12byte分読み込める状態になったらbyte[]に読み込み。 その後、ByteBufferにwrap()して、getInt(),getDouble()で各データを取り出す。一応エンディアンはbigendianにしておいた。サーバではデータを受信したら表示するだけ。

追記) doubleやfloatなどの浮動小数点型を送信する場合にはもう少し考慮が必要かも。
java同士なら問題ないけど、その他とつなぐときはIEEE754の表現に合わせるなど必要?
package test.socket;

import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;

public class server {
    private static int port = 11111;
    private static int datasize = (Integer.SIZE + Double.SIZE) / 8;

    public static void main(String[] args) throws IOException,
            InterruptedException {

        ServerSocket serverSocket = null;
        InputStream in = null;

        try {
            serverSocket = new ServerSocket(port);
            Socket socket = serverSocket.accept();
            System.out.println("connected");
            in = socket.getInputStream();
            while (!socket.isClosed()) {
                int size = in.available();
                if (size >= datasize) {
                    byte[] data = new byte[datasize];
                    in.read(data, 0, datasize);
                    ByteBuffer buf = ByteBuffer.wrap(data);
                    buf.order(ByteOrder.BIG_ENDIAN);
                    System.out.println(buf.getInt(0) + ": "
                            + buf.getDouble(Integer.SIZE / 8));
                }
                Thread.sleep(100);
            }
        } finally {
            if (in != null)
                in.close();
            if (serverSocket != null)
                serverSocket.close();
        }
    }
}

クライアント側

new Socket(hostName, port)でソケット作成。 その後、ByteBuffer.allocate(datasize)で12byteのデータ格納エリアを作り、intとdoubleの値を入れてwrite()する。これを100回繰り返し。

package test.socket;

import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.ByteBuffer;

public class client {
    private static String hostname = "localhost";
    private static int port = 11111;
    private static int datasize = (Integer.SIZE + Double.SIZE)/8;

    public static void main(String[] args) throws IOException,
            InterruptedException {

        OutputStream out = null;
        try {
            out = (new Socket(hostname, port)).getOutputStream();

            for (int i = 0; i < 100; i++) {
                ByteBuffer buf = ByteBuffer.allocate(datasize);
                buf.putInt(i).putDouble(Math.random());
                out.write(buf.array());
                Thread.sleep(100);
            }
        } finally {
            if (out != null)
                out.close();
        }
    }
}



結果
connected
0: 0.4699143388898742
1: 0.2983774724033843
2: 0.12623749040407317
3: 0.19952009860520947
4: 0.10241603823568246
5: 0.6230472332876812
    :

0 件のコメント:

コメントを投稿