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文件需要自己去做管理。