名称解释
– POSIX 便携式操作系统接口( POSIX ) 是IEEE 计算机协会指定的一系列标准,用于维护操作系统之间的兼容性
– IPC Inter-Process Communication,进程间通信
– UDS unix domain socket 是在socket架构上发展起来的用于同一台主机的进程间通讯
在众多IPC通信方式中,有一个基于domain socket方式实现跨进程通信,他的优势主要有:
- 类似tcp、udp协议可以做到双工通讯
- 相对于网络通讯,性能高、稳定性强
- 兼容性高、Linux、MAC和Window 10都支持
Java语言有个类库可以实现udp通讯,例子如下:
1)引入依赖
<dependency>
<groupId>com.github.jnr</groupId>
<artifactId>jnr-unixsocket</artifactId>
<version>0.18</version>
</dependency>
2)服务端代码
public class UnixServer {
public static void main(String[] args) throws IOException {
// 声明udp的地址
java.io.File path = new java.io.File("/tmp/fubar.sock");
// 退出自动删除
path.deleteOnExit();
// 场景udp地址
UnixSocketAddress address = new UnixSocketAddress(path);
// 打开channel
UnixServerSocketChannel channel = UnixServerSocketChannel.open();
try {
Selector sel = NativeSelectorProvider.getInstance().openSelector();
channel.configureBlocking(false);
// channel绑定address
channel.socket().bind(address);
// 注册server处理action
channel.register(sel, SelectionKey.OP_ACCEPT, new ServerActor(channel, sel));
// 监听selector事件
while (sel.select() > 0) {
Set<SelectionKey> keys = sel.selectedKeys();
Iterator<SelectionKey> iterator = keys.iterator();
boolean running = false;
boolean cancelled = false;
while ( iterator.hasNext() ) {
SelectionKey k = iterator.next();
Actor a = (Actor) k.attachment();
// 触发行为
if (a.rxready()) {
running = true;
} else {
k.cancel();
cancelled = true;
}
iterator.remove();
}
if (!running && cancelled) {
System.out.println("No Actors Running any more");
break;
}
}
} catch (IOException ex) {
log.info("",ex);
}
System.out.println("UnixServer EXIT");
}
static interface Actor {
public boolean rxready();
}
// 服务端actor
static final class ServerActor implements Actor {
private final UnixServerSocketChannel channel;
private final Selector selector;
public ServerActor(UnixServerSocketChannel channel, Selector selector) {
this.channel = channel;
this.selector = selector;
}
public final boolean rxready() {
try {
UnixSocketChannel client = channel.accept();
client.configureBlocking(false);
client.register(selector, SelectionKey.OP_READ, new ClientActor(client));
return true;
} catch (IOException ex) {
return false;
}
}
}
// 声明客户端actor
static final class ClientActor implements Actor {
private final UnixSocketChannel channel;
public ClientActor(UnixSocketChannel channel) {
this.channel = channel;
}
public final boolean rxready() {
try {
ByteBuffer buf = ByteBuffer.allocate(1024);
int n;
while ((n = channel.read(buf)) > 0) {
UnixSocketAddress remote = channel.getRemoteSocketAddress();
System.out.printf("Read in %d bytes from %s%n", n, remote);
if (n > 0) {
buf.flip();
// 回写同样内容
channel.write(buf);
buf.clear();
} else if (n < 0) {
return false;
}
}
} catch (IOException ex) {
ex.printStackTrace();
return false;
}
return true;
}
}
}
3)客户端代码
public class UnixClient {
public static void main(String[] args) throws IOException, InterruptedException {
java.io.File path = new java.io.File("/tmp/fubar.sock");
int retries = 0;
while (!path.exists()) {
TimeUnit.MILLISECONDS.sleep(500L);
retries++;
if (retries > 10) {
throw new IOException(
String.format(
"File %s does not exist after retry",
path.getAbsolutePath()
)
);
}
}
String data = "blah blah";
// 声明连接地址
UnixSocketAddress address = new UnixSocketAddress(path);
// 打开通道channel
UnixSocketChannel channel = UnixSocketChannel.open(address);
System.out.println("connected to " + channel.getRemoteSocketAddress());
PrintWriter w = new PrintWriter(Channels.newOutputStream(channel));
// 写入数据
w.print(data);
w.flush();
// 接受服务的输入流
InputStreamReader r = new InputStreamReader(Channels.newInputStream(channel));
CharBuffer result = CharBuffer.allocate(1024);
// 按字符串读入
r.read(result);
result.flip();
// 打印服务端写入内容
System.out.println("read from server: " + result.toString());
final int status;
if (!result.toString().equals(data)) {
System.out.println("ERROR: data mismatch");
status = -1;
} else {
System.out.println("SUCCESS");
status = 0;
}
System.exit(status);
}
}
服务端输出:
Read in 9 bytes from [family=PF_UNIX path=]
客户端输出:
connected to [family=PF_UNIX path=/tmp/fubar.sock]
read from server: blah blah
SUCCESS
Docker中获取容器进程信息,也可以通过udp的方式获取,演示一下。
命令:
curl --unix-socket /var/run/docker.sock http:/v1.24/containers/json | python -mjson.tool
结果:
[
{
"Command": "/bin/sh -c /httpserver",
"Created": 1654430518,
"HostConfig": {
"NetworkMode": "default"
},
"Id": "44aa82e8db9c69d04a2841b9c94b42bc93dc4b8e75078a4b469012862647a832",
"Image": "zyhui98/httpserver:v1.0",
"ImageID": "sha256:983c6f2a191be73cfd0731323d916ca02be4a5a0b884a0235405d8f39ed407d2",
"Labels": {
"multi.label1": "value1",
"multi.label2": "value2",
"other": "value3"
},
"Mounts": [],
"Names": [
"/practical_cray"
],
"NetworkSettings": {
"Networks": {
"bridge": {
"Aliases": null,
"DriverOpts": null,
"EndpointID": "62e81af9d1384fce3f434ba77fc042ed2afed1739c4068bf30c7bf6f41694855",
"Gateway": "172.17.0.1",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"IPAMConfig": null,
"IPAddress": "172.17.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"Links": null,
"MacAddress": "02:42:ac:11:00:02",
"NetworkID": "ad6980092187767c42fd3963e158a3e3030467240e70c265747de49723c1fd8d"
}
}
},
"Ports": [
{
"PrivatePort": 80,
"Type": "tcp"
}
],
"State": "running",
"Status": "Up 36 minutes"
}
]
声明:文中观点不代表本站立场。本文传送门:https://eyangzhen.com/206877.html