手记

java16 Unix Domain socket他来了

Unix Domain socket

A UNIX socket is an inter-process communication mechanism that allows bidirectional data exchange between processes running on the same machine.

他在socket的框架上发展出一种IPC(inter-process communication)机制。对于本地的进程间通信,Unix Domain socket 比TCP / IP环回连接更安全,更有效。

Unix Domain socket的场景

本机进程通信一直是一个大的需求。例如交互式的命令里,只是想获取一些数据,很多时候没必要开启额外的端口。开启端口就会有开多少的问题,机器上的随机端口很可能占用了你设置的值。进程启动先查哪些端口有没有被占用,查完之后再命令行等形式启动起来。最后client还得记住对应的端口。jdk本身实现命令的时候就没有这么麻烦,例如jstack等,用的都是 Domain socket。他们约定了一个固定的文件位置 /tmp/.java_pid${ns_pid}。java在jdk16之前没有Unix Domain socket,如果想用的话,得自己写jni。

目前这个功能已经完成,支持的平台如下。

Unix-domain sockets have long been a feature of most Unix platforms, and are now supported in Windows 10 and Windows Server 2019.

我们的理解就是对windows有一定的要求。

code

我们编写代码和以前区别不大。主要是围绕SocketChannel 和 ServerSocketChannel。在原来绑定ip和地址的地方换成UnixDomainSocketAddress。Channel open的时候选择好域,这个域还是枚举,StandardProtocolFamily。
我们看看ServerSocketChannel的code

        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(StandardProtocolFamily.UNIX);
        UnixDomainSocketAddress of = UnixDomainSocketAddress.of("./test.sock");
        serverSocketChannel.bind(of);
        while (true) {
            SocketChannel socketChannel = serverSocketChannel.accept();
            ByteBuffer buf = ByteBuffer.allocate(48);
            int bytesRead = socketChannel.read(buf);
            while (bytesRead > 0) {
                buf.flip();
                while (buf.hasRemaining()) {
                    System.out.print((char) buf.get());
                }
                System.out.println();
                buf.clear();
                bytesRead = socketChannel.read(buf);
            }
        }

读取的代码和以前是一样的。SocketChannel的部分也一样。

        SocketChannel socketChannel = SocketChannel.open(StandardProtocolFamily.UNIX);
        UnixDomainSocketAddress of = UnixDomainSocketAddress.of("./test.sock");
        boolean connect = socketChannel.connect(of);
        String newData = "this is domain socket..." + System.currentTimeMillis();
        ByteBuffer buf = ByteBuffer.allocate(48);
        buf.clear();
        buf.put(newData.getBytes());

        buf.flip();

        while (buf.hasRemaining()) {
            socketChannel.write(buf);
        }
        socketChannel.close();

jdk选择jdk16,否则编译不过去。下载地址[jdk16 ea]jdk.java.net/16/
我选择绑定文件为当前目录下的test.sock。为什么会绑定文件,可以了解一下socket的发展。

srwxr-xr-x  1 xie  staff     0B 12 27 12:19 test.sock

我们可以看到运行完程序之后产生了一个test.sock,他是s开头的表示他是一个socket文件。建议这个目录写到/tmp下去,后面可以依靠系统清理,否则就要自己去清理这个文件了。

demo代码的位置[domain socket demo]github.com/xpbob/java/tree/main/domainsocket

总结

Unix Domain socket给java同机进程通信带来了很大的方便。例如开发一些特殊的功能,完全可以做成本机通信,需要有权限的人员ssh到具体机器操作。开发起来也很方便,只不过socket文件需要自己去做管理。

0人推荐
随时随地看视频
慕课网APP