将nio套接字替换为exec用于二进制协议的软件

时间:2014-01-23 18:11:53

标签: java sockets exec

我必须在我的软件中进行抽象 - 将直接不可阻塞的NIO套接字(客户端/服务器)替换为软件抽象。

例如,不是通过tcp客户端连接,而是exec openssl s_client -connect xxx.xxx.xxx.xxx。我写了一个小演示,它甚至可以工作。有时:(

第一个问题是Process的流不能与Selector一起使用,所以我不能用任何其他类型的通道替换socketchannel,所以我必须读/写没有任何机会避免阻塞。 第二个是协议是双工二进制文件传输协议(binkp),因此进程的缓冲流是不可用的。我试图避免将输入/输出数据转换为base64并且它有效,但有时也可以。

我无法理解为什么它有效或无效。我在下面放了一段测试代码。第一个字是帧的长度,但第一个位被忽略。请告诉我你的猜测。感谢。

public class BufferedSocketBase64 {
    static class InToOut implements Runnable {
        InputStream is;
        OutputStream os;
        boolean direction; //

        public InToOut(InputStream is, OutputStream os, boolean direction) {
            super();
            this.is = is;
            this.os = os;
            this.direction = direction;
        }

        @Override
        public void run() {
            System.out.println(Thread.currentThread().getId() + " start "
                    + ((direction) ? "encode from to" : "decode from to"));
            boolean eof = false;
            while (true) {
                if (direction) {
                    // encode to base64 data

                    try {
                        int[] head = new int[2];
                        for (int i = 0; i < 2; i++) {
                            head[i] = is.read();
                        }
                        int len = (head[0] & 0xff << 8 | head[1] & 0xff) & 0x7FFF;
                        byte[] buf = new byte[len + 2];
                        buf[0] = (byte) (head[0] & 0xff);
                        buf[1] = (byte) (head[1] & 0xff);
                        for (int i = 2; i < len; i++) {
                            buf[i] = (byte) (is.read() & 0xff);
                        }
                        System.out.println(Thread.currentThread()
                                .getId() + " << " + new String(buf));
                        if (len > 0) {
                            String send = Base64Util.encode(buf, len);
                            send += "\n";
                            os.write(send.getBytes());
                            os.flush();
                        }
                    } catch (IOException e) {
                        eof = true;
                    }
                } else { // decode from base64
                    try {
                        StringBuilder sb = new StringBuilder(1024);
                        byte c = 0x0a;
                        do {
                            c = (byte) is.read();
                            if (c >= 0 && c != 0x0a) {
                                sb.append(new String(new byte[] { c }));
                            }
                        } while (c != 0x0a && c >= 0);
                        if (sb.length() != 0) {
                            try {
                                byte[] buf = Base64Util.decode(sb.toString());
                                System.out.println(Thread.currentThread()
                                        .getId() + " >> " + buf.length);
                                os.write(buf);
                                os.flush();
                            } catch (StringIndexOutOfBoundsException e) {
                                System.out
                                        .println(Thread.currentThread().getId()
                                                + " error on " + sb.toString());
                            }
                        }
                    } catch (IOException e) {
                        eof = true;
                    }
                }
                if (eof) {
                    System.out.println(Thread.currentThread().getId() + " EOF");
                    break;
                }
            }
            try {
                is.close();
                os.close();
            } catch (IOException e) {

            }
        }
    }

    public static void main(String[] args) throws Exception {
        Process proc2 = Runtime.getRuntime().exec("nc -l -p 2020");
        Process proc1 = Runtime.getRuntime().exec("nc 127.0.0.1 2020");

        Socket sock1 = new Socket();
        sock1.connect(new InetSocketAddress("127.0.0.1", 24554), 30);
        Socket sock2 = new Socket();
        sock2.connect(new InetSocketAddress("127.0.0.1", 24557), 30);

        new Thread(new InToOut(sock1.getInputStream(), proc1.getOutputStream(),
                true)).start();
        new Thread(new InToOut(proc1.getInputStream(), sock1.getOutputStream(),
                false)).start();

        new Thread(new InToOut(sock2.getInputStream(), proc2.getOutputStream(),
                true)).start();
        new Thread(new InToOut(proc2.getInputStream(), sock2.getOutputStream(),
                false)).start();

    }

更新:

我找到了正确的方法。我对每个流和同步线程使用同步查询来填充或擦除查询。所有线程相互阻塞自己。它的工作原理! :) 抱歉打扰。

1 个答案:

答案 0 :(得分:0)

我找到了正确的方法。我对每个流和同步线程使用同步查询来填充或擦除查询。所有线程相互阻塞自己。它的工作原理! :)抱歉打扰了。