Unix 域套接字demo

名称解释 

– 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 blahSUCCESS

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

(0)
联系我们
联系我们
分享本页
返回顶部