jjzjj

java - nio上下文中的请求-响应同步/匹配

coder 2024-03-14 原文

我有一个服务器客户端应用程序(Java EE 和 Android),通过 websockets 进行通信。通信正常,协议(protocol)本身也可以将对象作为 json 发送,这些对象将被正确包装、序列化、发送、反序列化、解包和重建。这两个应用程序都在使用另一个库项目,其中包含所有可能的请求和响应类。

现在解决我的问题: 图书馆还应该实现非阻塞通信策略,但透明的请求-响应实现。可能我不是第一个遇到这个问题的人,所以我认为那里可能有一些不错的实现:)。

我想要的:

// server should sleep 5000ms and then return 3*3
Future<Integer> f1 = server.put(
  new SleepAndReturnSquareRequest(5000, 3),
  new FutureCallback<Integer>{
    public void onSuccess(Integer square) {
      runOnUiThread(new Runnable{
        // Android Toast show square
      });
    }

    // impl onFailure
  }
);

Future<Date> f2 = server.put(
  new TimeRequest(),
  new FutureCallback<Date>{
    public void onSuccess(Date date) {
      // called before other onSuccess
    }

    // impl onFailure
  }
);

// e.g. when the activity in android changes I'll cancel all futures. That means no more callbacks and (later) if possible client sends cancellations to the server for long requests.

代码应该发送一个 SleepAndReturnRequest 然后一个 TimeRequest 当然是非阻塞的。第一个请求需要 5 秒,第二个请求几乎为零毫秒。我希望实现在收到响应后立即调用第二个回调,而在大约 5 秒后调用第一个回调。实现负责请求方的请求-响应匹配。

我的尝试和思考:

Google 的 guava listenable future 我认为对于“响应方”来说是一个很好的方法,因为它只是一个在任何线程上运行的任务,最后将结果发回。那应该更容易。

对于“请求方”,我需要一些实现,它向消息添加唯一标识符以便能够匹配响应。希望您能告诉我一些可以完成这项工作的软件包。

感谢您的帮助。

//编辑:

我认为我的问题被误解了或者不够精确。想想如何通过 websocket 实现 GET 或 POST。每个 GET/POST 请求都有一个响应,然后关闭连接。客户端连接到特定端口,服务器从线程池中获取线程,处理请求并响应。我认为请求与响应的匹配是在传输层 #4 中完成的。

因为我想使用 websockets,所以我必须在软件层 7 中实现匹配。

以下是我正在实现的一些步骤。 K是唯一键类型,V是消息内容的通用类型。这可能是一个字符串、字节流,等等。

public class Synchronizer<K, V> implements UniqueMessageListener<K, V> {

    private final ConcurrentMap<K, FutureCallback<V>> callbackMap = new ConcurrentHashMap<>();

    private final ListeningExecutorService executor;

    private final UniqueMessageFactory<K, V> factory;
    private final UniqueMessageSender<K, V> sender;
    private UniqueMessageReceiver<K, V> receiver = null;

    public Synchronizer(
            ListeningExecutorService executor,
            UniqueMessageFactory<K, V> factory,
            UniqueMessageSender<K, V> sender
    ) {
        this.executor = executor;
        this.factory = factory;
        this.sender = sender;
    }

    public void register(UniqueMessageReceiver<K, V> receiver) {

        unregister();

        this.receiver = receiver;
        receiver.addListener(this);
    }

    public void unregister() {
        if(receiver != null) {
            receiver.removeListener(this);
            receiver = null;
        }
    }

    public Future<V> put(Message<V> message, final FutureCallback<V> callback) {
        final UniqueMessage<K, V> uniqueMessage = factory.create(message);

        final Future<Boolean> sendFuture = sender.send(uniqueMessage);

        final ListenableFuture<Boolean> listenableSendFuture =
                JdkFutureAdapters.listenInPoolThread(sendFuture, executor);


        listenableSendFuture.addListener(
                new Runnable() {
                    @Override
                    public void run() {
                        try {
                            if(listenableSendFuture.get() == true) {
                                callbackMap.put(
                                        uniqueMessage.getId(),
                                        callback
                                );
                            } else {
                                // maybe try it later again?
                            }
                        } catch(Exception e) {
                            // ...
                        }
                    }
                },
                executor
        );

        // implement cancel
        return new SynchronizeFuture<>(
                listenableSendFuture,
                callback
        );
    }

    @Override
    public void onReceive(UniqueMessage<K, V> message) {
        K id = message.getId();
        FutureCallback<V> callback;

        callback = callbackMap.remove(id);

        if(callback != null) {
            callback.onSuccess(message.getContent());
        }
    }
}

对我来说有很多要测试的,但我认为它会起作用。

最佳答案

你可以试试 ProtoBuf-RPC-Pro - 但它不适用于 WebSockets,尽管我认为 GitHub 上有一个项目支持它 :)

关于java - nio上下文中的请求-响应同步/匹配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30014477/

有关java - nio上下文中的请求-响应同步/匹配的更多相关文章

  1. ruby 正则表达式 - 如何替换字符串中匹配项的第 n 个实例 - 2

    在我的应用程序中,我需要能够找到所有数字子字符串,然后扫描每个子字符串,找到第一个匹配范围(例如5到15之间)的子字符串,并将该实例替换为另一个字符串“X”。我的测试字符串s="1foo100bar10gee1"我的初始模式是1个或多个数字的任何字符串,例如,re=Regexp.new(/\d+/)matches=s.scan(re)给出["1","100","10","1"]如果我想用“X”替换第N个匹配项,并且只替换第N个匹配项,我该怎么做?例如,如果我想替换第三个匹配项“10”(匹配项[2]),我不能只说s[matches[2]]="X"因为它做了两次替换“1fooX0barXg

  2. ruby - 匹配未转义的平衡定界符对 - 2

    如何匹配未被反斜杠转义的平衡定界符对(其本身未被反斜杠转义)(无需考虑嵌套)?例如对于反引号,我试过了,但是转义的反引号没有像转义那样工作。regex=/(?!$1:"how\\"#expected"how\\`are"上面的正则表达式不考虑由反斜杠转义并位于反引号前面的反斜杠,但我愿意考虑。StackOverflow如何做到这一点?这样做的目的并不复杂。我有文档文本,其中包括内联代码的反引号,就像StackOverflow一样,我想在HTML文件中显示它,内联代码用一些spanMaterial装饰。不会有嵌套,但转义反引号或转义反斜杠可能出现在任何地方。

  3. ruby-on-rails - Rails HTML 请求渲染 JSON - 2

    在我的Controller中,我通过以下方式在我的index方法中支持HTML和JSON:respond_todo|format|format.htmlformat.json{renderjson:@user}end在浏览器中拉起它时,它会自然地以HTML呈现。但是,当我对/user资源进行内容类型为application/json的curl调用时(因为它是索引方法),我仍然将HTML作为响应。如何获取JSON作为响应?我还需要说明什么? 最佳答案 您应该将.json附加到请求的url,提供的格式在routes.rb的路径中定义。这

  4. java - 等价于 Java 中的 Ruby Hash - 2

    我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/

  5. ruby-on-rails - 每次我尝试部署时,我都会得到 - (gcloud.preview.app.deploy) 错误响应 : [4] DEADLINE_EXCEEDED - 2

    我是Google云的新手,我正在尝试对其进行首次部署。我的第一个部署是RubyonRails项目。我基本上是在关注thisguideinthegoogleclouddocumentation.唯一的区别是我使用的是我自己的项目,而不是他们提供的“helloworld”项目。这是我的app.yaml文件runtime:customvm:trueentrypoint:bundleexecrackup-p8080-Eproductionconfig.ruresources:cpu:0.5memory_gb:1.3disk_size_gb:10当我转到我的项目目录并运行gcloudprevie

  6. ruby - 匹配大写字母并用后续字母填充,直到一定的字符串长度 - 2

    我有一个驼峰式字符串,例如:JustAString。我想按照以下规则形成长度为4的字符串:抓取所有大写字母;如果超过4个大写字母,只保留前4个;如果少于4个大写字母,则将最后大写字母后的字母大写并添加字母,直到长度变为4。以下是可能发生的3种情况:ThisIsMyString将产生TIMS(大写字母);ThisIsOneVeryLongString将产生TIOV(前4个大写字母);MyString将生成MSTR(大写字母+tr大写)。我设法用这个片段解决了前两种情况:str.scan(/[A-Z]/).first(4).join但是,我不太确定如何最好地修改上面的代码片段以处理最后一种

  7. jquery - 我的 jquery AJAX POST 请求无需发送 Authenticity Token (Rails) - 2

    rails中是否有任何规定允许站点的所有AJAXPOST请求在没有authenticity_token的情况下通过?我有一个调用Controller方法的JqueryPOSTajax调用,但我没有在其中放置任何真实性代码,但调用成功。我的ApplicationController确实有'request_forgery_protection'并且我已经改变了config.action_controller.consider_all_requests_local在我的environments/development.rb中为false我还搜索了我的代码以确保我没有重载ajaxSend来发送

  8. java - 从 JRuby 调用 Java 类的问题 - 2

    我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www

  9. ruby-on-rails - Rails 3,嵌套资源,没有路由匹配 [PUT] - 2

    我真的为这个而疯狂。我一直在搜索答案并尝试我找到的所有内容,包括相关问题和stackoverflow上的答案,但仍然无法正常工作。我正在使用嵌套资源,但无法使表单正常工作。我总是遇到错误,例如没有路线匹配[PUT]"/galleries/1/photos"表格在这里:/galleries/1/photos/1/edit路线.rbresources:galleriesdoresources:photosendresources:galleriesresources:photos照片Controller.rbdefnew@gallery=Gallery.find(params[:galle

  10. java - 我的模型类或其他类中应该有逻辑吗 - 2

    我只想对我一直在思考的这个问题有其他意见,例如我有classuser_controller和classuserclassUserattr_accessor:name,:usernameendclassUserController//dosomethingaboutanythingaboutusersend问题是我的User类中是否应该有逻辑user=User.newuser.do_something(user1)oritshouldbeuser_controller=UserController.newuser_controller.do_something(user1,user2)我

随机推荐