RxJava:将一个流(Observable)作为另一个流

时间:2015-10-24 17:38:19

标签: reactive-programming rx-java

我还在学习RxJava。在另一个流中使用流的最佳方法是什么?还是反对反应式编程的原则?

我尝试编写的玩具示例包括TCP客户端和发送回大写输入的服务器。我想从标准输入中获取输入,将其发送到服务器并打印出客户端和服务器接收到的所有内容。

以下是该计划的预期输出:

(User input) apple
Server received: apple
Client received: APPLE
(User input) peach
Server received: peach
Client received: PEACH

我能够使用三个可观察量来实现这一点:

  • stdinStream从标准输入中发出字符串
  • serverStream发出服务器接收的字符串
  • clientStream发出客户端收到的字符串。

然后在inputStream的创建中订阅clientStream,如下所示:

    private Observable<String> createClientStream(String host, int port, Observable<String> inputStream) {
    return Observable.create(sub -> {
        try (Socket socket = new Socket(host, port);
             BufferedReader inFromServer = new BufferedReader(new InputStreamReader(socket.getInputStream()));
             DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream());
             PrintWriter outWriter = new PrintWriter(outputStream, true);
        ) {
            inputStream.subscribe(line -> {
                outWriter.println(line);
                try {
                    sub.onNext(inFromServer.readLine());
                } catch (IOException e) {
                    sub.onError(e);
                }
            });
        } catch (UnknownHostException e) {
            sub.onError(e);
        } catch (IOException e) {
            sub.onError(e);
        }
    });
}

注意:我不想创建多个客户端,而是希望保持单个客户端运行,并指示它根据输入向服务器发送不同的值。因此,不希望将输入映射到新clientStream的方法:

stdinStream.map(line -> createClientStream(line))

所以我的问题是:

  1. 这是一种使用RxJava的理智方式吗?还有更好的选择吗?
  2. 我创建了客户端套接字,作为clientStream创建的一部分。我这样做是为了让我可以使用调度程序clientStream.scheduleOn(Schedulers.newThread)轻松地异步运行它。也许我应该根据我的单客户要求做不同的事情?
  3. 以下是完整的代码:https://gist.github.com/lintonye/25af58abdfcc688ad3c3

1 个答案:

答案 0 :(得分:2)

您需要的是using。将所有与套接字相关的对象放入Connection类并给定输入序列,将其映射到一对println / readLine,同时保持单个连接。这是gist for a runnable example

static class Connection {
    Socket socket;
    BufferedReader inFromServer;
    DataOutputStream outputStream;
    PrintWriter outWriter;

    public Connection(String host, int port) {
        try {
            socket = new Socket(host, port);
            inFromServer = new BufferedReader(
                new InputStreamReader(socket.getInputStream()));
            outputStream = new DataOutputStream(socket.getOutputStream());
            outWriter = new PrintWriter(outputStream, true);
        } catch (IOException ex) {
            Exceptions.propagate(ex);
        }
    }

    public void close() {
        try {
            outWriter.close();
            outputStream.close();
            inFromServer.close();
            socket.close();
        } catch (IOException ex) {
            Exceptions.propagate(ex);
        }
    }
}

public static void main(String[] args) {
    runServer();

    Observable<String> source = Observable.just("a", "b", "c");

    String host = "localhost";
    int port = 8080;

    Observable.<String, Connection>using(() -> new Connection(host, port), 
    conn -> 
        source
        .map(v -> {
            conn.outWriter.println(v);
            try {
                return conn.inFromServer.readLine();
            } catch (IOException ex) {
                throw Exceptions.propagate(ex);
            }
        })
    , Connection::close)
    .subscribe(System.out::println);
}